Skip to main content

Send a WhatsApp Message

POST https://pilotstatus.com.br/v1/messages/send
This is the only send endpoint. It supports three mutually exclusive top-level modes:
  1. Template sendtemplateId (+ optional variables)
  2. Free-form text sendtext
  3. Direct media sendmedia + mediaType (no templateId, no text)
Exactly one mode must be used per request. There are no separate /messages/text, /messages/media, or /messages/interactive endpoints.

Headers

  • Content-Type: application/json
  • x-api-key: ps_... (or x-api-key-id: <api_key_id>) — a number-scoped key

Destination (exactly one)

destinationNumber
string
Destination phone in E.164 with a leading + (e.g., +5511999999999).
groupId
string
WhatsApp group JID ending in @g.us.
newsletterId
string
WhatsApp channel JID ending in @newsletter.

Mode fields

templateId
string
Template from the dashboard /templates. Mutually exclusive with text and direct-media mode.
variables
object
Key→value map for template variables. Missing required variables produce MISSING_TEMPLATE_VARIABLES.
text
string
Body of a free-form message. Required if templateId is not sent (and not doing a direct media send).
media
string
A public http(s) URL or a base64 data URI (e.g. data:audio/ogg;base64,AAAA...) to an image, video, document, or audio file. Base64 is accepted for all media types on Meta Cloud API and Evolution v2. On Evolution GO numbers, base64 is not accepted — use a public http(s) URL. Overrides any embedded mediaUrl in the template.
mediaType
string
image, video, document, or audio. Set it explicitly when the URL extension is not obvious (e.g. PDFs whose URL does not end in .pdf). When mediaType is audio, the file is delivered as a WhatsApp voice note (PTT) on Meta Cloud API, Evolution v2, and Evolution GO. On Evolution v2 and Evolution GO a “recording audio” presence indicator is shown just before delivery; Meta Cloud API has no outbound presence API, so no indicator is shown for Meta audio sends.

Direct media send

Send media on its own by providing media + mediaType without templateId and without text. In this mode buttons, header, footer, and variables are not allowed; an optional caption is allowed for image, video, and document but not for audio.
Sending with media requires an active paid subscription. Otherwise the API returns 402 with code: SUBSCRIPTION_REQUIRED_FOR_MEDIA.

Scheduling and delivery window

deliverAt
string
ISO 8601 datetime to schedule the send.
deliverUntil
string
ISO 8601 deadline for delivery. If it expires, the message fails (see Log Error Codes).

Other fields

labels
string[]
Tag the destination with Labels (tenant scope). Processed asynchronously. With API key retentionDays = 0, Labels are created but the phone/group linkage may not be persisted (PII).
marketingOptions
object
For MARKETING templates only. aiRewriteEnabled: true enables automatic variation of the final message text to reduce repetitive patterns (anti-spam) while preserving intent. If variation cannot be applied, the original text is sent. MARKETING sends also receive an automatic variable queue delay (default 8–25 s) to space out sending pace.
buttons
array
Up to 3 buttons that override the template’s buttons. Each button has type and displayText plus type-specific fields:
  • { "type": "reply", "displayText": "Yes", "id": "yes" } — quick reply
  • { "type": "url", "displayText": "Site", "url": "https://example.com" } — URL button
  • { "type": "call", "displayText": "Call", "phoneNumber": "+5511999999999" } — call button
  • { "type": "copy", "displayText": "Code", "copyCode": "ABC123" } — copy button
buttons is incompatible with mediaType: "video" or mediaType: "document" (WhatsApp does not support buttons with video/PDF).
header
object
Header for a free-form interactive message. Requires buttons. Types: { "type": "text", "content": "Header title" } (up to 60 chars), or image / video / document with a public URL as content.
Message footer (max 60 characters). Requires buttons.

Free-form restrictions

  • media and mediaType cannot be used with text (free-form).
  • header and footer are only supported when buttons is present (Meta Cloud API limitation).
  • On Meta numbers, free-form messages only work within the WhatsApp 24h conversation window. Outside the window, a META_OUTSIDE_24H_WINDOW error is returned in the message.failed webhook — use an approved template instead.

Examples

curl -X POST "https://pilotstatus.com.br/v1/messages/send" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ps_your_key_here" \
  -d '{
    "templateId": "onboarding-test",
    "destinationNumber": "+5511999999999",
    "variables": { "name": "John", "order_id": "123" }
  }'

Response (202)

{
  "id": "msg_abc",
  "correlationId": "corr_123",
  "status": "QUEUED",
  "createdAt": "2026-02-24T15:00:00.000Z",
  "origin": "My WhatsApp"
}
id
string
Internal message ID. Persist this — it is the value to use with GET /v1/messages/{id} and it matches internalMessageId in webhooks.
correlationId
string
Correlation identifier for the send request.
status
string
Always QUEUED on accept.

Correlation with webhooks

  • The id field in the response is the same as internalMessageId in message.sent, message.delivered, message.read, and message.failed, and matches messageRepliedId in message.reply when the platform ties the reply to your send.
  • The WhatsApp messageId (wamid) is not in the 202 body; it first appears on the message.sent webhook (and repeats on status events for that message).
  • Persist id when you receive 202 and use GET /v1/messages/{id} with the same value.

Common errors

StatusMeaning
400Invalid payload (e.g., phone not in E.164, missing required fields, MISSING_TEMPLATE_VARIABLES)
401Missing/invalid API key header (x-api-key / x-api-key-id)
402Paid subscription required to send media (code: SUBSCRIPTION_REQUIRED_FOR_MEDIA)
403Operation blocked (e.g., free-form not supported by the provider: code: FREE_FORM_NOT_SUPPORTED; or a tenant-scoped key on a number-scoped endpoint)
404Template not found or without an approved version
429Rate limit
Asynchronous delivery failures (e.g. META_OUTSIDE_24H_WINDOW, META_TEMPLATE_NOT_APPROVED, WHATSAPP_NOT_EXIST) surface via the message.failed webhook and in Logs — see Log Error Codes.