Files you get back
Capabilities that make a file (audio.speech, image.generate, video.generate) return it as
a link on this API’s own host, with an id and an expiry:
- The link works without an API key, for anyone who has it, until
expiresAt(7 days after the call). Download the file if you need it for longer. GET /v1/files/{id}returns a fresh link.DELETE /v1/files/{id}removes the file at once.- A link can be downloaded about 20 times. After that it answers
429; get the file once and serve it from your own storage if many people will fetch it. - If the file cannot be stored, the call fails with
502 upstream_unavailableand you are not charged. Retry it.
Upload a file
Send the file as the request body, with its media type inContent-Type and its kind in the
query:
- Uploading is free. You need a credit balance above zero.
- An upload is kept for 7 days. You can hold up to 1 GB of uploads at a time; over that the
upload is refused with
402 spend_cap_reacheduntil you delete files or they expire. - The media type must match the file’s own bytes, or the upload is refused with
400.
Upload directly (required above 90 MB)
The request-body endpoint above accepts at most 90 MB. The per-kind limits in the table still apply. Larger files go directly to storage, without passing through the API. The SDK chooses the flow for you (a browserFile is also a Blob):
POST /v1/files/uploadswith API authorization,Content-Type: application/json, and{ "kind": "video", "contentType": "video/mp4", "sizeBytes": 120000000 }. It returns201with{ "fileId": "file_...", "uploadUrl": "...", "headers": { ... }, "expiresAt": "..." }. Size, type, credit and available storage are checked before the link is issued; pending uploads count toward storage quota, and a failed or deleted direct upload keeps counting for one hour after it was started.- Send one
PUTtouploadUrlwith the file as the body and all returned headers. Do not send your API key to this URL. The link expires in 15 minutes and accepts exactly the declared size and type. It only creates the object once, so repeating a successful PUT is refused. In browsers, omit the returnedcontent-lengthheader: fetch sets it from the Blob automatically. Browser uploads require the bucket owner to allow the app’s origin. POST /v1/files/{fileId}/finishwith API authorization. It returns the usual file facts after checking the stored size and file contents. Until then the file cannot be used. If the bytes are not there yet, or storage does not answer, the upload stays pending and you can call finish again. A failed check deletes the object and returns an error explaining how to start again.
Upload a large object in parts
For an object larger than onestorage.object.put takes (25 MB), or of a type the list above does
not accept, use a multipart upload to your own bucket. Each chunk is uploaded as a part file:
raw bytes, sent as application/octet-stream with kind=part.
- A part file can only be passed to
storage.upload.part.put. It has no link, cannot be downloaded, and every other capability refuses it with400 invalid_request. - One part is at most 8 MiB. The parts of one upload may total 1 GiB. Part files count toward your 1 GB of uploads until they are deleted.
- Part files are deleted when the upload completes or is aborted, and after 7 days otherwise.
An upload near 1 GB does not fit in your 1 GB of uploads all at once: delete each part file
(
DELETE /v1/files/{id}) once itsstorage.upload.part.puthas succeeded. - The finished object is assembled in your bucket exactly as you sent it. Its content is not checked.
- Without
kind=part, anapplication/octet-streamupload is refused as before.
Use an uploaded file
Pass thefileId where a capability accepts one, in place of a public link:
Send exactly one of them. The audio capabilities take
audio files; the document capabilities
take document and image files (a scan or a photo of a page). A fileId returned by a capability (a generated audio file, say) can
be passed on the same way.
Errors
See errors for the full list.