{"id":"storage.object.put","module":"storage","namespace":"storage","action":"object.put","method":"PUT","path":"/v1/storage/object/put/{bucket}/{key}","idempotent":true,"available":true,"vendors":[],"vendors_ready":[],"vendors_pending":[],"key_status":"live","default_vendor":null,"self_hosted":true,"minimum_tier":"standard","supported_message_classes":null,"regions":["western","china"],"dynamic_params":{},"models_tracked":false,"sdk_hint":"Regular parameters + types are stable — read them from the typed SDK signature / API reference for this capability. discovery only carries the runtime-dynamic values above (available, vendors, dynamic_params).","params":{"title":"ObjectPutRequest","description":"Server-side direct write for storage.object.put (PUT /v1/storage/object/put/{bucket}/{key}). The object bytes travel base64-encoded in the JSON data_base64 field (aliases: data / file_base64). Base64 upload is intended for small files and is not recommended above 1 MB; use object.presign or multipart.presign_part for larger files. Persistent storage writes cannot be paid by trial-only credit; if the response is 402 INSUFFICIENT_CREDIT with code_detail=trial_restricted, add paid balance and retry.","type":"object","additionalProperties":false,"required":["data_base64"],"properties":{"data_base64":{"type":"string","description":"REQUIRED. The object bytes, base64-encoded as a bare base64 string or data: URL. Intended for small files; not recommended above 1 MB."},"data":{"type":["string","null"],"description":"Alias for data_base64 (base64-encoded object bytes)."},"file_base64":{"type":["string","null"],"description":"Alias for data_base64 (base64-encoded object bytes)."},"content_type":{"type":["string","null"],"description":"MIME type of the object"},"metadata":{"type":["object","null"],"description":"Arbitrary user metadata key/value pairs."},"cache_control":{"type":["string","null"],"description":"Cache-Control header value"},"storage_class":{"type":["string","null"],"default":"standard","description":"Storage class (e.g. standard, infrequent_access)"},"idempotency_key":{"type":["string","null"],"description":"Optional; SDK auto-derives a content-hash key (bucket_id+key+content) when omitted."}}},"response":{"title":"StorageObject","description":"An object inside a bucket. See docs/phase2/P2_03_New_Modules.md §4.2.","type":"object","required":["bucket_id","key","size_bytes","etag","created_at"],"additionalProperties":false,"properties":{"bucket_id":{"type":"string","pattern":"^bkt_[A-Za-z0-9]{20,}$","description":"Unique identifier for this storage bucket"},"key":{"type":"string","description":"Unique identifier key for this resource"},"size_bytes":{"type":"integer","minimum":0,"description":"Size of the resource in bytes"},"etag":{"type":"string","description":"ETag hash of the object content"},"content_type":{"type":["string","null"],"description":"MIME type of the object"},"metadata":{"type":["object","null"],"description":"Arbitrary key-value metadata attached to this resource"},"created_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp when this resource was created"},"last_modified":{"type":["string","null"],"format":"date-time","description":"ISO 8601 timestamp when the object was last modified"}}},"errors":["ACCOUNT_AUTORECHARGE_LIMIT","ACCOUNT_FROZEN","AUTH_RATE_LIMIT","AUTH_REFRESH_TOO_FREQUENT","IDEMPOTENCY_KEY_CONFLICT","INSUFFICIENT_CREDIT","INTERNAL_ERROR","INVALID_ARGUMENT","KEY_REVOKED","MAINTENANCE","NETWORK_ERROR","RATE_LIMIT_ACCOUNT","RATE_LIMIT_USER","RATE_LIMIT_VENDOR","SCOPE_INSUFFICIENT","STORAGE_ACL_INVALID","STORAGE_BANDWIDTH_EXCEEDED","STORAGE_BUCKET_EXISTS","STORAGE_BUCKET_NAME_TAKEN","STORAGE_BUCKET_NOT_FOUND","STORAGE_CONTENT_BLOCKED","STORAGE_CONTENT_TYPE_BLOCKED","STORAGE_DELETE_NOT_FORCED","STORAGE_INVALID_BUCKET_NAME","STORAGE_INVALID_CORS_RULES","STORAGE_INVALID_DATA","STORAGE_INVALID_LIFECYCLE_RULES","STORAGE_INVALID_MODE","STORAGE_INVALID_OBJECT_KEY","STORAGE_INVALID_REGION","STORAGE_INVALID_TTL","STORAGE_INVALID_VENDOR","STORAGE_MULTIPART_INCONSISTENT","STORAGE_OBJECT_NOT_FOUND","STORAGE_OBJECT_TOO_LARGE","STORAGE_PRESIGN_EXPIRED","UNAUTHORIZED","VENDOR_AUTH_ERROR","VENDOR_DOWN","VENDOR_TIMEOUT","WALLET_EXPIRED"],"examples":{"curl":"curl -X PUT https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY \\\n  -H \"Authorization: Bearer $INFRAI_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"data_base64\": \"sample\"}'","python":"# Zero-install REST call — no SDK required (short-term the API is REST-only).\nimport os, requests\n\nresp = requests.put(\n    \"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['INFRAI_API_KEY']}\",\n    },\n    json={'data_base64': 'sample'},\n)\nresp.raise_for_status()\nprint(resp.json())","javascript":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\nconst resp = await fetch(\n  \"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\",\n  {\n    method: \"PUT\",\n    headers: {\n      \"Authorization\": `Bearer ${process.env.INFRAI_API_KEY}`,\n      \"Content-Type\": \"application/json\",\n    },\n    body: JSON.stringify({\"data_base64\": \"sample\"}),\n  },\n);\nconsole.log(await resp.json());","typescript":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\nconst resp = await fetch(\n  \"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\",\n  {\n    method: \"PUT\",\n    headers: {\n      \"Authorization\": `Bearer ${process.env.INFRAI_API_KEY}`,\n      \"Content-Type\": \"application/json\",\n    },\n    body: JSON.stringify({\"data_base64\": \"sample\"}),\n  },\n);\nif (!resp.ok) throw new Error(`infrai ${resp.status}`);\nconst data: unknown = await resp.json();\nconsole.log(data);","go":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\npackage main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\tbody := []byte(`{\"data_base64\": \"sample\"}`)\n\treq, _ := http.NewRequest(\"PUT\", \"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\", bytes.NewReader(body))\n\treq.Header.Set(\"Authorization\", \"Bearer \"+os.Getenv(\"INFRAI_API_KEY\"))\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n\tfmt.Println(resp.Status)\n}","java":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\nimport java.net.URI;\nimport java.net.http.*;\n\nHttpRequest req = HttpRequest.newBuilder()\n    .uri(URI.create(\"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\"))\n    .header(\"Authorization\", \"Bearer \" + System.getenv(\"INFRAI_API_KEY\"))\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"PUT\", HttpRequest.BodyPublishers.ofString(\"{\\\"data_base64\\\": \\\"sample\\\"}\"))\n    .build();\nHttpResponse<String> resp = HttpClient.newHttpClient()\n    .send(req, HttpResponse.BodyHandlers.ofString());\nSystem.out.println(resp.body());","csharp":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\nusing System;\nusing System.Net.Http;\n\nvar client = new HttpClient();\nvar req = new HttpRequestMessage(new HttpMethod(\"PUT\"), \"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\");\nvar key = Environment.GetEnvironmentVariable(\"INFRAI_API_KEY\");\nreq.Headers.Add(\"Authorization\", \"Bearer \" + key);\nreq.Content = new StringContent(\"{\\\"data_base64\\\": \\\"sample\\\"}\", System.Text.Encoding.UTF8, \"application/json\");\nvar resp = await client.SendAsync(req);\nConsole.WriteLine(await resp.Content.ReadAsStringAsync());","php":"<?php\n// Zero-install REST call — no SDK required (short-term the API is REST-only).\n$ch = curl_init(\"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\");\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, \"PUT\");\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\ncurl_setopt($ch, CURLOPT_HTTPHEADER, [\n    \"Authorization: Bearer \" . getenv(\"INFRAI_API_KEY\"),\n    \"Content-Type: application/json\",\n]);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, \"{\\\"data_base64\\\": \\\"sample\\\"}\");\n$response = curl_exec($ch);\ncurl_close($ch);\necho $response;","ruby":"# Zero-install REST call — no SDK required (short-term the API is REST-only).\nrequire \"net/http\"\nrequire \"uri\"\n\nuri = URI(\"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\")\nhttp = Net::HTTP.new(uri.host, uri.port)\nhttp.use_ssl = true\nreq = Net::HTTP::Put.new(uri)\nreq[\"Authorization\"] = \"Bearer #{ENV['INFRAI_API_KEY']}\"\nreq[\"Content-Type\"] = \"application/json\"\nreq.body = '{\"data_base64\": \"sample\"}'\nres = http.request(req)\nputs res.body","rust":"// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let resp = reqwest::Client::new()\n        .put(\"https://api.infrai.cc/v1/storage/object/put/BUCKET/KEY\")\n        .header(\"Authorization\", format!(\"Bearer {}\", env::var(\"INFRAI_API_KEY\")?))\n        .header(\"Content-Type\", \"application/json\")\n        .body(r#\"{\"data_base64\": \"sample\"}\"#)\n        .send()\n        .await?;\n    println!(\"{}\", resp.text().await?);\n    Ok(())\n}","request":{"data_base64":"sample"}},"billing":{"is_billable":true,"free":false,"billing_class":"floored","unit":"per_call","price_usd":0.0001,"currency":"USD","approximate":false,"new_account_trial_uses":19999,"note":"new accounts get $2 free → ~19999 free calls"}}