Send message
Enqueues sending a message from the number linked to the API key. Use exactly one of templateId (template send, with variables) or text (free-form); and exactly one destination: destinationNumber (E.164), groupId (…@g.us) or newsletterId (…@newsletter). Requires a number-scoped key (403 for a tenant key). Real side effect: actually delivers and may cost. NOT_SUPPORTED_FOR_META for groupId/newsletterId on Meta numbers.
Requires a number-scoped key.
curl --request POST \
--url https://pilotstatus.com.br/v1/messages/send \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"templateId": "boas_vindas",
"text": "Olá! Sua entrega chegou.",
"destinationNumber": "5511988887777",
"groupId": "123456789-987654321@g.us",
"newsletterId": "120363000000000000@newsletter",
"variables": {
"nome": "Ana"
},
"media": "https://cdn.acme.com/img.png",
"mediaType": "image",
"mediaFilename": "Nota Fiscal 123.pdf",
"caption": "Here is your receipt",
"buttons": [
{
"type": "reply",
"displayText": "Confirm",
"id": "confirm"
},
{
"type": "url",
"displayText": "View details",
"url": "https://example.com/order/123"
}
],
"list": {
"buttonText": "See areas",
"sections": [
{
"title": "Support",
"rows": [
{
"id": "clients",
"title": "Clients",
"description": "Look up and register clients"
}
]
}
]
},
"carousel": {
"cardTemplate": {
"hasBody": true,
"buttons": [
{
"type": "QUICK_REPLY"
}
]
},
"cards": [
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/a.png"
},
"body": "Sneakers — 30% off",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-1"
}
]
},
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/b.png"
},
"body": "Backpack — free shipping",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-2"
}
]
}
]
},
"header": {
"type": "text",
"content": "Header title"
},
"footer": "Reply STOP to unsubscribe",
"deliverAt": "2026-06-21T09:00:00Z",
"deliverUntil": "2026-06-21T18:00:00Z",
"labels": [
"pedido",
"vip"
]
}
'import requests
url = "https://pilotstatus.com.br/v1/messages/send"
payload = {
"templateId": "boas_vindas",
"text": "Olá! Sua entrega chegou.",
"destinationNumber": "5511988887777",
"groupId": "123456789-987654321@g.us",
"newsletterId": "120363000000000000@newsletter",
"variables": { "nome": "Ana" },
"media": "https://cdn.acme.com/img.png",
"mediaType": "image",
"mediaFilename": "Nota Fiscal 123.pdf",
"caption": "Here is your receipt",
"buttons": [
{
"type": "reply",
"displayText": "Confirm",
"id": "confirm"
},
{
"type": "url",
"displayText": "View details",
"url": "https://example.com/order/123"
}
],
"list": {
"buttonText": "See areas",
"sections": [
{
"title": "Support",
"rows": [
{
"id": "clients",
"title": "Clients",
"description": "Look up and register clients"
}
]
}
]
},
"carousel": {
"cardTemplate": {
"hasBody": True,
"buttons": [{ "type": "QUICK_REPLY" }]
},
"cards": [
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/a.png"
},
"body": "Sneakers — 30% off",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-1"
}
]
},
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/b.png"
},
"body": "Backpack — free shipping",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-2"
}
]
}
]
},
"header": {
"type": "text",
"content": "Header title"
},
"footer": "Reply STOP to unsubscribe",
"deliverAt": "2026-06-21T09:00:00Z",
"deliverUntil": "2026-06-21T18:00:00Z",
"labels": ["pedido", "vip"]
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
templateId: 'boas_vindas',
text: 'Olá! Sua entrega chegou.',
destinationNumber: '5511988887777',
groupId: '123456789-987654321@g.us',
newsletterId: '120363000000000000@newsletter',
variables: {nome: 'Ana'},
media: 'https://cdn.acme.com/img.png',
mediaType: 'image',
mediaFilename: 'Nota Fiscal 123.pdf',
caption: 'Here is your receipt',
buttons: [
{type: 'reply', displayText: 'Confirm', id: 'confirm'},
{type: 'url', displayText: 'View details', url: 'https://example.com/order/123'}
],
list: {
buttonText: 'See areas',
sections: [
{
title: 'Support',
rows: [{id: 'clients', title: 'Clients', description: 'Look up and register clients'}]
}
]
},
carousel: {
cardTemplate: {hasBody: true, buttons: [{type: 'QUICK_REPLY'}]},
cards: [
{
media: {format: 'IMAGE', url: 'https://media.example.com/a.png'},
body: JSON.stringify('Sneakers — 30% off'),
buttons: [{type: 'QUICK_REPLY', text: 'I want it', payload: 'SKU-1'}]
},
{
media: {format: 'IMAGE', url: 'https://media.example.com/b.png'},
body: JSON.stringify('Backpack — free shipping'),
buttons: [{type: 'QUICK_REPLY', text: 'I want it', payload: 'SKU-2'}]
}
]
},
header: {type: 'text', content: 'Header title'},
footer: 'Reply STOP to unsubscribe',
deliverAt: '2026-06-21T09:00:00Z',
deliverUntil: '2026-06-21T18:00:00Z',
labels: ['pedido', 'vip']
})
};
fetch('https://pilotstatus.com.br/v1/messages/send', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://pilotstatus.com.br/v1/messages/send",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'templateId' => 'boas_vindas',
'text' => 'Olá! Sua entrega chegou.',
'destinationNumber' => '5511988887777',
'groupId' => '123456789-987654321@g.us',
'newsletterId' => '120363000000000000@newsletter',
'variables' => [
'nome' => 'Ana'
],
'media' => 'https://cdn.acme.com/img.png',
'mediaType' => 'image',
'mediaFilename' => 'Nota Fiscal 123.pdf',
'caption' => 'Here is your receipt',
'buttons' => [
[
'type' => 'reply',
'displayText' => 'Confirm',
'id' => 'confirm'
],
[
'type' => 'url',
'displayText' => 'View details',
'url' => 'https://example.com/order/123'
]
],
'list' => [
'buttonText' => 'See areas',
'sections' => [
[
'title' => 'Support',
'rows' => [
[
'id' => 'clients',
'title' => 'Clients',
'description' => 'Look up and register clients'
]
]
]
]
],
'carousel' => [
'cardTemplate' => [
'hasBody' => true,
'buttons' => [
[
'type' => 'QUICK_REPLY'
]
]
],
'cards' => [
[
'media' => [
'format' => 'IMAGE',
'url' => 'https://media.example.com/a.png'
],
'body' => 'Sneakers — 30% off',
'buttons' => [
[
'type' => 'QUICK_REPLY',
'text' => 'I want it',
'payload' => 'SKU-1'
]
]
],
[
'media' => [
'format' => 'IMAGE',
'url' => 'https://media.example.com/b.png'
],
'body' => 'Backpack — free shipping',
'buttons' => [
[
'type' => 'QUICK_REPLY',
'text' => 'I want it',
'payload' => 'SKU-2'
]
]
]
]
],
'header' => [
'type' => 'text',
'content' => 'Header title'
],
'footer' => 'Reply STOP to unsubscribe',
'deliverAt' => '2026-06-21T09:00:00Z',
'deliverUntil' => '2026-06-21T18:00:00Z',
'labels' => [
'pedido',
'vip'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://pilotstatus.com.br/v1/messages/send"
payload := strings.NewReader("{\n \"templateId\": \"boas_vindas\",\n \"text\": \"Olá! Sua entrega chegou.\",\n \"destinationNumber\": \"5511988887777\",\n \"groupId\": \"123456789-987654321@g.us\",\n \"newsletterId\": \"120363000000000000@newsletter\",\n \"variables\": {\n \"nome\": \"Ana\"\n },\n \"media\": \"https://cdn.acme.com/img.png\",\n \"mediaType\": \"image\",\n \"mediaFilename\": \"Nota Fiscal 123.pdf\",\n \"caption\": \"Here is your receipt\",\n \"buttons\": [\n {\n \"type\": \"reply\",\n \"displayText\": \"Confirm\",\n \"id\": \"confirm\"\n },\n {\n \"type\": \"url\",\n \"displayText\": \"View details\",\n \"url\": \"https://example.com/order/123\"\n }\n ],\n \"list\": {\n \"buttonText\": \"See areas\",\n \"sections\": [\n {\n \"title\": \"Support\",\n \"rows\": [\n {\n \"id\": \"clients\",\n \"title\": \"Clients\",\n \"description\": \"Look up and register clients\"\n }\n ]\n }\n ]\n },\n \"carousel\": {\n \"cardTemplate\": {\n \"hasBody\": true,\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\"\n }\n ]\n },\n \"cards\": [\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/a.png\"\n },\n \"body\": \"Sneakers — 30% off\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-1\"\n }\n ]\n },\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/b.png\"\n },\n \"body\": \"Backpack — free shipping\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-2\"\n }\n ]\n }\n ]\n },\n \"header\": {\n \"type\": \"text\",\n \"content\": \"Header title\"\n },\n \"footer\": \"Reply STOP to unsubscribe\",\n \"deliverAt\": \"2026-06-21T09:00:00Z\",\n \"deliverUntil\": \"2026-06-21T18:00:00Z\",\n \"labels\": [\n \"pedido\",\n \"vip\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://pilotstatus.com.br/v1/messages/send")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"templateId\": \"boas_vindas\",\n \"text\": \"Olá! Sua entrega chegou.\",\n \"destinationNumber\": \"5511988887777\",\n \"groupId\": \"123456789-987654321@g.us\",\n \"newsletterId\": \"120363000000000000@newsletter\",\n \"variables\": {\n \"nome\": \"Ana\"\n },\n \"media\": \"https://cdn.acme.com/img.png\",\n \"mediaType\": \"image\",\n \"mediaFilename\": \"Nota Fiscal 123.pdf\",\n \"caption\": \"Here is your receipt\",\n \"buttons\": [\n {\n \"type\": \"reply\",\n \"displayText\": \"Confirm\",\n \"id\": \"confirm\"\n },\n {\n \"type\": \"url\",\n \"displayText\": \"View details\",\n \"url\": \"https://example.com/order/123\"\n }\n ],\n \"list\": {\n \"buttonText\": \"See areas\",\n \"sections\": [\n {\n \"title\": \"Support\",\n \"rows\": [\n {\n \"id\": \"clients\",\n \"title\": \"Clients\",\n \"description\": \"Look up and register clients\"\n }\n ]\n }\n ]\n },\n \"carousel\": {\n \"cardTemplate\": {\n \"hasBody\": true,\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\"\n }\n ]\n },\n \"cards\": [\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/a.png\"\n },\n \"body\": \"Sneakers — 30% off\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-1\"\n }\n ]\n },\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/b.png\"\n },\n \"body\": \"Backpack — free shipping\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-2\"\n }\n ]\n }\n ]\n },\n \"header\": {\n \"type\": \"text\",\n \"content\": \"Header title\"\n },\n \"footer\": \"Reply STOP to unsubscribe\",\n \"deliverAt\": \"2026-06-21T09:00:00Z\",\n \"deliverUntil\": \"2026-06-21T18:00:00Z\",\n \"labels\": [\n \"pedido\",\n \"vip\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pilotstatus.com.br/v1/messages/send")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"templateId\": \"boas_vindas\",\n \"text\": \"Olá! Sua entrega chegou.\",\n \"destinationNumber\": \"5511988887777\",\n \"groupId\": \"123456789-987654321@g.us\",\n \"newsletterId\": \"120363000000000000@newsletter\",\n \"variables\": {\n \"nome\": \"Ana\"\n },\n \"media\": \"https://cdn.acme.com/img.png\",\n \"mediaType\": \"image\",\n \"mediaFilename\": \"Nota Fiscal 123.pdf\",\n \"caption\": \"Here is your receipt\",\n \"buttons\": [\n {\n \"type\": \"reply\",\n \"displayText\": \"Confirm\",\n \"id\": \"confirm\"\n },\n {\n \"type\": \"url\",\n \"displayText\": \"View details\",\n \"url\": \"https://example.com/order/123\"\n }\n ],\n \"list\": {\n \"buttonText\": \"See areas\",\n \"sections\": [\n {\n \"title\": \"Support\",\n \"rows\": [\n {\n \"id\": \"clients\",\n \"title\": \"Clients\",\n \"description\": \"Look up and register clients\"\n }\n ]\n }\n ]\n },\n \"carousel\": {\n \"cardTemplate\": {\n \"hasBody\": true,\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\"\n }\n ]\n },\n \"cards\": [\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/a.png\"\n },\n \"body\": \"Sneakers — 30% off\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-1\"\n }\n ]\n },\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/b.png\"\n },\n \"body\": \"Backpack — free shipping\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-2\"\n }\n ]\n }\n ]\n },\n \"header\": {\n \"type\": \"text\",\n \"content\": \"Header title\"\n },\n \"footer\": \"Reply STOP to unsubscribe\",\n \"deliverAt\": \"2026-06-21T09:00:00Z\",\n \"deliverUntil\": \"2026-06-21T18:00:00Z\",\n \"labels\": [\n \"pedido\",\n \"vip\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "msg_01HZX...",
"correlationId": "corr_01HZX...",
"status": "QUEUED",
"createdAt": "2026-06-20T10:00:00.000Z",
"origin": "Suporte",
"sourceNumber": "5511999999999"
}{
"error": "Validation error"
}{
"error": "Unauthorized"
}{
"error": "Tenant-scoped keys cannot call number endpoints",
"code": "TENANT_SCOPE_NOT_ALLOWED"
}{
"error": "Template not found"
}{
"error": "Billing suspended",
"code": "BILLING_SUSPENDED"
}{
"error": "Too many requests"
}Authorizations
Your ps_ API key
Body
Template id or name (mutually exclusive with text).
"boas_vindas"
Free-form text (mutually exclusive with templateId).
"Olá! Sua entrega chegou."
Destination (exactly one). Accepts an E.164 phone OR a BSUID — the contact's durable userId (e.g. BR.13491208655302741918), returned by GET /api/v1/conversations. Use the BSUID to reply to contacts using a WhatsApp username (no phone). One-tap/zero-tap/copy-code authentication templates require a phone number.
"5511988887777"
Group JID. NOT_SUPPORTED_FOR_META.
"123456789-987654321@g.us"
Channel/newsletter JID. NOT_SUPPORTED_FOR_META.
"120363000000000000@newsletter"
Template variables (default {}). For a template created in Meta's console whose dynamic URL button has a numbered placeholder (e.g. https://ctlnk.io/{{1}}, not the body's {{1}}), pass that button's URL suffix as button_<N>, where N is the button's position among all of the template's buttons, starting at 1. On an official (Meta) number, the same key also carries the code of a copy-code button whose value has no {{variable}} (the code set at creation is only Meta's sample), e.g. button_2 for buttons [QUICK_REPLY, COPY_CODE]; a send without it is refused with 400 MISSING_TEMPLATE_VARIABLES.
Show child attributes
Show child attributes
{ "nome": "Ana" }
Public http(s) URL OR base64 data URI (e.g. data:audio/ogg;base64,AAAA…). Base64 is accepted on Meta Cloud API and on unofficial (Pilot Status web) numbers; on unofficial numbers Pilot Status uploads the decoded file to its own storage and sends the provider a URL, and if that upload fails the message fails with MEDIA_REHOST_FAILED. For stickers on unofficial numbers, use a public http(s) URL. Used in template mode or in direct-media mode (media + mediaType, without templateId and without text). Base64 is capped by decoded size: 50 MiB (52428800 bytes) when mediaType is document, 16 MiB (16777216 bytes) for every other type and when mediaType is omitted; above it the request fails with 400 Validation error (details.fieldErrors.media). Send larger files as a public http(s) URL. A URL (or a redirect it answers with) that points to an internal or private network address is never downloaded: the message fails after the 202 with MEDIA_DOWNLOAD_FAILED, on every number type.
"https://cdn.acme.com/img.png"
Media type. In direct-media mode (no templateId/text) send media + mediaType: optional caption for image/video/document (not for audio/voice); buttons/header/footer/variables not allowed. "voice" delivers a WhatsApp voice note (PTT) on every number. "audio" delivers an audio file (not a voice note) on official (Meta Cloud API) numbers and a voice note on unofficial numbers (Evolution v2 and GO) — send "voice" for a voice note. Before sending, audio is converted to AAC in MP4 (audio/mp4) on official numbers and to Ogg/Opus on unofficial numbers. On Evolution v2 and GO a "recording audio" presence indicator is shown before an audio or voice send; on Meta Cloud API a "typing" indicator is shown instead, when the conversation has a recent message from the contact. "sticker" sends a WhatsApp sticker: direct-media mode only (never with templateId), no caption, and the file must be image/webp at exactly 512x512 pixels — static up to 100 KB, animated up to 500 KB. Any other dimension is rejected by WhatsApp (Meta error 131053, META_MEDIA_UPLOAD_ERROR) after this API has already answered 202. On Meta Cloud API the sticker is uploaded and sent as type "sticker"; on Evolution v2 and GO it goes through each server's dedicated sticker route.
image, video, document, audio, voice, sticker "image"
Filename the document arrives with in WhatsApp. Direct document sends only (requires mediaType: document). When omitted the name falls back to the URL basename. Path separators are stripped. Rejected with 400 when sent without media, on a template send, or with any mediaType other than document.
"Nota Fiscal 123.pdf"
Caption that travels with a direct media send. Allowed for image, video and document; rejected with 400 for audio and sticker. Not supported for voice either: it is not rejected, but it is dropped on unofficial numbers and its rendering on official numbers is not guaranteed — don't send one. Max 1024 characters. Not used in template mode — there the text comes from the template body.
"Here is your receipt"
Up to 3 interactive buttons. Each item has type + displayText plus one type-specific field.
reply— quick-reply button; works on free-form and template sends. Setid(your own value; not echoed back on tap — match replies by label +quotedMessageId).url— opens a link; seturl(https). On free-form sends at most one URL button per message, and it may be combined withreplybuttons.call— dials a number; setphoneNumber(E.164, e.g.+5511999999999). Template sends only — rejected with 400 (BUTTON_PHONE_NUMBER_TEMPLATE_ONLY) on free-form.copy— copies a code; setcopyCode. Template sends only — rejected with 400 (BUTTON_COPY_CODE_TEMPLATE_ONLY) on free-form.
On a template send, buttons override the template's own buttons — except on Meta (official) numbers, where the approved template's buttons are fixed: buttons does not replace them and does not fill a button variable. Fill a dynamic URL button through variables (its named key, or button_<N> for a numbered placeholder in a template created in Meta's console); a copy-code button's code also goes in variables as button_<N>, not in copyCode.
Show child attributes
Show child attributes
[
{
"type": "reply",
"displayText": "Confirm",
"id": "confirm"
},
{
"type": "url",
"displayText": "View details",
"url": "https://example.com/order/123"
}
]
Interactive single-select list — a button that opens a menu of up to 10 rows. Requires text (the message body above the button); mutually exclusive with templateId, buttons and direct media. Works on both number types with the same request: Meta Cloud API numbers send the official interactive list, unofficial (Pilot Status web) numbers send the native list. The recipient's selection arrives as a normal inbound message/webhook.
Show child attributes
Show child attributes
{
"buttonText": "See areas",
"sections": [
{
"title": "Support",
"rows": [
{
"id": "clients",
"title": "Clients",
"description": "Look up and register clients"
}
]
}
]
}
Session carousel — a horizontal, swipeable row of 2–10 cards attached to a free-form send. Requires text (the message body shown above the cards); mutually exclusive with templateId, list, buttons and direct media, and a header is not allowed (each card carries its own media). Works on both number types: Meta Cloud API numbers send it only inside the 24-hour service window (outside it, use an approved template carousel); unofficial (Pilot Status web) numbers send it ad-hoc. Session-carousel buttons are QUICK_REPLY only on Meta (a URL button there requires an approved template carousel); on unofficial numbers a URL button also works ad-hoc. A card's quick-reply tap arrives as a normal inbound webhook.
Show child attributes
Show child attributes
{
"cardTemplate": {
"hasBody": true,
"buttons": [{ "type": "QUICK_REPLY" }]
},
"cards": [
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/a.png"
},
"body": "Sneakers — 30% off",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-1"
}
]
},
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/b.png"
},
"body": "Backpack — free shipping",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-2"
}
]
}
]
}
Dynamic Flow — a button that opens a WhatsApp Flow chosen AT SEND TIME, instead of being frozen into an approved template. Meta Cloud API numbers only (unofficial providers have no Flows), requires text, and requires the 24-hour service window to be open: outside it Meta answers 200 with a wamid and silently discards the message, so Pilot Status refuses the send with FLOW_WINDOW_CLOSED rather than letting it vanish. Mutually exclusive with templateId, list, carousel, buttons, header and direct media. The flow_token is minted per message by Pilot Status and cannot be supplied.
Show child attributes
Show child attributes
Header for a free-form interactive message. Requires buttons. type is text (up to 60 chars in content) or image / video / document (public URL in content).
Show child attributes
Show child attributes
{ "type": "text", "content": "Header title" }
Message footer (max 60 characters). Requires buttons.
"Reply STOP to unsubscribe"
Schedule delivery for a future time.
"2026-06-21T09:00:00Z"
Maximum delivery window.
"2026-06-21T18:00:00Z"
Labels to apply to the destination conversation.
["pedido", "vip"]
Response
Send template
Was this page helpful?
curl --request POST \
--url https://pilotstatus.com.br/v1/messages/send \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"templateId": "boas_vindas",
"text": "Olá! Sua entrega chegou.",
"destinationNumber": "5511988887777",
"groupId": "123456789-987654321@g.us",
"newsletterId": "120363000000000000@newsletter",
"variables": {
"nome": "Ana"
},
"media": "https://cdn.acme.com/img.png",
"mediaType": "image",
"mediaFilename": "Nota Fiscal 123.pdf",
"caption": "Here is your receipt",
"buttons": [
{
"type": "reply",
"displayText": "Confirm",
"id": "confirm"
},
{
"type": "url",
"displayText": "View details",
"url": "https://example.com/order/123"
}
],
"list": {
"buttonText": "See areas",
"sections": [
{
"title": "Support",
"rows": [
{
"id": "clients",
"title": "Clients",
"description": "Look up and register clients"
}
]
}
]
},
"carousel": {
"cardTemplate": {
"hasBody": true,
"buttons": [
{
"type": "QUICK_REPLY"
}
]
},
"cards": [
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/a.png"
},
"body": "Sneakers — 30% off",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-1"
}
]
},
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/b.png"
},
"body": "Backpack — free shipping",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-2"
}
]
}
]
},
"header": {
"type": "text",
"content": "Header title"
},
"footer": "Reply STOP to unsubscribe",
"deliverAt": "2026-06-21T09:00:00Z",
"deliverUntil": "2026-06-21T18:00:00Z",
"labels": [
"pedido",
"vip"
]
}
'import requests
url = "https://pilotstatus.com.br/v1/messages/send"
payload = {
"templateId": "boas_vindas",
"text": "Olá! Sua entrega chegou.",
"destinationNumber": "5511988887777",
"groupId": "123456789-987654321@g.us",
"newsletterId": "120363000000000000@newsletter",
"variables": { "nome": "Ana" },
"media": "https://cdn.acme.com/img.png",
"mediaType": "image",
"mediaFilename": "Nota Fiscal 123.pdf",
"caption": "Here is your receipt",
"buttons": [
{
"type": "reply",
"displayText": "Confirm",
"id": "confirm"
},
{
"type": "url",
"displayText": "View details",
"url": "https://example.com/order/123"
}
],
"list": {
"buttonText": "See areas",
"sections": [
{
"title": "Support",
"rows": [
{
"id": "clients",
"title": "Clients",
"description": "Look up and register clients"
}
]
}
]
},
"carousel": {
"cardTemplate": {
"hasBody": True,
"buttons": [{ "type": "QUICK_REPLY" }]
},
"cards": [
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/a.png"
},
"body": "Sneakers — 30% off",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-1"
}
]
},
{
"media": {
"format": "IMAGE",
"url": "https://media.example.com/b.png"
},
"body": "Backpack — free shipping",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "I want it",
"payload": "SKU-2"
}
]
}
]
},
"header": {
"type": "text",
"content": "Header title"
},
"footer": "Reply STOP to unsubscribe",
"deliverAt": "2026-06-21T09:00:00Z",
"deliverUntil": "2026-06-21T18:00:00Z",
"labels": ["pedido", "vip"]
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
templateId: 'boas_vindas',
text: 'Olá! Sua entrega chegou.',
destinationNumber: '5511988887777',
groupId: '123456789-987654321@g.us',
newsletterId: '120363000000000000@newsletter',
variables: {nome: 'Ana'},
media: 'https://cdn.acme.com/img.png',
mediaType: 'image',
mediaFilename: 'Nota Fiscal 123.pdf',
caption: 'Here is your receipt',
buttons: [
{type: 'reply', displayText: 'Confirm', id: 'confirm'},
{type: 'url', displayText: 'View details', url: 'https://example.com/order/123'}
],
list: {
buttonText: 'See areas',
sections: [
{
title: 'Support',
rows: [{id: 'clients', title: 'Clients', description: 'Look up and register clients'}]
}
]
},
carousel: {
cardTemplate: {hasBody: true, buttons: [{type: 'QUICK_REPLY'}]},
cards: [
{
media: {format: 'IMAGE', url: 'https://media.example.com/a.png'},
body: JSON.stringify('Sneakers — 30% off'),
buttons: [{type: 'QUICK_REPLY', text: 'I want it', payload: 'SKU-1'}]
},
{
media: {format: 'IMAGE', url: 'https://media.example.com/b.png'},
body: JSON.stringify('Backpack — free shipping'),
buttons: [{type: 'QUICK_REPLY', text: 'I want it', payload: 'SKU-2'}]
}
]
},
header: {type: 'text', content: 'Header title'},
footer: 'Reply STOP to unsubscribe',
deliverAt: '2026-06-21T09:00:00Z',
deliverUntil: '2026-06-21T18:00:00Z',
labels: ['pedido', 'vip']
})
};
fetch('https://pilotstatus.com.br/v1/messages/send', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://pilotstatus.com.br/v1/messages/send",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'templateId' => 'boas_vindas',
'text' => 'Olá! Sua entrega chegou.',
'destinationNumber' => '5511988887777',
'groupId' => '123456789-987654321@g.us',
'newsletterId' => '120363000000000000@newsletter',
'variables' => [
'nome' => 'Ana'
],
'media' => 'https://cdn.acme.com/img.png',
'mediaType' => 'image',
'mediaFilename' => 'Nota Fiscal 123.pdf',
'caption' => 'Here is your receipt',
'buttons' => [
[
'type' => 'reply',
'displayText' => 'Confirm',
'id' => 'confirm'
],
[
'type' => 'url',
'displayText' => 'View details',
'url' => 'https://example.com/order/123'
]
],
'list' => [
'buttonText' => 'See areas',
'sections' => [
[
'title' => 'Support',
'rows' => [
[
'id' => 'clients',
'title' => 'Clients',
'description' => 'Look up and register clients'
]
]
]
]
],
'carousel' => [
'cardTemplate' => [
'hasBody' => true,
'buttons' => [
[
'type' => 'QUICK_REPLY'
]
]
],
'cards' => [
[
'media' => [
'format' => 'IMAGE',
'url' => 'https://media.example.com/a.png'
],
'body' => 'Sneakers — 30% off',
'buttons' => [
[
'type' => 'QUICK_REPLY',
'text' => 'I want it',
'payload' => 'SKU-1'
]
]
],
[
'media' => [
'format' => 'IMAGE',
'url' => 'https://media.example.com/b.png'
],
'body' => 'Backpack — free shipping',
'buttons' => [
[
'type' => 'QUICK_REPLY',
'text' => 'I want it',
'payload' => 'SKU-2'
]
]
]
]
],
'header' => [
'type' => 'text',
'content' => 'Header title'
],
'footer' => 'Reply STOP to unsubscribe',
'deliverAt' => '2026-06-21T09:00:00Z',
'deliverUntil' => '2026-06-21T18:00:00Z',
'labels' => [
'pedido',
'vip'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://pilotstatus.com.br/v1/messages/send"
payload := strings.NewReader("{\n \"templateId\": \"boas_vindas\",\n \"text\": \"Olá! Sua entrega chegou.\",\n \"destinationNumber\": \"5511988887777\",\n \"groupId\": \"123456789-987654321@g.us\",\n \"newsletterId\": \"120363000000000000@newsletter\",\n \"variables\": {\n \"nome\": \"Ana\"\n },\n \"media\": \"https://cdn.acme.com/img.png\",\n \"mediaType\": \"image\",\n \"mediaFilename\": \"Nota Fiscal 123.pdf\",\n \"caption\": \"Here is your receipt\",\n \"buttons\": [\n {\n \"type\": \"reply\",\n \"displayText\": \"Confirm\",\n \"id\": \"confirm\"\n },\n {\n \"type\": \"url\",\n \"displayText\": \"View details\",\n \"url\": \"https://example.com/order/123\"\n }\n ],\n \"list\": {\n \"buttonText\": \"See areas\",\n \"sections\": [\n {\n \"title\": \"Support\",\n \"rows\": [\n {\n \"id\": \"clients\",\n \"title\": \"Clients\",\n \"description\": \"Look up and register clients\"\n }\n ]\n }\n ]\n },\n \"carousel\": {\n \"cardTemplate\": {\n \"hasBody\": true,\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\"\n }\n ]\n },\n \"cards\": [\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/a.png\"\n },\n \"body\": \"Sneakers — 30% off\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-1\"\n }\n ]\n },\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/b.png\"\n },\n \"body\": \"Backpack — free shipping\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-2\"\n }\n ]\n }\n ]\n },\n \"header\": {\n \"type\": \"text\",\n \"content\": \"Header title\"\n },\n \"footer\": \"Reply STOP to unsubscribe\",\n \"deliverAt\": \"2026-06-21T09:00:00Z\",\n \"deliverUntil\": \"2026-06-21T18:00:00Z\",\n \"labels\": [\n \"pedido\",\n \"vip\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://pilotstatus.com.br/v1/messages/send")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"templateId\": \"boas_vindas\",\n \"text\": \"Olá! Sua entrega chegou.\",\n \"destinationNumber\": \"5511988887777\",\n \"groupId\": \"123456789-987654321@g.us\",\n \"newsletterId\": \"120363000000000000@newsletter\",\n \"variables\": {\n \"nome\": \"Ana\"\n },\n \"media\": \"https://cdn.acme.com/img.png\",\n \"mediaType\": \"image\",\n \"mediaFilename\": \"Nota Fiscal 123.pdf\",\n \"caption\": \"Here is your receipt\",\n \"buttons\": [\n {\n \"type\": \"reply\",\n \"displayText\": \"Confirm\",\n \"id\": \"confirm\"\n },\n {\n \"type\": \"url\",\n \"displayText\": \"View details\",\n \"url\": \"https://example.com/order/123\"\n }\n ],\n \"list\": {\n \"buttonText\": \"See areas\",\n \"sections\": [\n {\n \"title\": \"Support\",\n \"rows\": [\n {\n \"id\": \"clients\",\n \"title\": \"Clients\",\n \"description\": \"Look up and register clients\"\n }\n ]\n }\n ]\n },\n \"carousel\": {\n \"cardTemplate\": {\n \"hasBody\": true,\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\"\n }\n ]\n },\n \"cards\": [\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/a.png\"\n },\n \"body\": \"Sneakers — 30% off\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-1\"\n }\n ]\n },\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/b.png\"\n },\n \"body\": \"Backpack — free shipping\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-2\"\n }\n ]\n }\n ]\n },\n \"header\": {\n \"type\": \"text\",\n \"content\": \"Header title\"\n },\n \"footer\": \"Reply STOP to unsubscribe\",\n \"deliverAt\": \"2026-06-21T09:00:00Z\",\n \"deliverUntil\": \"2026-06-21T18:00:00Z\",\n \"labels\": [\n \"pedido\",\n \"vip\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pilotstatus.com.br/v1/messages/send")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"templateId\": \"boas_vindas\",\n \"text\": \"Olá! Sua entrega chegou.\",\n \"destinationNumber\": \"5511988887777\",\n \"groupId\": \"123456789-987654321@g.us\",\n \"newsletterId\": \"120363000000000000@newsletter\",\n \"variables\": {\n \"nome\": \"Ana\"\n },\n \"media\": \"https://cdn.acme.com/img.png\",\n \"mediaType\": \"image\",\n \"mediaFilename\": \"Nota Fiscal 123.pdf\",\n \"caption\": \"Here is your receipt\",\n \"buttons\": [\n {\n \"type\": \"reply\",\n \"displayText\": \"Confirm\",\n \"id\": \"confirm\"\n },\n {\n \"type\": \"url\",\n \"displayText\": \"View details\",\n \"url\": \"https://example.com/order/123\"\n }\n ],\n \"list\": {\n \"buttonText\": \"See areas\",\n \"sections\": [\n {\n \"title\": \"Support\",\n \"rows\": [\n {\n \"id\": \"clients\",\n \"title\": \"Clients\",\n \"description\": \"Look up and register clients\"\n }\n ]\n }\n ]\n },\n \"carousel\": {\n \"cardTemplate\": {\n \"hasBody\": true,\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\"\n }\n ]\n },\n \"cards\": [\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/a.png\"\n },\n \"body\": \"Sneakers — 30% off\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-1\"\n }\n ]\n },\n {\n \"media\": {\n \"format\": \"IMAGE\",\n \"url\": \"https://media.example.com/b.png\"\n },\n \"body\": \"Backpack — free shipping\",\n \"buttons\": [\n {\n \"type\": \"QUICK_REPLY\",\n \"text\": \"I want it\",\n \"payload\": \"SKU-2\"\n }\n ]\n }\n ]\n },\n \"header\": {\n \"type\": \"text\",\n \"content\": \"Header title\"\n },\n \"footer\": \"Reply STOP to unsubscribe\",\n \"deliverAt\": \"2026-06-21T09:00:00Z\",\n \"deliverUntil\": \"2026-06-21T18:00:00Z\",\n \"labels\": [\n \"pedido\",\n \"vip\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "msg_01HZX...",
"correlationId": "corr_01HZX...",
"status": "QUEUED",
"createdAt": "2026-06-20T10:00:00.000Z",
"origin": "Suporte",
"sourceNumber": "5511999999999"
}{
"error": "Validation error"
}{
"error": "Unauthorized"
}{
"error": "Tenant-scoped keys cannot call number endpoints",
"code": "TENANT_SCOPE_NOT_ALLOWED"
}{
"error": "Template not found"
}{
"error": "Billing suspended",
"code": "BILLING_SUSPENDED"
}{
"error": "Too many requests"
}