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 the vision size limit that applies to it (not the one in the table below, which is the
upload limit). 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
Video format:
video/mp4 and video/3gpp are accepted only with H.264 video and AAC audio (a single audio track or none). confirm reads the file’s codec and rejects anything else —for example HEVC/H.265— with 400 VIDEO_CODEC_UNSUPPORTED, deleting the file. Convert the video to H.264 before uploading it.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 (a type that can’t be transcribed automatically, or above the size limit that applies to it), 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
Which types get transcribed automatically may expand in stages. The authoritative per-file
signal is
requires_transcription in the /files/confirm response, which saves you from tracking
those stages. The limits behind that signal are vision limits, distinct from the upload limits. .doc, .ppt and .pptx are never transcribed automatically, at any size.Three practical consequences:requires_transcriptionanswers as of the confirm. The gate that rules is the one at send time, so a file confirmed withfalsemay requiretranscriptionagain if availability changes between the confirm and the send. When in doubt, send it.- Sending
transcriptionalongside afile_uuidis never an error, even when the file did not need it: it wins over automatic transcription. Withoutfile_uuidthe whole body is rejected withINVALID_REQUEST(400), and so is atranscriptionthat is empty or whitespace-only. Text that only ends up empty once control characters are stripped does pass the schema, though: the body is accepted with202, and it is that action that fails withINVALID_REQUESTduring background execution. - The size limit depends on the file type: it is not a single number for everything.