Skip to content
API PlatformDevelopers
POST/v1/conversations/{conversation_id}/filesbeta

Send a file in a conversation

Needs
Send WhatsApp messages; manage templates, quick messages and WhatsApp short links (messaging:write)
Plan
Any plan with API access
Limits
60 a minute per key · 20 an hour · 100 a day · 3 per contact a day
Dry run
Yes — a full preview with ?dry_run=true
Undo
Cannot be undone: the customer receives the file.

Uploads a file and sends it to the customer in a conversation, in one request: a PDF, an Office document, a photo, a voice note or other audio, a video or a text file, with an optional caption. The customer receives it and it cannot be undone. Nothing is kept on our side after the answer, so there is no upload step and no upload id: to send the same file again, send it again (or host it and use Send a message in a conversation with media.url).

Send the file as multipart/form-data with a file part (recommended; any HTTP client or curl -F builds it):

curl https://mcp.wa-api.cloud/v1/conversations/77410/files \
  -H "Authorization: Bearer ${env_var_name}" \
  -H "Idempotency-Key: 5f1c2d9e-invoice-1001" \
  -F file=@invoice-1001.pdf \
  -F caption="Your invoice"

or as JSON with the file in content_base64 (with filename), which suits small files: a JSON body is about a third larger than the file.

What can be sent. The file's content decides its type, whatever its name or declared type says; a declared type that does not match the content is refused (reason: content_mismatch). Accepted: PDF, JPEG, PNG, WebP, MP4, 3GP, MP3, OGG, AAC, AMR, DOCX, XLSX, PPTX, plain text and CSV. Executables, scripts, HTML, SVG, XML and other archives are refused (reason: unsupported_type). A file is at most 10 MB (the answer names this server's limit). Images go as images up to 5 MB; a larger image, or any file with as_document: true, goes as a document. Audio has no caption. A video may go as a document on channels that cannot take a video file yet (the answer's note says so).

Like any free-form message it needs an open reply window where the channel has one (on WhatsApp, 24 hours after the customer's last message): otherwise 409 with reason: window_closed (send an approved template instead). The key's staff member must be allowed to reply in the conversation. Files count against the workspace send limits and the workspace's file upload limits (files per hour and per day, and megabytes per day: 429 with reason: upload_cap or upload_bytes_cap). Try it with ?dry_run=true (or a test key): the file is read and every check runs, and nothing is sent or kept.

Try it

Path

The conversation id.

Body

Up to 10.0 MB: PDF, Office, images, audio, video or text. Sent as multipart/form-data; the server decides the type from the content. This portal never stores the file.

The file name the customer sees, e.g. `invoice-1001.pdf` (up to 200 characters; any path is removed and the extension is set from the content). Optional here: the file part's own file name is used by default.

The file's type as you know it, e.g. `application/pdf`. Optional: the content decides, and a type that does not match it is refused. Optional here: the file part's own Content-Type is used by default.

Text shown with the file (up to 1024 characters; not for audio).

`true` sends the file as a document whatever its type (e.g. a photo in full quality, or an image over 5 MB).

Protects against doing it twice if you retry: a retry with the same key gets the first answer back instead of running again.

Test mode (dry run): nothing will change
Turns test mode off for this page only. It switches back when you leave the page.

Code and response

curl -X POST 'https://mcp.wa-api.cloud/v1/conversations/77410/files?dry_run=true' \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F 'file=@invoice-1001.pdf;type=application/pdf' \
  --form-string 'caption=Your order summary'

The code reads your key from $API_KEY.

Parameters

Parameters
FieldTypeWhat it is
conversation_idrequiredstring · pathThe conversation id.pattern ^\d{1,19}$Signed in? Pick one from your data with “My data”.

Body

Body fields
FieldTypeWhat it is
content_base64requiredstringJSON body: the file itself, base64-encoded (standard or URL-safe alphabet). With multipart/form-data send the file part instead.0–140000000 characters
filenamerequiredstringThe file name the customer sees, e.g. invoice-1001.pdf (up to 200 characters; any path is removed and the extension is set from the content).1–200 characters
content_typestringThe file's type as you know it, e.g. application/pdf. Optional: the content decides, and a type that does not match it is refused.0–120 characters
captionstringText shown with the file (up to 1024 characters; not for audio).0–1024 characters
as_documentbooleantrue sends the file as a document whatever its type (e.g. a photo in full quality, or an image over 5 MB).

Headers

Headers
FieldTypeWhat it is
AuthorizationrequiredheaderBearer $API_KEY — your API key.
Api-VersionheaderThe API version to use, e.g. 2026-10-01. Default: the version your key is pinned to.one of: 2026-10-01 · pattern ^\d{4}-\d{2}-\d{2}$
Idempotency-KeyrequiredheaderRequired here. Any unique string (8–128 characters), e.g. your order id plus the step. Kept 24 hours. Not needed with dry_run=true.pattern ^[A-Za-z0-9._:-]+$ · 8–128 characters

Response 202

Accepted for delivery (or the dry-run check): how the file went (`sent_as`: `image`, `video`, `audio` or `document`) and the file as it was sent. Delivery and read receipts show as the message's `status` in the message list.

Response fields
FieldTypeWhat it is
message_idrequiredstring or nullnull for a dry run.
statusrequiredstringqueued, or dry_run.
conversation_idrequiredstring
sent_asrequiredstringimage, video, audio or document.
filerequiredobject
namerequiredstring
content_typerequiredstring
size_bytesrequirednumber
channelrequiredobject
idrequiredstring
typerequiredstring
windowrequiredobject
appliesrequiredbooleanfalse for channels without a window (web chat, custom) and for system messages.
openrequiredboolean or nullnull when the window does not apply.
kindrequiredstring or nullservice (24 h), free_entry (72 h after an ad), standard, tiktok (48 h), web.
closes_atrequiredstring or nullOpen window: when it closes.
closed_atrequiredstring or nullClosed window: when it closed (null = the customer never wrote on this channel, or unknown).
noterequiredstring or null
dry_runbooleantrue when this was a dry run: every check ran and nothing changed.

Errors

Errors are application/problem+json. Branch on code.

StatusCodeWhen
400invalid_input

A field is missing or has the wrong format. errors[] points at each field. No file (/file), a file type that cannot be sent (reason: unsupported_type), content that is not the declared type (reason: content_mismatch), a file over the limit (reason: too_large) or an image over 5 MB not sent as a document (reason: too_large_for_type), a caption on audio, a malformed multipart body (reason: invalid_multipart), a body over the limit (reason: body_too_large: the file limit plus 64 KB for multipart, a third more for JSON), or a body that stopped arriving for 30 seconds (reason: body_timeout). Also returned when the Idempotency-Key header is missing, or was used before with a different body.

401unauthenticated

The Authorization header is missing, the key is unknown, expired or revoked.

403entitlement_required

The workspace's plan does not include API access (api_access).

403forbidden

The key's staff member may not reply here: the conversation is closed, or assigned to someone else (reason: cannot_send_here).

403insufficient_scope

The key does not have the permission this operation needs.

404not_found

No conversation with this id, or your key cannot see it.

409conflict

The customer's reply window is closed (reason: window_closed): send a template instead. Or the channel refused the file (reason: send_failed). Also returned while a request with the same Idempotency-Key is still running.

429rate_limited

The key or workspace went over its rate limit. Wait for Retry-After seconds. A send cap (reason: send_cap) or a file upload cap (reason: upload_cap, files per hour or day; reason: upload_bytes_cap, megabytes per day) was reached, or too many files are being sent at once — on the server, or two at a time by one workspace (reason: busy: retry in a few seconds).

503upstream_unavailable

A service behind the API is briefly unavailable. Safe to retry with backoff.

504timeout

The change did not finish in time. Retry with the same Idempotency-Key: it never runs twice.

Examples

Send a small text file as JSON (base64)

Request body

{
  "content_base64": "T3JkZXIgIzEwMDE6IDIgaXRlbXMsIHRvdGFsICQ0MC4wMAo=",
  "filename": "order-1001.txt",
  "content_type": "text/plain",
  "caption": "Your order summary"
}

Response 202

{
  "message_id": "5501240",
  "status": "queued",
  "conversation_id": "77410",
  "sent_as": "document",
  "file": {
    "name": "order-1001.txt",
    "content_type": "text/plain",
    "size_bytes": 35
  },
  "channel": {
    "id": "301",
    "type": "whatsapp"
  },
  "window": {
    "applies": true,
    "open": true,
    "kind": "service",
    "closes_at": "2026-09-25T09:12:00.000Z",
    "closed_at": null
  },
  "note": null
}

Operation path

The same operation is also at POST /v1/ops/inbox_send_file, with every field in the JSON body.