Skip to main content

Files API

Generic file storage for everything that needs an attachment — MMS images, WhatsApp media, agent-side documents, message templates, campaign assets. Files live in Cloud Storage; URLs are signed and time-limited. Base path: /api/v1/files Authentication: API key (X-API-Key) or session JWT. Upload limits: 25 MB per file (multipart form data).

Using the SDKs

The Node SDK publishes typed helpers for upload, list, get, and delete. The Python SDK publishes a core-scope client — /files sits outside its wrapped surface, so call it through the request escape hatch or a plain requests call. For Go, Ruby, and PHP the samples below use the plain standard-library HTTP form per the sample-writing policy (Go net/http, Ruby Net::HTTP, PHP curl); the header comments that previously leaked into this page are removed.

Example — upload an image for an MMS

The upload response carries the file ID and a signed URL:
Pass the file ID to POST /api/v1/messages/sms (or serve the signed URL as the attachment) to send an MMS — the end-to-end send is in Attach the file to an MMS below.

List files

List returns files newest-first, cursor-paginated. The data array carries one row per file (each with a fresh 1-hour signed url), and meta.pagination carries cursor plus has_more for the next page:
Each list page looks like:

Get a file

Get returns one file’s metadata plus a fresh signed read URL in a single call. The data envelope carries the file’s id, url, filename, content_type, size, and uploaded_at; the url lives for one hour unless you passed a longer ttl_ms at upload time.
A file ID that does not exist in your tenant namespace responds 404.

Delete a file

Delete removes the file row and the underlying storage object. The response is 204 No Content, so there is no response body to read on success — check the status code.
A file ID that does not exist responds 404; an already-deleted ID does the same. The full per-op request/response shapes are in the file upload endpoint reference.

Presigned download URLs

The signed URL returned on upload (and from GET /api/v1/files/{id}) is short-lived — 1 hour by default. When you need a fresh download link — or one with a different lifetime — call GET /api/v1/files/{id}/presign to mint a new S3-style presigned read URL for an existing object. The response declares when the URL dies with expires_at (an ISO 8601 instant): subtract the current time to get the remaining lifetime. Use the optional ttl_ms query parameter to control how long the URL stays valid:
The response:
A request for a file ID that does not exist in your tenant namespace responds 404; a ttl_ms outside the 1-minute-to-7-day band is clamped, not rejected.

Attach the file to an MMS

Uploading only stores the asset — sending it as an MMS is a second call that passes the returned signed URL as media_url:
Passing media_url turns the SMS into an MMS with the attachment inline — the send is rejected before dispatch if the URL fails the HTTPS fetch or the media-type check, so the upload’s signed read URL (which resolves over Google’s storage domain) is the reliable shape. Full MMS semantics (multi-attachment media_urls, the NANP coverage gate, media policy) live on the MMS channel page.

See also