Storage
S3-compatible buckets and objects with presigned URLs.
1. Overview
https://api.infrai.cc/v1/storageAuthorization: Bearer $INFRAI_API_KEY# 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
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
| Name | Type | Required | Description |
|---|---|---|---|
name | string | 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. |
bucket | string | Optional | Alias for name. Prefer name in new integrations. |
vendor | string | Optional | Pin 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" | null | Optional | Storage 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" | Optional | Bucket 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? }| Name | Type | Description |
|---|---|---|
bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
name | string | Human-readable name for this resource |
vendor | "r2" | "s3" | "oss" | "cos" | Vendor that handled or will handle this request |
region | string | null | Geographic region where this resource is located or processed |
acl | "private" | "signed-only" | Access control list for the bucket or object |
created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
cors_rules | object[] | CORS configuration rules for the bucket |
lifecycle_rules | object[] | Lifecycle management rules for the bucket |
lifecycle_rules[].prefix | string | Match objects whose key starts with this.e.g. tmp/ |
lifecycle_rules[].expire_days | integer | null | Auto-delete after N days.≥ 1e.g. 1 |
lifecycle_rules[].transition_class | string | null | Transition to colder storage class (e.g. "glacier"). |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/bucket/create",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'name': 'example'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/create",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"name": "example"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/create",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"name": "example"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"name": "example"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/bucket/create", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/bucket/create"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"name\": \"example\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/bucket/create");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"name\": \"example\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/bucket/create");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"name\": \"example\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/bucket/create")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"name": "example"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/bucket/create")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"name": "example"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.2storage.bucket.list
List your buckets.
Returns
{ items: Bucket[] }| Name | Type | Description |
|---|---|---|
items | object[] | Array of result items in this page |
items[].bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
items[].name | string | Human-readable name for this resource |
items[].vendor | "r2" | "s3" | "oss" | "cos" | Vendor that handled or will handle this request |
items[].region | string | null | Geographic region where this resource is located or processed |
items[].acl | "private" | "signed-only" | Access control list for the bucket or object |
items[].created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
items[].cors_rules | object[] | CORS configuration rules for the bucket |
items[].lifecycle_rules | object[] | Lifecycle management rules for the bucket |
items[].lifecycle_rules[].prefix | string | Match objects whose key starts with this.e.g. tmp/ |
items[].lifecycle_rules[].expire_days | integer | null | Auto-delete after N days.≥ 1e.g. 1 |
items[].lifecycle_rules[].transition_class | string | null | Transition to colder storage class (e.g. "glacier"). |
next_cursor | string | null | Opaque cursor to fetch the next page; null/absent if this is the last page |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X GET https://api.infrai.cc/v1/storage/bucket/list \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/bucket/list",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/list",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/list",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.infrai.cc/v1/storage/bucket/list", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/bucket/list"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.infrai.cc/v1/storage/bucket/list");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/bucket/list");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/bucket/list")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.get("https://api.infrai.cc/v1/storage/bucket/list")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.3storage.object.presign
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
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Bucket name. |
key | string | 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_seconds | number | Optional | Presigned URL lifetime in seconds.≥ 1 |
Returns
PresignedUrl { url, method, expires_at, headers? }| Name | Type | Description |
|---|---|---|
url | string | URL for this resource or endpoint |
method | "PUT" | "POST" | Authentication method used (e.g. email_otp, oauth, password) |
headers | object | null | Custom HTTP headers to include in requests or responses |
fields | object | null | For POST form uploads. |
expires_at | string | ISO 8601 timestamp when this resource or token expiresformat: date-time |
max_bytes | integer | null | Maximum allowed file size in bytes≥ 0 |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'op': 'put'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"op": "put"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"op": "put"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"op": "put"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"op\": \"put\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"op\": \"put\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"op\": \"put\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"op": "put"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"op": "put"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.4storage.object.delete
Delete a single object from a bucket. After deletion, head/get report the object as not found.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Bucket name. |
key | string | Required | Object key (path) within the bucket. |
Returns
{ ok: boolean }| Name | Type | Description |
|---|---|---|
bucket | string | Bucket the object was deleted from |
key | string | Key of the deleted object |
deleted | boolean | Whether the object existed and was deleted |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X DELETE https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.delete(
"https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("DELETE", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("DELETE"), "https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.delete("https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.5storage.bucket.get
获取存储桶元信息
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
Returns
Bucket { bucket_id, name, vendor, region, acl, created_at, cors_rules, lifecycle_rules }| Name | Type | Description |
|---|---|---|
bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
name | string | Human-readable name for this resource |
vendor | "r2" | "s3" | "oss" | "cos" | Vendor that handled or will handle this request |
region | string | null | Geographic region where this resource is located or processed |
acl | "private" | "signed-only" | Access control list for the bucket or object |
created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
cors_rules | object[] | CORS configuration rules for the bucket |
lifecycle_rules | object[] | Lifecycle management rules for the bucket |
lifecycle_rules[].prefix | string | Match objects whose key starts with this.e.g. tmp/ |
lifecycle_rules[].expire_days | integer | null | Auto-delete after N days.≥ 1e.g. 1 |
lifecycle_rules[].transition_class | string | null | Transition to colder storage class (e.g. "glacier"). |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X GET https://api.infrai.cc/v1/storage/bucket/get/BUCKET \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/bucket/get/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/get/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/get/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.infrai.cc/v1/storage/bucket/get/BUCKET", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/bucket/get/BUCKET"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.infrai.cc/v1/storage/bucket/get/BUCKET");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/bucket/get/BUCKET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/bucket/get/BUCKET")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.get("https://api.infrai.cc/v1/storage/bucket/get/BUCKET")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.6storage.bucket.delete
Delete a bucket. Empty buckets can be deleted directly; non-empty buckets require force=true, otherwise STORAGE_DELETE_NOT_FORCED is returned.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Bucket name |
force | boolean | Optional | Whether 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_key | string | Optional | Idempotency key; derived automatically when omitted. |
Returns
BucketDeleteResult { deleted }| Name | Type | Description |
|---|---|---|
deleted | boolean | Whether the resource was successfully deleted |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X DELETE https://api.infrai.cc/v1/storage/bucket/delete/BUCKET \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.delete(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.infrai.cc/v1/storage/bucket/delete/BUCKET", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/bucket/delete/BUCKET"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("DELETE", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("DELETE"), "https://api.infrai.cc/v1/storage/bucket/delete/BUCKET");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/bucket/delete/BUCKET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/bucket/delete/BUCKET")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.delete("https://api.infrai.cc/v1/storage/bucket/delete/BUCKET")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.7storage.bucket.usage
查询存储桶用量
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
Returns
BucketUsageResult { byte_count, object_count, as_of }| Name | Type | Description |
|---|---|---|
byte_count | integer | Total bytes stored in the bucket≥ 0 |
object_count | integer | Number of objects in the bucket≥ 0 |
as_of | string | ISO 8601 timestamp when the usage was measuredformat: date-time |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X GET https://api.infrai.cc/v1/storage/bucket/usage/BUCKET \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/bucket/usage/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/usage/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/usage/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.infrai.cc/v1/storage/bucket/usage/BUCKET", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/bucket/usage/BUCKET"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.infrai.cc/v1/storage/bucket/usage/BUCKET");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/bucket/usage/BUCKET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/bucket/usage/BUCKET")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.get("https://api.infrai.cc/v1/storage/bucket/usage/BUCKET")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.8storage.bucket.set_lifecycle
Set bucket lifecycle rules.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Bucket name. |
rules | Array<{ 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_key | string | Optional | Idempotency key; derived automatically when omitted. |
Returns
Bucket { bucket_id, name, vendor, region, acl, created_at, cors_rules, lifecycle_rules }| Name | Type | Description |
|---|---|---|
bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
name | string | Human-readable name for this resource |
vendor | "r2" | "s3" | "oss" | "cos" | Vendor that handled or will handle this request |
region | string | null | Geographic region where this resource is located or processed |
acl | "private" | "signed-only" | Access control list for the bucket or object |
created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
cors_rules | object[] | CORS configuration rules for the bucket |
lifecycle_rules | object[] | Lifecycle management rules for the bucket |
lifecycle_rules[].prefix | string | Match objects whose key starts with this.e.g. tmp/ |
lifecycle_rules[].expire_days | integer | null | Auto-delete after N days.≥ 1e.g. 1 |
lifecycle_rules[].transition_class | string | null | Transition to colder storage class (e.g. "glacier"). |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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}]}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'rules': [{'prefix': 'tmp/', 'expire_days': 1}]},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"rules": [{"prefix": "tmp/", "expire_days": 1}]}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"rules": [{"prefix": "tmp/", "expire_days": 1}]}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"rules": [{"prefix": "tmp/", "expire_days": 1}]}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"rules\": [{\"prefix\": \"tmp/\", \"expire_days\": 1}]}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"rules\": [{\"prefix\": \"tmp/\", \"expire_days\": 1}]}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"rules\": [{\"prefix\": \"tmp/\", \"expire_days\": 1}]}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"rules": [{"prefix": "tmp/", "expire_days": 1}]}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"rules": [{"prefix": "tmp/", "expire_days": 1}]}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.9storage.bucket.set_notification
Subscribe storage object events to a callback URL.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | 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_key | string | Optional | Idempotency key; derived automatically when omitted. |
Returns
BucketSetNotificationResult { subscription_id }| Name | Type | Description |
|---|---|---|
subscription_id | string | Unique identifier for this subscription |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'events': ['object.created', 'object.deleted', 'multipart.completed'], 'target': {'url': 'https://example.com/storage-events'}},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"events": ["object.created", "object.deleted", "multipart.completed"], "target": {"url": "https://example.com/storage-events"}}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"events": ["object.created", "object.deleted", "multipart.completed"], "target": {"url": "https://example.com/storage-events"}}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"events": ["object.created", "object.deleted", "multipart.completed"], "target": {"url": "https://example.com/storage-events"}}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"events\": [\"object.created\", \"object.deleted\", \"multipart.completed\"], \"target\": {\"url\": \"https://example.com/storage-events\"}}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"events\": [\"object.created\", \"object.deleted\", \"multipart.completed\"], \"target\": {\"url\": \"https://example.com/storage-events\"}}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"events\": [\"object.created\", \"object.deleted\", \"multipart.completed\"], \"target\": {\"url\": \"https://example.com/storage-events\"}}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"events": ["object.created", "object.deleted", "multipart.completed"], "target": {"url": "https://example.com/storage-events"}}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/bucket/set_notification/BUCKET")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"events": ["object.created", "object.deleted", "multipart.completed"], "target": {"url": "https://example.com/storage-events"}}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.10storage.object.put
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
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
key | string | Required | 对象键(路径) |
data_base64 | string | 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. |
data | string | null | Optional | Alias for data_base64. |
file_base64 | string | null | Optional | Alias for data_base64. |
content_type | string | Optional | 对象的 MIME 类型 |
metadata | Record<string, string> | Optional | 任意用户自定义元数据键值对 |
cache_control | string | Optional | Cache-Control 头 |
storage_class | string | Optional | 存储类别(默认 standard)default: "standard" |
idempotency_key | string | Optional | 幂等键;省略时按内容哈希自动派生 |
Returns
StorageObject { bucket_id, key, size_bytes, etag, content_type, metadata, created_at, last_modified }| Name | Type | Description |
|---|---|---|
bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
key | string | Unique identifier key for this resource |
size_bytes | integer | Size of the resource in bytes≥ 0 |
etag | string | ETag hash of the object content |
content_type | string | null | MIME type of the object |
metadata | object | null | Arbitrary key-value metadata attached to this resource |
created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
last_modified | string | null | ISO 8601 timestamp when the object was last modifiedformat: date-time |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.put(
"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'data_base64': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY",
{
method: "PUT",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"data_base64": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY",
{
method: "PUT",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"data_base64": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"data_base64": "sample"}`)
req, _ := http.NewRequest("PUT", "https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("PUT", HttpRequest.BodyPublishers.ofString("{\"data_base64\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("PUT"), "https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"data_base64\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"data_base64\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Put.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"data_base64": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.put("https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"data_base64": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.11storage.object.get
Download object content as JSON metadata plus base64-encoded data_base64.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
key | string | Required | 对象键(路径) |
Returns
object bytes (application/octet-stream)| Name | Type | Description |
|---|---|---|
found | boolean | Whether the object was found |
status | string | "found" or "not_found" |
key | string | Key of the requested object |
size_bytes | integer | Size of the object in bytes (present only when found) |
data_base64 | string | Base64-encoded object content (present only when found) |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X GET https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.get("https://api.infrai.cc/v1/storage/object/get/BUCKET/KEY")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.12storage.object.head
查询对象元信息
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
key | string | Required | 对象键(路径) |
Returns
ObjectHeadResult { found, status, key, size_bytes, etag, content_type, metadata, last_modified }| Name | Type | Description |
|---|---|---|
found | boolean | Whether the resource was found |
status | "found" | "not_found" | Current status of this resource |
key | string | null | Unique identifier key for this resource |
size_bytes | integer | null | Size of the resource in bytes≥ 0 |
etag | string | null | ETag hash of the object content |
content_type | string | null | MIME type of the object |
metadata | object | null | Arbitrary key-value metadata attached to this resource |
last_modified | string | null | ISO 8601 timestamp when the object was last modifiedformat: date-time |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X GET https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.get("https://api.infrai.cc/v1/storage/object/head/BUCKET/KEY")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.13storage.object.list
列举存储桶内对象
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
prefix | string | Optional | 仅列举键以此前缀开头的对象 |
delimiter | string | Optional | S3 风格的目录分隔符(如 /),将键归并为 common_prefixes |
cursor | string | Optional | 来自上次 next_cursor 的分页游标 |
limit | number | Optional | 本次返回的最大条数(1-1000) |
Returns
ObjectListResult { items: StorageObject[], next_cursor, common_prefixes }| Name | Type | Description |
|---|---|---|
items | object[] | Array of result items in this page |
items[].bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
items[].key | string | Unique identifier key for this resource |
items[].size_bytes | integer | Size of the resource in bytes≥ 0 |
items[].etag | string | ETag hash of the object content |
items[].content_type | string | null | MIME type of the object |
items[].metadata | object | null | Arbitrary key-value metadata attached to this resource |
items[].created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
items[].last_modified | string | null | ISO 8601 timestamp when the object was last modifiedformat: date-time |
next_cursor | string | null | Opaque cursor to fetch the next page; null/absent if this is the last page |
common_prefixes | string[] | null | S3-style folder prefixes when a delimiter was supplied to object.list. |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X GET https://api.infrai.cc/v1/storage/object/list/BUCKET \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/object/list/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/list/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/list/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.infrai.cc/v1/storage/object/list/BUCKET", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/list/BUCKET"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.infrai.cc/v1/storage/object/list/BUCKET");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/list/BUCKET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/list/BUCKET")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.get("https://api.infrai.cc/v1/storage/object/list/BUCKET")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.14storage.object.copy
Copy an object within or across buckets while preserving content_type and custom metadata.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
src_bucket | string | Required | 源存储桶名称 |
src_key | string | Required | 源对象键 |
dst_bucket | string | Required | 目标存储桶名称 |
dst_key | string | Required | 目标对象键 |
idempotency_key | string | Optional | 幂等键;省略时自动派生 |
Returns
StorageObject { bucket_id, key, size_bytes, etag, content_type, metadata, created_at, last_modified }| Name | Type | Description |
|---|---|---|
bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
key | string | Unique identifier key for this resource |
size_bytes | integer | Size of the resource in bytes≥ 0 |
etag | string | ETag hash of the object content |
content_type | string | null | MIME type of the object |
metadata | object | null | Arbitrary key-value metadata attached to this resource |
created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
last_modified | string | null | ISO 8601 timestamp when the object was last modifiedformat: date-time |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/object/copy",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'src_bucket': 'sample', 'src_key': 'sample', 'dst_bucket': 'sample', 'dst_key': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/copy",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"src_bucket": "sample", "src_key": "sample", "dst_bucket": "sample", "dst_key": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/copy",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"src_bucket": "sample", "src_key": "sample", "dst_bucket": "sample", "dst_key": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"src_bucket": "sample", "src_key": "sample", "dst_bucket": "sample", "dst_key": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/object/copy", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/copy"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"src_bucket\": \"sample\", \"src_key\": \"sample\", \"dst_bucket\": \"sample\", \"dst_key\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/object/copy");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"src_bucket\": \"sample\", \"src_key\": \"sample\", \"dst_bucket\": \"sample\", \"dst_key\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/copy");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"src_bucket\": \"sample\", \"src_key\": \"sample\", \"dst_bucket\": \"sample\", \"dst_key\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/copy")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"src_bucket": "sample", "src_key": "sample", "dst_bucket": "sample", "dst_key": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/object/copy")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"src_bucket": "sample", "src_key": "sample", "dst_bucket": "sample", "dst_key": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.15storage.object.delete_batch
Delete objects in a batch, returning deleted and errors; missing keys are reported in errors.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
keys | string[] | Required | Object keys to delete, 1-1000 items. Missing keys are returned in errors with code STORAGE_OBJECT_NOT_FOUND.1–1000 items |
idempotency_key | string | Optional | 幂等键;省略时按键集合内容哈希自动派生 |
Returns
ObjectDeleteBatchResult { deleted, errors }| Name | Type | Description |
|---|---|---|
deleted | string[] | Keys successfully deleted. |
errors | object[] | Array of per-item errors (for batch operations) |
errors[].key | string | - |
errors[].code | string | Error code from errors/registry.yaml. |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"]}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'keys': ['sample']},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"keys": ["sample"]}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"keys": ["sample"]}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"keys": ["sample"]}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"keys\": [\"sample\"]}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"keys\": [\"sample\"]}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"keys\": [\"sample\"]}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"keys": ["sample"]}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/object/delete_batch/BUCKET")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"keys": ["sample"]}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.16storage.object.set_acl
Set object access policy. Current supported ACL values are private and signed-only; public/public-read are not supported.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
key | string | 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_key | string | Optional | 幂等键;省略时自动派生 |
Returns
ObjectSetAclResult { acl, public_url }| Name | Type | Description |
|---|---|---|
acl | "private" | "signed-only" | Access control list for the bucket or object |
public_url | string | null | Always null (public-read removed; no permanent public direct link). |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'acl': 'private'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"acl": "private"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"acl": "private"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"acl": "private"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"acl\": \"private\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"acl\": \"private\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"acl\": \"private\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"acl": "private"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/object/set_acl/BUCKET/KEY")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"acl": "private"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.17storage.object.set_metadata
Update an object content_type, cache_control, and custom metadata. metadata uses replacement semantics.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
key | string | Required | 对象键(路径) |
content_type | string | Optional | 对象的 MIME 类型 |
cache_control | string | Optional | Cache-Control 头 |
metadata | Record<string, string> | Optional | Custom metadata key/value pairs. Passing metadata replaces the previous metadata instead of merging with it; omitted metadata preserves the old value. |
idempotency_key | string | Optional | 幂等键;省略时自动派生 |
Returns
StorageObject { bucket_id, key, size_bytes, etag, content_type, metadata, created_at, last_modified }| Name | Type | Description |
|---|---|---|
bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
key | string | Unique identifier key for this resource |
size_bytes | integer | Size of the resource in bytes≥ 0 |
etag | string | ETag hash of the object content |
content_type | string | null | MIME type of the object |
metadata | object | null | Arbitrary key-value metadata attached to this resource |
created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
last_modified | string | null | ISO 8601 timestamp when the object was last modifiedformat: date-time |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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 '{}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/object/set_metadata/BUCKET/KEY")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.18storage.multipart.create
发起分片上传
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | 存储桶名称 |
key | string | Required | 对象键(路径) |
content_type | string | Optional | 对象的 MIME 类型 |
idempotency_key | string | Optional | 幂等键;省略时自动派生 |
Returns
MultipartUpload { upload_id, bucket_id, key, started_at, part_size_min, part_count_max }| Name | Type | Description |
|---|---|---|
upload_id | string | Unique identifier for this multipart upload |
bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
key | string | Unique identifier key for this resource |
started_at | string | ISO 8601 timestamp when execution startedformat: date-time |
part_size_min | integer | null | Vendor minimum part size (≥5 MiB for S3).≥ 5242880 |
part_count_max | integer | null | Maximum number of parts allowed1–10000 |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/multipart/create/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'key': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/create/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"key": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/create/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"key": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"key": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/multipart/create/BUCKET", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/multipart/create/BUCKET"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"key\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/multipart/create/BUCKET");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"key\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/multipart/create/BUCKET");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"key\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/multipart/create/BUCKET")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"key": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/multipart/create/BUCKET")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"key": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.19storage.multipart.presign_part
Generate a presigned upload URL for one part. Upload that part binary with the returned method and pass the returned ETag to complete.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
upload_id | string | Required | 分片上传 ID |
part_number | number | 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 }| Name | Type | Description |
|---|---|---|
url | string | URL for this resource or endpoint |
method | "PUT" | Authentication method used (e.g. email_otp, oauth, password) |
headers | object | null | Custom HTTP headers to include in requests or responses |
expires_at | string | ISO 8601 timestamp when this resource or token expiresformat: date-time |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'upload_id': 'sample', 'part_number': 1},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"upload_id": "sample", "part_number": 1}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"upload_id": "sample", "part_number": 1}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"upload_id": "sample", "part_number": 1}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"upload_id\": \"sample\", \"part_number\": 1}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"upload_id\": \"sample\", \"part_number\": 1}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"upload_id\": \"sample\", \"part_number\": 1}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"upload_id": "sample", "part_number": 1}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/multipart/presign_part/UPLOAD_ID/PART_NUMBER")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"upload_id": "sample", "part_number": 1}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.20storage.multipart.upload_part
上传单个分片
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
upload_id | string | Required | 分片上传 ID |
part_number | number | Required | 分片序号(从 1 开始)≥ 1 |
body | bytes | Required | 分片字节内容 |
idempotency_key | string | Optional | 幂等键;省略时自动派生 |
Returns
MultipartPart { part_number, etag }| Name | Type | Description |
|---|---|---|
part_number | integer | Part number in the multipart upload1–10000 |
etag | string | ETag hash of the object content |
size_bytes | integer | null | Size of the resource in bytes≥ 0 |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.put(
"https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'upload_id': 'sample', 'part_number': 1, 'data_base64': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER",
{
method: "PUT",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"upload_id": "sample", "part_number": 1, "data_base64": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER",
{
method: "PUT",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"upload_id": "sample", "part_number": 1, "data_base64": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"upload_id": "sample", "part_number": 1, "data_base64": "sample"}`)
req, _ := http.NewRequest("PUT", "https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("PUT", HttpRequest.BodyPublishers.ofString("{\"upload_id\": \"sample\", \"part_number\": 1, \"data_base64\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("PUT"), "https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"upload_id\": \"sample\", \"part_number\": 1, \"data_base64\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"upload_id\": \"sample\", \"part_number\": 1, \"data_base64\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Put.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"upload_id": "sample", "part_number": 1, "data_base64": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.put("https://api.infrai.cc/v1/storage/multipart/upload_part/UPLOAD_ID/PART_NUMBER")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"upload_id": "sample", "part_number": 1, "data_base64": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.21storage.multipart.complete
完成分片上传
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
upload_id | string | Required | 分片上传 ID |
parts | MultipartPart[] | 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_key | string | Optional | 幂等键;省略时自动派生 |
Returns
StorageObject { bucket_id, key, size_bytes, etag, content_type, metadata, created_at, last_modified }| Name | Type | Description |
|---|---|---|
bucket_id | string | Unique identifier for this storage bucketpattern: ^bkt_[A-Za-z0-9]{20,}$ |
key | string | Unique identifier key for this resource |
size_bytes | integer | Size of the resource in bytes≥ 0 |
etag | string | ETag hash of the object content |
content_type | string | null | MIME type of the object |
metadata | object | null | Arbitrary key-value metadata attached to this resource |
created_at | string | ISO 8601 timestamp when this resource was createdformat: date-time |
last_modified | string | null | ISO 8601 timestamp when the object was last modifiedformat: date-time |
Example
一次性前置(每个范例都假定已完成):
# 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_..."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"}]}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'parts': [{'part_number': 1, 'etag': 'sample'}]},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"parts": [{"part_number": 1, "etag": "sample"}]}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"parts": [{"part_number": 1, "etag": "sample"}]}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"parts": [{"part_number": 1, "etag": "sample"}]}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"parts\": [{\"part_number\": 1, \"etag\": \"sample\"}]}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"parts\": [{\"part_number\": 1, \"etag\": \"sample\"}]}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"parts\": [{\"part_number\": 1, \"etag\": \"sample\"}]}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"parts": [{"part_number": 1, "etag": "sample"}]}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/storage/multipart/complete/UPLOAD_ID")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"parts": [{"part_number": 1, "etag": "sample"}]}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.22storage.multipart.abort
Abort a multipart upload. After success, the upload_id is invalid and later presign_part/complete calls return STORAGE_MULTIPART_INCONSISTENT.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
upload_id | string | Required | 分片上传 ID |
idempotency_key | string | Optional | 幂等键;省略时自动派生 |
Returns
MultipartAbortResult { aborted }| Name | Type | Description |
|---|---|---|
aborted | boolean | Whether the multipart upload was successfully aborted |
Example
一次性前置(每个范例都假定已完成):
# 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_..."curl -X DELETE https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID \
-H "Authorization: Bearer $INFRAI_API_KEY"# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.delete(
"https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.method("DELETE", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("DELETE"), "https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.delete("https://api.infrai.cc/v1/storage/multipart/abort/UPLOAD_ID")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}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/createCreate 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)
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Required | Bucket name. Length 3-63; lowercase letters, digits, dots, and hyphens only; must start and end with a letter or digit. Example: demo-files. |
bucket | string | null | Optional | Alias for name. Prefer name in new integrations. |
vendor | string | null | Optional | Pin 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" | null | Optional | Optional storage region code. Pass a canonical code such as cn-beijing for Beijing or ap-singapore for Singapore; localized names such as 北京 are rejected. |
acl | string | Optional | Bucket access control. Defaults to private; currently only private and signed-only are supported. public and public-read are not supported.default: "private" |
idempotency_key | string | null | Optional | Client-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)
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Path parameter. |
storage.bucket.getGET /v1/storage/bucket/get/{bucket}Retrieve a bucket's metadata (provider, region, ACL, CORS, and lifecycle rules).
Parameters (1)
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Path parameter. |
storage.bucket.listGET /v1/storage/bucket/listList 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)
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Path parameter. |
rules | object[] | Required | Lifecycle 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_key | string | null | Optional | Client-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)
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Path parameter. |
events | ("object.created" | "object.deleted" | "multipart.completed")[] | Required | Event types that trigger a notification. Supported values are object.created, object.deleted, and multipart.completed.≥ 1 iteme.g. ["object.created","object.deleted","multipart.completed"] |
target | object | Required | Notification callback target. For public API usage, pass target.url.e.g. {"url":"https://example.com/storage-events"} |
idempotency_key | string | null | Optional | Client-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)
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Path parameter. |
storage.multipart.abortDELETE /v1/storage/multipart/abort/{upload_id}Abort a multipart upload and invalidate the upload_id.
Parameters (1)
| Name | Type | Required | Description |
|---|---|---|---|
upload_id | string | Required | Path parameter. |
storage.multipart.completePOST /v1/storage/multipart/complete/{upload_id}Complete a multipart upload, assembling parts into the final StorageObject.
Parameters (3)
| Name | Type | Required | Description |
|---|---|---|---|
upload_id | string | Required | Path parameter. |
parts | object[] | Required | Uploaded parts (part number + ETag) to assemble into the final object, in order.1–10000 items |
idempotency_key | string | null | Optional | Client-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)
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Path parameter. |
key | string | Required | Destination object key (path) for the multipart upload. |
content_type | string | null | Optional | MIME type of the object |
idempotency_key | string | null | Optional | Client-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)
| Name | Type | Required | Description |
|---|---|---|---|
upload_id | string | Required | Id of the multipart upload. |
part_number | integer | Required | 1-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_key | string | null | Optional | Client-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)
| Name | Type | Required | Description |
|---|---|---|---|
upload_id | string | Required | Id of the multipart upload. |
part_number | integer | Required | 1-based index of this part.≥ 1 |
data_base64 | string | Required | Base64-encoded part bytes (the part payload — required). Aliases data/file_base64 are also accepted by the server. |
data | string | null | Optional | Base64-encoded part bytes (alias of data_base64/file_base64). |
file_base64 | string | null | Optional | Base64-encoded part bytes (alias). |
idempotency_key | string | null | Optional | Client-provided idempotency key; prevents duplicate execution on retry |
storage.object.copyPOST /v1/storage/object/copyCopy an object within or across buckets, preserving content_type and metadata.
Parameters (5)
| Name | Type | Required | Description |
|---|---|---|---|
src_bucket | string | Required | Source bucket to copy from. |
src_key | string | Required | Source object key (path) to copy from. |
dst_bucket | string | Required | Destination bucket to copy into. |
dst_key | string | Required | Destination object key (path) to write. |
idempotency_key | string | null | Optional | Client-provided idempotency key; prevents duplicate execution on retry |
storage.object.deleteDELETE /v1/storage/object/delete/{bucket}/{key}Delete a storage object (idempotent).
Parameters (2)
| Name | Type | Required | Description |
|---|---|---|---|
key | string | Required | Path parameter. |
bucket | string | Required | Path 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)
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Path parameter. |
keys | string[] | Required | Object keys to delete in one batch. Missing keys are returned in errors with code STORAGE_OBJECT_NOT_FOUND.1–1000 items |
idempotency_key | string | null | Optional | Optional; 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)
| Name | Type | Required | Description |
|---|---|---|---|
key | string | Required | Path parameter. |
bucket | string | Required | Path 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)
| Name | Type | Required | Description |
|---|---|---|---|
key | string | Required | Path parameter. |
bucket | string | Required | Path parameter. |
storage.object.listGET /v1/storage/object/list/{bucket}List objects in a bucket, supporting prefix, delimiter, and cursor pagination.
Parameters (1)
| Name | Type | Required | Description |
|---|---|---|---|
bucket | string | Required | Path 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)
| Name | Type | Required | Description |
|---|---|---|---|
key | string | Required | Path parameter. |
bucket | string | Required | Path parameter. |
op | "get" | "put" | Required | Operation type: get creates a download URL; put creates an upload URL for direct binary upload.e.g. put |
expires_seconds | integer | null | Optional | TTL of the presigned URL (defaults: get=3600, put=300).≥ 1 |
content_type | string | null | Optional | For op=put: constrain the upload content type. |
max_bytes | integer | null | Optional | For op=put: cap the upload size.≥ 0 |
response_disposition | string | null | Optional | For op=get: Content-Disposition for the download filename. |
idempotency_key | string | null | Optional | Client-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)
| Name | Type | Required | Description |
|---|---|---|---|
key | string | Required | Path parameter. |
bucket | string | Required | Path parameter. |
data_base64 | string | Required | REQUIRED. The object bytes, base64-encoded as a bare base64 string or data: URL. Intended for small files; not recommended above 1 MB. |
data | string | null | Optional | Alias for data_base64 (base64-encoded object bytes). |
file_base64 | string | null | Optional | Alias for data_base64 (base64-encoded object bytes). |
content_type | string | null | Optional | MIME type of the object |
metadata | object | null | Optional | Arbitrary user metadata key/value pairs. |
cache_control | string | null | Optional | Cache-Control header value |
storage_class | string | null | Optional | Storage class (e.g. standard, infrequent_access)default: "standard" |
idempotency_key | string | null | Optional | Optional; 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)
| Name | Type | Required | Description |
|---|---|---|---|
key | string | Required | Path parameter. |
bucket | string | Required | Path parameter. |
acl | "private" | "signed-only" | Required | Access policy. Supported values: private, signed-only. public/public-read are not supported; public_url remains null. |
idempotency_key | string | null | Optional | Client-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)
| Name | Type | Required | Description |
|---|---|---|---|
key | string | Required | Path parameter. |
bucket | string | Required | Path parameter. |
content_type | string | null | Optional | MIME type of the object |
cache_control | string | null | Optional | Cache-Control header value |
metadata | object | null | Optional | Custom metadata key/value pairs. Passing metadata replaces the previous metadata instead of merging with it; omit metadata to preserve the old value. |
idempotency_key | string | null | Optional | Client-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.
#!/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"))
一次性前置(每个范例都假定已完成):
# 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_..."# 1) Auth: every call is a raw HTTPS request to the Infrai gateway carrying
# only your project key. No SDK, no install.
# Get your key: sign in with Google/GitHub at https://infrai.cc/login for a
# project key + $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_..." # from https://infrai.cc/login
# 2) storage.bucket.create
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"}'
# 3) storage.bucket.list
curl -X GET https://api.infrai.cc/v1/storage/bucket/list \
-H "Authorization: Bearer $INFRAI_API_KEY"
# 4) storage.object.presign
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 '{"bucket_id": "bkt_42", "key": "uploads/photo.jpg", "ttl_seconds": 3600}'
# Use data.url from the response above to upload the file bytes directly.
# Do not include the Infrai Authorization header on this PUT request.
curl -X PUT "PASTE_RETURNED_DATA_URL_HERE" \
-H "Content-Type: application/octet-stream" \
--data-binary @upload.bin
# 5) storage.object.delete
curl -X DELETE https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY \
-H "Authorization: Bearer $INFRAI_API_KEY"
# 6) storage.bucket.get
curl -X GET https://api.infrai.cc/v1/storage/bucket/get/BUCKET \
-H "Authorization: Bearer $INFRAI_API_KEY"
# 7) storage.bucket.delete
curl -X DELETE https://api.infrai.cc/v1/storage/bucket/delete/BUCKET \
-H "Authorization: Bearer $INFRAI_API_KEY"
# Non-empty buckets require force=true; otherwise the API returns STORAGE_DELETE_NOT_FORCED.
curl -X DELETE https://api.infrai.cc/v1/storage/bucket/delete/BUCKET \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"force": true}'
# 8) storage.bucket.usage
curl -X GET https://api.infrai.cc/v1/storage/bucket/usage/BUCKET \
-H "Authorization: Bearer $INFRAI_API_KEY"
# 9) storage.bucket.set_lifecycle
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}]}'
# 1) Auth: every call is a raw HTTPS request carrying only your project key.
# No SDK to install — just the `requests` library.
import os, requests
BASE = "https://api.infrai.cc"
HEADERS = {
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
"Content-Type": "application/json",
}
# 2) storage.bucket.create
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/bucket/create",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'name': 'example'},
)
resp.raise_for_status()
print(resp.json())
# 3) storage.bucket.list
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/bucket/list",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())
# 4) storage.object.presign
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'bucket_id': 'bkt_42', 'key': 'uploads/photo.jpg', 'ttl_seconds': 3600},
)
resp.raise_for_status()
print(resp.json())
# Use data['data']['url'] from the response above to upload raw bytes.
# Do not include the Infrai Authorization header on this PUT request.
with open("upload.bin", "rb") as f:
upload_resp = requests.put(resp.json()["data"]["url"], data=f, headers={"Content-Type": "application/octet-stream"})
upload_resp.raise_for_status()
# 5) storage.object.delete
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.delete(
"https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())
# 6) storage.bucket.get
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/bucket/get/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())
# 7) storage.bucket.delete
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.delete(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())
# Non-empty buckets require force=True; otherwise the API returns STORAGE_DELETE_NOT_FORCED.
resp = requests.delete(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
headers={"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}"},
json={"force": True},
)
resp.raise_for_status()
print(resp.json())
# 8) storage.bucket.usage
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.get(
"https://api.infrai.cc/v1/storage/bucket/usage/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
)
resp.raise_for_status()
print(resp.json())
# 9) storage.bucket.set_lifecycle
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'rules': [{'prefix': 'tmp/', 'expire_days': 1}]},
)
resp.raise_for_status()
print(resp.json())
// 1) Auth: every call is a raw HTTPS request carrying only your project key.
// No SDK to install — just the built-in fetch().
const BASE = "https://api.infrai.cc";
const HEADERS = {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
};
// 2) storage.bucket.create
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/create",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"name": "example"}),
},
);
console.log(await resp.json());
// 3) storage.bucket.list
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/list",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());
// 4) storage.object.presign
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"bucket_id": "bkt_42", "key": "uploads/photo.jpg", "ttl_seconds": 3600}),
},
);
console.log(await resp.json());
// Use data.url from the response above to upload raw bytes.
// Do not include the Infrai Authorization header on this PUT request.
const uploadUrl = "PASTE_RETURNED_DATA_URL_HERE";
const { readFile } = await import("node:fs/promises");
const fileBytes = await readFile("upload.bin");
const uploadResp = await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": "application/octet-stream" },
body: fileBytes,
});
if (!uploadResp.ok) throw new Error(`upload ${uploadResp.status}`);
// 5) storage.object.delete
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());
// 6) storage.bucket.get
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/get/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());
// 7) storage.bucket.delete
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());
// Non-empty buckets require force=true; otherwise the API returns STORAGE_DELETE_NOT_FORCED.
const forceDeleteResp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ force: true }),
},
);
console.log(await forceDeleteResp.json());
// 8) storage.bucket.usage
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/usage/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
console.log(await resp.json());
// 9) storage.bucket.set_lifecycle
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"rules": [{"prefix": "tmp/", "expire_days": 1}]}),
},
);
console.log(await resp.json());
// 1) Auth: every call is a raw HTTPS request carrying only your project key.
// No SDK to install — just the built-in fetch(), typed.
const BASE = "https://api.infrai.cc";
const HEADERS: Record<string, string> = {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
};
// 2) storage.bucket.create
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/create",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"name": "example"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 3) storage.bucket.list
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/list",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 4) storage.object.presign
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/presign/BUCKET/KEY",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"bucket_id": "bkt_42", "key": "uploads/photo.jpg", "ttl_seconds": 3600}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// Use data.url from the response above to upload raw bytes.
// Do not include the Infrai Authorization header on this PUT request.
const uploadUrl = "PASTE_RETURNED_DATA_URL_HERE";
const { readFile } = await import("node:fs/promises");
const fileBytes = await readFile("upload.bin");
const uploadResp = await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": "application/octet-stream" },
body: fileBytes,
});
if (!uploadResp.ok) throw new Error(`upload ${uploadResp.status}`);
// 5) storage.object.delete
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/object/delete/BUCKET/KEY",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 6) storage.bucket.get
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/get/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 7) storage.bucket.delete
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// Non-empty buckets require force=true; otherwise the API returns STORAGE_DELETE_NOT_FORCED.
const forceDeleteResp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/delete/BUCKET",
{
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ force: true }),
},
);
console.log(await forceDeleteResp.json());
// 8) storage.bucket.usage
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/usage/BUCKET",
{
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
},
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 9) storage.bucket.set_lifecycle
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/storage/bucket/set_lifecycle/BUCKET",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"rules": [{"prefix": "tmp/", "expire_days": 1}]}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);