Skip to content

Storage

S3-compatible buckets and objects with presigned URLs.

1. Overview

Base path: https://api.infrai.cc/v1/storage
Auth header: Authorization: Bearer $INFRAI_API_KEY
bash
# Call any /v1/storage capability over raw HTTP — no SDK to install.
# curl:
curl https://api.infrai.cc/v1/storage/... \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json"

2. Methods (22)

2.1storage.bucket.create

POST /v1/storage/bucket/create

Create an object-storage bucket. Bucket names must be 3-63 lowercase letters, digits, dots, or hyphens, start and end with a letter or digit, and use canonical region codes such as cn-beijing or ap-singapore.

Parameters

NameTypeRequiredDescription
namestring
Required
Bucket name. Length 3-63; lowercase letters, digits, dots, and hyphens only; must start and end with a letter or digit. Prefer name in new integrations; bucket is accepted as an alias.
bucketstringOptionalAlias for name. Prefer name in new integrations.
vendorstringOptionalPin a specific vendor instead of auto-routing.
region"us-east-1" | "us-west-2" | "eu-west-1" | "eu-central-1" | "ap-southeast-1" | "ap-northeast-1" | "cn-hangzhou" | "cn-beijing" | "auto" | "ap-singapore" | "ap-hongkong" | "ap-tokyo" | "ap-bangkok" | "na-siliconvalley" | nullOptionalStorage region code, for example cn-beijing for Beijing or ap-singapore for Singapore. Do not pass localized city names such as 北京; unsupported regions return INVALID_REGION.
acl"private" | "signed-only"OptionalBucket access control. Defaults to private; currently only private and signed-only are supported. public and public-read are not supported.
default: "private"

Returns

Bucket { bucket, vendor, region, created_at, acl? }
NameTypeDescription
bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
namestringHuman-readable name for this resource
vendor"r2" | "s3" | "oss" | "cos"Vendor that handled or will handle this request
regionstring | nullGeographic region where this resource is located or processed
acl"private" | "signed-only"Access control list for the bucket or object
created_atstringISO 8601 timestamp when this resource was created
format: date-time
cors_rulesobject[]CORS configuration rules for the bucket
lifecycle_rulesobject[]Lifecycle management rules for the bucket
lifecycle_rules[].prefixstringMatch objects whose key starts with this.
e.g. tmp/
lifecycle_rules[].expire_daysinteger | nullAuto-delete after N days.
≥ 1e.g. 1
lifecycle_rules[].transition_classstring | nullTransition to colder storage class (e.g. "glacier").

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/bucket/create \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "example"}'

2.2storage.bucket.list

GET /v1/storage/bucket/list

List your buckets.

Returns

{ items: Bucket[] }
NameTypeDescription
itemsobject[]Array of result items in this page
items[].bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
items[].namestringHuman-readable name for this resource
items[].vendor"r2" | "s3" | "oss" | "cos"Vendor that handled or will handle this request
items[].regionstring | nullGeographic region where this resource is located or processed
items[].acl"private" | "signed-only"Access control list for the bucket or object
items[].created_atstringISO 8601 timestamp when this resource was created
format: date-time
items[].cors_rulesobject[]CORS configuration rules for the bucket
items[].lifecycle_rulesobject[]Lifecycle management rules for the bucket
items[].lifecycle_rules[].prefixstringMatch objects whose key starts with this.
e.g. tmp/
items[].lifecycle_rules[].expire_daysinteger | nullAuto-delete after N days.
≥ 1e.g. 1
items[].lifecycle_rules[].transition_classstring | nullTransition to colder storage class (e.g. "glacier").
next_cursorstring | nullOpaque cursor to fetch the next page; null/absent if this is the last page

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/storage/bucket/list \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.3storage.object.presign

POST /v1/storage/object/presign/{bucket}/{key}

Create a presigned URL for uploading or downloading an object. For op=put, send the file binary bytes to the returned URL using the returned method.

Parameters

NameTypeRequiredDescription
bucketstring
Required
Bucket name.
keystring
Required
Object key (path) within the bucket.
op"get" | "put"
Required
Purpose of the presigned URL: get creates a download URL; put creates an upload URL. For op=put, send the file binary bytes to the returned url using the response method.
e.g. put
expires_secondsnumberOptionalPresigned URL lifetime in seconds.
≥ 1

Returns

PresignedUrl { url, method, expires_at, headers? }
NameTypeDescription
urlstringURL for this resource or endpoint
method"PUT" | "POST"Authentication method used (e.g. email_otp, oauth, password)
headersobject | nullCustom HTTP headers to include in requests or responses
fieldsobject | nullFor POST form uploads.
expires_atstringISO 8601 timestamp when this resource or token expires
format: date-time
max_bytesinteger | nullMaximum allowed file size in bytes
≥ 0

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op": "put"}'

2.4storage.object.delete

DELETE /v1/storage/object/delete/{bucket}/{key}

Delete a single object from a bucket. After deletion, head/get report the object as not found.

Parameters

NameTypeRequiredDescription
bucketstring
Required
Bucket name.
keystring
Required
Object key (path) within the bucket.

Returns

{ ok: boolean }
NameTypeDescription
bucketstringBucket the object was deleted from
keystringKey of the deleted object
deletedbooleanWhether the object existed and was deleted

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X DELETE https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.5storage.bucket.get

GET /v1/storage/bucket/get/{bucket}

获取存储桶元信息

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称

Returns

Bucket { bucket_id, name, vendor, region, acl, created_at, cors_rules, lifecycle_rules }
NameTypeDescription
bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
namestringHuman-readable name for this resource
vendor"r2" | "s3" | "oss" | "cos"Vendor that handled or will handle this request
regionstring | nullGeographic region where this resource is located or processed
acl"private" | "signed-only"Access control list for the bucket or object
created_atstringISO 8601 timestamp when this resource was created
format: date-time
cors_rulesobject[]CORS configuration rules for the bucket
lifecycle_rulesobject[]Lifecycle management rules for the bucket
lifecycle_rules[].prefixstringMatch objects whose key starts with this.
e.g. tmp/
lifecycle_rules[].expire_daysinteger | nullAuto-delete after N days.
≥ 1e.g. 1
lifecycle_rules[].transition_classstring | nullTransition to colder storage class (e.g. "glacier").

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/storage/bucket/get/BUCKET \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.6storage.bucket.delete

DELETE /v1/storage/bucket/delete/{bucket}

Delete a bucket. Empty buckets can be deleted directly; non-empty buckets require force=true, otherwise STORAGE_DELETE_NOT_FORCED is returned.

Parameters

NameTypeRequiredDescription
bucketstring
Required
Bucket name
forcebooleanOptionalWhether to force-delete a non-empty bucket. Defaults to false: if objects remain, the API returns STORAGE_DELETE_NOT_FORCED; true deletes the bucket and its objects.
idempotency_keystringOptionalIdempotency key; derived automatically when omitted.

Returns

BucketDeleteResult { deleted }
NameTypeDescription
deletedbooleanWhether the resource was successfully deleted

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X DELETE https://api.infrai.cc/v1/storage/bucket/delete/BUCKET \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.7storage.bucket.usage

GET /v1/storage/bucket/usage/{bucket}

查询存储桶用量

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称

Returns

BucketUsageResult { byte_count, object_count, as_of }
NameTypeDescription
byte_countintegerTotal bytes stored in the bucket
≥ 0
object_countintegerNumber of objects in the bucket
≥ 0
as_ofstringISO 8601 timestamp when the usage was measured
format: date-time

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/storage/bucket/usage/BUCKET \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.8storage.bucket.set_lifecycle

POST /v1/storage/bucket/set_lifecycle/{bucket}

Set bucket lifecycle rules.

Parameters

NameTypeRequiredDescription
bucketstring
Required
Bucket name.
rulesArray<{ prefix: string; expire_days?: number; transition_class?: string }>
Required
Lifecycle rule list. Each rule can include prefix, expire_days, and transition_class; expire_days is measured in days and must be at least 1. The submitted rules replace the current list.
e.g. [{"prefix":"tmp/","expire_days":1}]
idempotency_keystringOptionalIdempotency key; derived automatically when omitted.

Returns

Bucket { bucket_id, name, vendor, region, acl, created_at, cors_rules, lifecycle_rules }
NameTypeDescription
bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
namestringHuman-readable name for this resource
vendor"r2" | "s3" | "oss" | "cos"Vendor that handled or will handle this request
regionstring | nullGeographic region where this resource is located or processed
acl"private" | "signed-only"Access control list for the bucket or object
created_atstringISO 8601 timestamp when this resource was created
format: date-time
cors_rulesobject[]CORS configuration rules for the bucket
lifecycle_rulesobject[]Lifecycle management rules for the bucket
lifecycle_rules[].prefixstringMatch objects whose key starts with this.
e.g. tmp/
lifecycle_rules[].expire_daysinteger | nullAuto-delete after N days.
≥ 1e.g. 1
lifecycle_rules[].transition_classstring | nullTransition to colder storage class (e.g. "glacier").

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rules": [{"prefix": "tmp/", "expire_days": 1}]}'

2.9storage.bucket.set_notification

POST /v1/storage/bucket/set_notification/{bucket}

Subscribe storage object events to a callback URL.

Parameters

NameTypeRequiredDescription
bucketstring
Required
Bucket name.
events("object.created" | "object.deleted" | "multipart.completed")[]
Required
Event types to subscribe to. Supported values are object.created, object.deleted, and multipart.completed.
≥ 1 iteme.g. ["object.created","object.deleted","multipart.completed"]
target{ url: string }
Required
Callback target. Pass {"url":"https://..."}; when an event fires, the endpoint receives a JSON POST with X-Infrai-Event and body fields event/type, account_id, bucket, key, timestamp, and subscription_id.
e.g. {"url":"https://example.com/storage-events"}
idempotency_keystringOptionalIdempotency key; derived automatically when omitted.

Returns

BucketSetNotificationResult { subscription_id }
NameTypeDescription
subscription_idstringUnique identifier for this subscription

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"events": ["object.created", "object.deleted", "multipart.completed"], "target": {"url": "https://example.com/storage-events"}}'

2.10storage.object.put

PUT /v1/storage/object/put/{bucket}/{key}

Upload an object server-side with JSON data_base64. Base64 upload is intended for small files and is not recommended above 1 MB; use presigned direct upload or multipart direct upload for larger files.

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称
keystring
Required
对象键(路径)
data_base64string
Required
Object bytes encoded as a base64 string in the JSON request body. A data: URL is also accepted. Base64 upload is intended for small files and is not recommended above 1 MB.
datastring | nullOptionalAlias for data_base64.
file_base64string | nullOptionalAlias for data_base64.
content_typestringOptional对象的 MIME 类型
metadataRecord<string, string>Optional任意用户自定义元数据键值对
cache_controlstringOptionalCache-Control 头
storage_classstringOptional存储类别(默认 standard)
default: "standard"
idempotency_keystringOptional幂等键;省略时按内容哈希自动派生

Returns

StorageObject { bucket_id, key, size_bytes, etag, content_type, metadata, created_at, last_modified }
NameTypeDescription
bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
keystringUnique identifier key for this resource
size_bytesintegerSize of the resource in bytes
≥ 0
etagstringETag hash of the object content
content_typestring | nullMIME type of the object
metadataobject | nullArbitrary key-value metadata attached to this resource
created_atstringISO 8601 timestamp when this resource was created
format: date-time
last_modifiedstring | nullISO 8601 timestamp when the object was last modified
format: date-time

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X PUT https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data_base64": "sample"}'

2.11storage.object.get

GET /v1/storage/object/get/{bucket}/{key}

Download object content as JSON metadata plus base64-encoded data_base64.

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称
keystring
Required
对象键(路径)

Returns

object bytes (application/octet-stream)
NameTypeDescription
foundbooleanWhether the object was found
statusstring"found" or "not_found"
keystringKey of the requested object
size_bytesintegerSize of the object in bytes (present only when found)
data_base64stringBase64-encoded object content (present only when found)

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.12storage.object.head

GET /v1/storage/object/head/{bucket}/{key}

查询对象元信息

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称
keystring
Required
对象键(路径)

Returns

ObjectHeadResult { found, status, key, size_bytes, etag, content_type, metadata, last_modified }
NameTypeDescription
foundbooleanWhether the resource was found
status"found" | "not_found"Current status of this resource
keystring | nullUnique identifier key for this resource
size_bytesinteger | nullSize of the resource in bytes
≥ 0
etagstring | nullETag hash of the object content
content_typestring | nullMIME type of the object
metadataobject | nullArbitrary key-value metadata attached to this resource
last_modifiedstring | nullISO 8601 timestamp when the object was last modified
format: date-time

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.13storage.object.list

GET /v1/storage/object/list/{bucket}

列举存储桶内对象

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称
prefixstringOptional仅列举键以此前缀开头的对象
delimiterstringOptionalS3 风格的目录分隔符(如 /),将键归并为 common_prefixes
cursorstringOptional来自上次 next_cursor 的分页游标
limitnumberOptional本次返回的最大条数(1-1000)

Returns

ObjectListResult { items: StorageObject[], next_cursor, common_prefixes }
NameTypeDescription
itemsobject[]Array of result items in this page
items[].bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
items[].keystringUnique identifier key for this resource
items[].size_bytesintegerSize of the resource in bytes
≥ 0
items[].etagstringETag hash of the object content
items[].content_typestring | nullMIME type of the object
items[].metadataobject | nullArbitrary key-value metadata attached to this resource
items[].created_atstringISO 8601 timestamp when this resource was created
format: date-time
items[].last_modifiedstring | nullISO 8601 timestamp when the object was last modified
format: date-time
next_cursorstring | nullOpaque cursor to fetch the next page; null/absent if this is the last page
common_prefixesstring[] | nullS3-style folder prefixes when a delimiter was supplied to object.list.

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/storage/object/list/BUCKET \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.14storage.object.copy

POST /v1/storage/object/copy

Copy an object within or across buckets while preserving content_type and custom metadata.

Parameters

NameTypeRequiredDescription
src_bucketstring
Required
源存储桶名称
src_keystring
Required
源对象键
dst_bucketstring
Required
目标存储桶名称
dst_keystring
Required
目标对象键
idempotency_keystringOptional幂等键;省略时自动派生

Returns

StorageObject { bucket_id, key, size_bytes, etag, content_type, metadata, created_at, last_modified }
NameTypeDescription
bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
keystringUnique identifier key for this resource
size_bytesintegerSize of the resource in bytes
≥ 0
etagstringETag hash of the object content
content_typestring | nullMIME type of the object
metadataobject | nullArbitrary key-value metadata attached to this resource
created_atstringISO 8601 timestamp when this resource was created
format: date-time
last_modifiedstring | nullISO 8601 timestamp when the object was last modified
format: date-time

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/object/copy \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"src_bucket": "sample", "src_key": "sample", "dst_bucket": "sample", "dst_key": "sample"}'

2.15storage.object.delete_batch

POST /v1/storage/object/delete_batch/{bucket}

Delete objects in a batch, returning deleted and errors; missing keys are reported in errors.

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称
keysstring[]
Required
Object keys to delete, 1-1000 items. Missing keys are returned in errors with code STORAGE_OBJECT_NOT_FOUND.
1–1000 items
idempotency_keystringOptional幂等键;省略时按键集合内容哈希自动派生

Returns

ObjectDeleteBatchResult { deleted, errors }
NameTypeDescription
deletedstring[]Keys successfully deleted.
errorsobject[]Array of per-item errors (for batch operations)
errors[].keystring-
errors[].codestringError code from errors/registry.yaml.

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"keys": ["sample"]}'

2.16storage.object.set_acl

POST /v1/storage/object/set_acl/{bucket}/{key}

Set object access policy. Current supported ACL values are private and signed-only; public/public-read are not supported.

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称
keystring
Required
对象键(路径)
acl"private" | "signed-only"
Required
Access policy. Supported values are private and signed-only; public and public-read are not supported, and public_url is always null.
idempotency_keystringOptional幂等键;省略时自动派生

Returns

ObjectSetAclResult { acl, public_url }
NameTypeDescription
acl"private" | "signed-only"Access control list for the bucket or object
public_urlstring | nullAlways null (public-read removed; no permanent public direct link).

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"acl": "private"}'

2.17storage.object.set_metadata

POST /v1/storage/object/set_metadata/{bucket}/{key}

Update an object content_type, cache_control, and custom metadata. metadata uses replacement semantics.

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称
keystring
Required
对象键(路径)
content_typestringOptional对象的 MIME 类型
cache_controlstringOptionalCache-Control 头
metadataRecord<string, string>OptionalCustom metadata key/value pairs. Passing metadata replaces the previous metadata instead of merging with it; omitted metadata preserves the old value.
idempotency_keystringOptional幂等键;省略时自动派生

Returns

StorageObject { bucket_id, key, size_bytes, etag, content_type, metadata, created_at, last_modified }
NameTypeDescription
bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
keystringUnique identifier key for this resource
size_bytesintegerSize of the resource in bytes
≥ 0
etagstringETag hash of the object content
content_typestring | nullMIME type of the object
metadataobject | nullArbitrary key-value metadata attached to this resource
created_atstringISO 8601 timestamp when this resource was created
format: date-time
last_modifiedstring | nullISO 8601 timestamp when the object was last modified
format: date-time

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

2.18storage.multipart.create

POST /v1/storage/multipart/create/{bucket}

发起分片上传

Parameters

NameTypeRequiredDescription
bucketstring
Required
存储桶名称
keystring
Required
对象键(路径)
content_typestringOptional对象的 MIME 类型
idempotency_keystringOptional幂等键;省略时自动派生

Returns

MultipartUpload { upload_id, bucket_id, key, started_at, part_size_min, part_count_max }
NameTypeDescription
upload_idstringUnique identifier for this multipart upload
bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
keystringUnique identifier key for this resource
started_atstringISO 8601 timestamp when execution started
format: date-time
part_size_mininteger | nullVendor minimum part size (≥5 MiB for S3).
≥ 5242880
part_count_maxinteger | nullMaximum number of parts allowed
1–10000

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/multipart/create/BUCKET \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"key": "sample"}'

2.19storage.multipart.presign_part

POST /v1/storage/multipart/presign_part/{upload_id}/{part_number}

Generate a presigned upload URL for one part. Upload that part binary with the returned method and pass the returned ETag to complete.

Parameters

NameTypeRequiredDescription
upload_idstring
Required
分片上传 ID
part_numbernumber
Required
Part number, starting at 1. Except for the final part, the binary part uploaded to this URL usually must be at least 5 MiB.
≥ 1

Returns

MultipartPresignPartResult { url, method, headers, expires_at }
NameTypeDescription
urlstringURL for this resource or endpoint
method"PUT"Authentication method used (e.g. email_otp, oauth, password)
headersobject | nullCustom HTTP headers to include in requests or responses
expires_atstringISO 8601 timestamp when this resource or token expires
format: date-time

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"upload_id": "sample", "part_number": 1}'

2.20storage.multipart.upload_part

PUT /v1/storage/multipart/upload_part/{upload_id}/{part_number}

上传单个分片

Parameters

NameTypeRequiredDescription
upload_idstring
Required
分片上传 ID
part_numbernumber
Required
分片序号(从 1 开始)
≥ 1
bodybytes
Required
分片字节内容
idempotency_keystringOptional幂等键;省略时自动派生

Returns

MultipartPart { part_number, etag }
NameTypeDescription
part_numberintegerPart number in the multipart upload
1–10000
etagstringETag hash of the object content
size_bytesinteger | nullSize of the resource in bytes
≥ 0

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X PUT https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"upload_id": "sample", "part_number": 1, "data_base64": "sample"}'

2.21storage.multipart.complete

POST /v1/storage/multipart/complete/{upload_id}

完成分片上传

Parameters

NameTypeRequiredDescription
upload_idstring
Required
分片上传 ID
partsMultipartPart[]
Required
Uploaded part list, each with part_number and etag, 1-10000 items. Use the ETag returned by each part upload.
1–10000 items
idempotency_keystringOptional幂等键;省略时自动派生

Returns

StorageObject { bucket_id, key, size_bytes, etag, content_type, metadata, created_at, last_modified }
NameTypeDescription
bucket_idstringUnique identifier for this storage bucket
pattern: ^bkt_[A-Za-z0-9]{20,}$
keystringUnique identifier key for this resource
size_bytesintegerSize of the resource in bytes
≥ 0
etagstringETag hash of the object content
content_typestring | nullMIME type of the object
metadataobject | nullArbitrary key-value metadata attached to this resource
created_atstringISO 8601 timestamp when this resource was created
format: date-time
last_modifiedstring | nullISO 8601 timestamp when the object was last modified
format: date-time

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"parts": [{"part_number": 1, "etag": "sample"}]}'

2.22storage.multipart.abort

DELETE /v1/storage/multipart/abort/{upload_id}

Abort a multipart upload. After success, the upload_id is invalid and later presign_part/complete calls return STORAGE_MULTIPART_INCONSISTENT.

Parameters

NameTypeRequiredDescription
upload_idstring
Required
分片上传 ID
idempotency_keystringOptional幂等键;省略时自动派生

Returns

MultipartAbortResult { aborted }
NameTypeDescription
abortedbooleanWhether the multipart upload was successfully aborted

Example

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X DELETE https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID \
  -H "Authorization: Bearer $INFRAI_API_KEY"
Advanced: pin a vendor

By default infrai routes each call to the best available provider — you do not pick a vendor. As an escape hatch, this capability accepts an optional vendor parameter to pin one specific provider. Every live vendor for this capability is available in real time from the discovery endpoint for the capability id — see the discovery API.

GET /v1/discovery/{capability}

storage.bucket.create

3. All capabilities

Every routed capability in this module — the complete public REST contract. The methods above are the guided walkthrough; this index is the full reference.

storage.bucket.createPOST /v1/storage/bucket/create

Create an object storage bucket. Bucket names must be 3-63 lowercase letters, digits, dots, or hyphens and start/end with a letter or digit; `region` must be a canonical region code.

Parameters (6)
NameTypeRequiredDescription
namestringRequiredBucket name. Length 3-63; lowercase letters, digits, dots, and hyphens only; must start and end with a letter or digit. Example: demo-files.
bucketstring | nullOptionalAlias for name. Prefer name in new integrations.
vendorstring | nullOptionalPin to a specific storage vendor.
region"us-east-1" | "us-west-2" | "eu-west-1" | "eu-central-1" | "ap-southeast-1" | "ap-northeast-1" | "cn-hangzhou" | "cn-beijing" | "auto" | "ap-singapore" | "ap-hongkong" | "ap-tokyo" | "ap-bangkok" | "na-siliconvalley" | nullOptionalOptional storage region code. Pass a canonical code such as cn-beijing for Beijing or ap-singapore for Singapore; localized names such as 北京 are rejected.
aclstringOptionalBucket access control. Defaults to private; currently only private and signed-only are supported. public and public-read are not supported.
default: "private"
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.bucket.deleteDELETE /v1/storage/bucket/delete/{bucket}

Delete an object storage bucket (idempotent). Empty buckets can be deleted directly; non-empty buckets require `force=true`, otherwise the API returns STORAGE_DELETE_NOT_FORCED.

Parameters (1)
NameTypeRequiredDescription
bucketstringRequiredPath parameter.
storage.bucket.getGET /v1/storage/bucket/get/{bucket}

Retrieve a bucket's metadata (provider, region, ACL, CORS, and lifecycle rules).

Parameters (1)
NameTypeRequiredDescription
bucketstringRequiredPath parameter.
storage.bucket.listGET /v1/storage/bucket/list

List the account's object storage buckets.

No request parameters.

storage.bucket.set_lifecyclePOST /v1/storage/bucket/set_lifecycle/{bucket}

Set bucket lifecycle rules by key prefix; expire_days is measured in days and must be at least 1.

Parameters (3)
NameTypeRequiredDescription
bucketstringRequiredPath parameter.
rulesobject[]RequiredLifecycle rule set governing object expiration/transition. Each rule supports prefix, expire_days, and transition_class. The whole list replaces the existing rule set.
e.g. [{"prefix":"tmp/","expire_days":1}]
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.bucket.set_notificationPOST /v1/storage/bucket/set_notification/{bucket}

Subscribe storage object events to a callback URL; Infrai sends JSON POST notifications with X-Infrai-Event.

Parameters (4)
NameTypeRequiredDescription
bucketstringRequiredPath parameter.
events("object.created" | "object.deleted" | "multipart.completed")[]RequiredEvent types that trigger a notification. Supported values are object.created, object.deleted, and multipart.completed.
≥ 1 iteme.g. ["object.created","object.deleted","multipart.completed"]
targetobjectRequiredNotification callback target. For public API usage, pass target.url.
e.g. {"url":"https://example.com/storage-events"}
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.bucket.usageGET /v1/storage/bucket/usage/{bucket}

Query a bucket's usage statistics: object count, bytes stored, and measurement timestamp.

Parameters (1)
NameTypeRequiredDescription
bucketstringRequiredPath parameter.
storage.multipart.abortDELETE /v1/storage/multipart/abort/{upload_id}

Abort a multipart upload and invalidate the upload_id.

Parameters (1)
NameTypeRequiredDescription
upload_idstringRequiredPath parameter.
storage.multipart.completePOST /v1/storage/multipart/complete/{upload_id}

Complete a multipart upload, assembling parts into the final StorageObject.

Parameters (3)
NameTypeRequiredDescription
upload_idstringRequiredPath parameter.
partsobject[]RequiredUploaded parts (part number + ETag) to assemble into the final object, in order.
1–10000 items
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.multipart.createPOST /v1/storage/multipart/create/{bucket}

Initiate a multipart upload, returning an upload_id and part size/count limits.

Parameters (4)
NameTypeRequiredDescription
bucketstringRequiredPath parameter.
keystringRequiredDestination object key (path) for the multipart upload.
content_typestring | nullOptionalMIME type of the object
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.multipart.presign_partPOST /v1/storage/multipart/presign_part/{upload_id}/{part_number}

Generate a presigned upload URL for a single part; upload the part binary with the returned method.

Parameters (3)
NameTypeRequiredDescription
upload_idstringRequiredId of the multipart upload.
part_numberintegerRequired1-based index of the part being uploaded. Except for the final part, S3-compatible multipart uploads usually require each part to be at least 5 MiB.
≥ 1
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.multipart.upload_partPUT /v1/storage/multipart/upload_part/{upload_id}/{part_number}

Upload the bytes of a single part, returning that part's etag.

Parameters (6)
NameTypeRequiredDescription
upload_idstringRequiredId of the multipart upload.
part_numberintegerRequired1-based index of this part.
≥ 1
data_base64stringRequiredBase64-encoded part bytes (the part payload — required). Aliases data/file_base64 are also accepted by the server.
datastring | nullOptionalBase64-encoded part bytes (alias of data_base64/file_base64).
file_base64string | nullOptionalBase64-encoded part bytes (alias).
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.object.copyPOST /v1/storage/object/copy

Copy an object within or across buckets, preserving content_type and metadata.

Parameters (5)
NameTypeRequiredDescription
src_bucketstringRequiredSource bucket to copy from.
src_keystringRequiredSource object key (path) to copy from.
dst_bucketstringRequiredDestination bucket to copy into.
dst_keystringRequiredDestination object key (path) to write.
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.object.deleteDELETE /v1/storage/object/delete/{bucket}/{key}

Delete a storage object (idempotent).

Parameters (2)
NameTypeRequiredDescription
keystringRequiredPath parameter.
bucketstringRequiredPath parameter.
storage.object.delete_batchPOST /v1/storage/object/delete_batch/{bucket}

Delete up to 1000 objects in one call, returning deleted keys plus per-key errors.

Parameters (3)
NameTypeRequiredDescription
bucketstringRequiredPath parameter.
keysstring[]RequiredObject keys to delete in one batch. Missing keys are returned in errors with code STORAGE_OBJECT_NOT_FOUND.
1–1000 items
idempotency_keystring | nullOptionalOptional; SDK auto-derives from the content_hash of the key set when omitted.
storage.object.getGET /v1/storage/object/get/{bucket}/{key}

Download an object's contents as JSON metadata plus base64-encoded data_base64.

Parameters (2)
NameTypeRequiredDescription
keystringRequiredPath parameter.
bucketstringRequiredPath parameter.
storage.object.headGET /v1/storage/object/head/{bucket}/{key}

Fetch an object's existence and metadata (size, etag, content_type, metadata) without the body.

Parameters (2)
NameTypeRequiredDescription
keystringRequiredPath parameter.
bucketstringRequiredPath parameter.
storage.object.listGET /v1/storage/object/list/{bucket}

List objects in a bucket, supporting prefix, delimiter, and cursor pagination.

Parameters (1)
NameTypeRequiredDescription
bucketstringRequiredPath parameter.
storage.object.presignPOST /v1/storage/object/presign/{bucket}/{key}

Generate a presigned URL for direct client upload or download of an object (idempotent). For `op=put`, use the returned URL with its returned method (usually PUT) to upload raw binary bytes directly; do not send the Infrai API key to the presigned URL.

Parameters (8)
NameTypeRequiredDescription
keystringRequiredPath parameter.
bucketstringRequiredPath parameter.
op"get" | "put"RequiredOperation type: get creates a download URL; put creates an upload URL for direct binary upload.
e.g. put
expires_secondsinteger | nullOptionalTTL of the presigned URL (defaults: get=3600, put=300).
≥ 1
content_typestring | nullOptionalFor op=put: constrain the upload content type.
max_bytesinteger | nullOptionalFor op=put: cap the upload size.
≥ 0
response_dispositionstring | nullOptionalFor op=get: Content-Disposition for the download filename.
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.object.putPUT /v1/storage/object/put/{bucket}/{key}

Upload an object server-side with JSON `data_base64`. Base64 upload is intended for small files and is not recommended above 1 MB; use presigned or multipart direct upload for larger files.

Parameters (10)
NameTypeRequiredDescription
keystringRequiredPath parameter.
bucketstringRequiredPath parameter.
data_base64stringRequiredREQUIRED. The object bytes, base64-encoded as a bare base64 string or data: URL. Intended for small files; not recommended above 1 MB.
datastring | nullOptionalAlias for data_base64 (base64-encoded object bytes).
file_base64string | nullOptionalAlias for data_base64 (base64-encoded object bytes).
content_typestring | nullOptionalMIME type of the object
metadataobject | nullOptionalArbitrary user metadata key/value pairs.
cache_controlstring | nullOptionalCache-Control header value
storage_classstring | nullOptionalStorage class (e.g. standard, infrequent_access)
default: "standard"
idempotency_keystring | nullOptionalOptional; SDK auto-derives a content-hash key (bucket_id+key+content) when omitted.
storage.object.set_aclPOST /v1/storage/object/set_acl/{bucket}/{key}

Set object access policy. Current supported ACL values are private and signed-only; public/public-read are not supported.

Parameters (4)
NameTypeRequiredDescription
keystringRequiredPath parameter.
bucketstringRequiredPath parameter.
acl"private" | "signed-only"RequiredAccess policy. Supported values: private, signed-only. public/public-read are not supported; public_url remains null.
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
storage.object.set_metadataPOST /v1/storage/object/set_metadata/{bucket}/{key}

Update a stored object's content-type, cache-control, and custom metadata; metadata replaces previous metadata.

Parameters (6)
NameTypeRequiredDescription
keystringRequiredPath parameter.
bucketstringRequiredPath parameter.
content_typestring | nullOptionalMIME type of the object
cache_controlstring | nullOptionalCache-Control header value
metadataobject | nullOptionalCustom metadata key/value pairs. Passing metadata replaces the previous metadata instead of merging with it; omit metadata to preserve the old value.
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry

4. End-to-end example

A production-style walkthrough of this module: configure once, then run the flow. It exercises most of the module's APIs.

A copy-paste-runnable single-file Python program (stdlib only, no SDK): set your INFRAI_API_KEY, run it, and walk this module's core flow with REAL billed calls — later steps reuse real fields returned by earlier ones. The 12-line helper is the entire integration.

python
#!/usr/bin/env python3
"""Infrai · storage — runnable real-app example (single file, zero deps).

Copy this file, set your key, run it: every step is a REAL call to
api.infrai.cc, billed at the real (tiny) per-call price, printing the
live JSON response. Get a key at https://infrai.cc/login (Google/
GitHub sign-in grants $2 free credit); add funds at
https://infrai.cc/billing. No SDK — the 12-line helper below is the
entire integration."""
import json
import os
from urllib import error, request

KEY = os.environ.get("INFRAI_API_KEY") or "ifr_..."  # <- your key
BASE = "https://api.infrai.cc"


# Same raw HTTPS POST/GET as every per-method example on this page —
# wrapped once for reuse. There is nothing else to it: no SDK.
def infrai(method, path, body=None):
    req = request.Request(
        BASE + path, method=method,
        data=json.dumps(body).encode() if body is not None else None,
        headers={"Authorization": f"Bearer {KEY}",
                 "Content-Type": "application/json"})
    try:
        with request.urlopen(req, timeout=60) as r:
            return json.loads(r.read())
    except error.HTTPError as e:
        return json.loads(e.read())


def show(label, resp):
    print(f"\n== {label} ==")
    print(json.dumps(resp, indent=2, ensure_ascii=False))
    return resp


# 1) storage.bucket.create — POST /v1/storage/bucket/create · Create an object storage bucket. Bucket names must be 3-63 lowercase letters, digits, dots, or hyphens and start/end with a letter or digit; `region` must be a canonical region code.
r1 = show("storage.bucket.create", infrai("POST", "/v1/storage/bucket/create", {"name":"demo-bucket"}))

# 2) storage.object.presign — POST /v1/storage/object/presign/{bucket}/{key} · Generate a presigned URL for direct client upload or download of an object (idempotent). For `op=put`, use the returned URL with its returned method (usually PUT) to upload raw binary bytes directly; do not send the Infrai API key to the presigned URL.
bucket_2 = (r1.get("data") or {}).get("name") or ""
r2 = show("storage.object.presign", infrai("POST", f"/v1/storage/object/presign/{bucket_2}/hello.txt", {"op":"put","expires_seconds":300}))

# 3) storage.bucket.list — GET /v1/storage/bucket/list · List the account's object storage buckets.
r3 = show("storage.bucket.list", infrai("GET", "/v1/storage/bucket/list"))