file_uuid, which you then pass to a send action.
1
Request an upload URL
{ filename, mime_type }. It returns 201 with
file_uuid, upload_url, upload_token, storage_path, and expires_at.2
Upload the binary
upload_url you received, before it expires
(expires_at).3
Confirm
{ file_uuid }. It returns 200 with file_uuid, mime_type,
size_bytes, requires_transcription, download_url, and expires_at.
From here the file_uuid is sendable.You no longer declare
size_bytes when requesting the URL: the server measures
the real size on confirm. In the confirm response, requires_transcription
signals whether this file_uuid will require a transcription when used in a
send — because the file type isn’t auto-transcribable or it exceeds 20 MB. It’s
a hint so you can prepare it ahead of time.Validate the file size locally before uploading: the per-type limit and the storage quota are enforced at confirm, with the binary already transferred. A business with its storage disabled (quota_bytes = 0) or already over its cap is rejected at request-upload with 413 before the transfer.Size limits
Concurrent pending uploads: a business can have at most 100 unconfirmed uploads at a time. Beyond that,
request-upload returns 429 TOO_MANY_PENDING_UPLOADS with Retry-After — confirm or let your pending uploads expire before requesting more. The normal flow (request → PUT → confirm) never hits it; it only affects integrations that request many request-upload up front without confirming.Send the file
Once confirmed, pass thefile_uuid to a send action — as direct media in
send_message, or as a template header:
header.type ∈ image | video | document carries file_uuid
(document accepts an optional filename) and a transcription that is required
when vision can’t transcribe the file (the requires_transcription above anticipates
it). In send_message media mode, the file_uuid goes at the action level with body
as an optional caption (audio doesn’t accept a caption) and the same transcription rule.
Executable example
The full flow in three calls. Thefile_uuid confirmed in step 3 is the one you
then pass to a send action.
1 · Request an upload URL
upload_url before it expires
With required transcription
If the file isn’t auto-transcribable by vision (an unsupported type such as.docx/.xlsx, or larger than 20 MB), the /confirm response
anticipates it with requires_transcription: true:
200 Response (transcription required)
transcription — as the primary
media in send_message or as template.header.transcription — or the action
fails with TRANSCRIPTION_REQUIRED / TEMPLATE_HEADER_TRANSCRIPTION_MISSING:
Send with transcription