Template with a file header
How to send an official template with a document, image or video header — a different PDF invoice for each customer.
https://app.syncro.chat/api/v1AuthX-API-Key: crm_SUA_CHAVE_AQUIPrerequisites
Meta's official templates can carry a document, image or video header. The file is not part of the approved template: it travels with each send, and it can be different for every recipient.
This is how you send one PDF invoice per customer, a receipt, a payment slip or a shipping label.
- The number must be on Meta's Official API (
provider: "cloud_api"). Numbers connected via QR Code cannot send templates. - The template must be approved (
status: "APPROVED") and must have been created with a media header. The header is defined when the template is created, in the dashboard — you cannot attach a file to a text template. - The file must sit on a public URL. Meta downloads it from its own servers; a URL behind a login, a VPN or an IP allowlist will not work. Use a long-lived signed link if the file is sensitive.
Size and format limits are Meta's, not ours.
Find out whether a template needs a file
GET /whatsapp/templates returns the template's components exactly as Meta publishes them. Look for the HEADER component and read its format:
curl "https://app.syncro.chat/api/v1/whatsapp/templates?status=APPROVED" \
-H "X-API-Key: crm_YOUR_KEY_HERE"
{
"success": true,
"data": [
{
"id": 10,
"name": "fatura_mensal",
"language": "pt_BR",
"category": "UTILITY",
"status": "APPROVED",
"variables": ["1", "2"],
"components": [
{ "type": "HEADER", "format": "DOCUMENT" },
{ "type": "BODY", "text": "Olá {{1}}, sua fatura vence em {{2}}." }
]
}
]
}
HEADER format |
What to send |
|---|---|
TEXT or absent |
nothing — the header is fixed text |
DOCUMENT |
header_media_url pointing at the file (a PDF, for example) |
IMAGE |
header_media_url pointing at the image |
VIDEO |
header_media_url pointing at the video |
A template with a media header and no
header_media_urlis rejected with422before anything is sent.
Send
Sending uses the usual endpoint: POST /leads/{id}/send-whatsapp-template, with the whatsapp:write scope. The full parameter table lives there.
A different invoice per customer
curl -X POST https://app.syncro.chat/api/v1/leads/123/send-whatsapp-template \
-H "X-API-Key: crm_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"template_id": 10,
"variables": { "1": "João", "2": "30/07" },
"header_media_url": "https://yourdomain.com/invoices/8842.pdf",
"header_media_filename": "Invoice-July-2026.pdf"
}'
{
"success": true,
"conversation_id": 99,
"message_id": 457,
"provider_msg_id": "wamid.xyz456",
"template_name": "fatura_mensal"
}
To send in bulk, repeat the call per recipient swapping header_media_url. It is the only route that allows one file per contact — the dashboard's bulk send uses the same media for the whole campaign.
About header_media_filename
Without it, the contact sees whatever name Meta can infer from the URL — usually the file's identifier. With it, they see the name you choose:
Without header_media_filename |
With |
|---|---|
8842.pdf |
Invoice-July-2026.pdf |
On IMAGE and VIDEO headers the field is ignored: Meta does not display a filename for those types.
Variables
The key is the {{N}} number in the template's approved body:
{ "variables": { "1": "João", "2": "30/07" } }
A list in order is also accepted and is equivalent to the map above:
{ "variables": ["João", "30/07"] }
Two of Meta's rules are worth remembering, because it rejects the whole send when they are broken:
- a variable cannot be empty;
- a variable cannot contain a line break.
If the template has a text header with a variable ({{1}} inside the HEADER), pass that value under the header_1 key, so it does not compete for position with the body:
{ "variables": { "header_1": "Julho", "1": "João", "2": "30/07" } }
Errors
| HTTP | Body | What to do |
|---|---|---|
422 |
skip_reason: "header_media_required", with header_format |
The template needs a file in the header. Send header_media_url |
422 |
Envio de template requer instancia Cloud API. |
The number is QR Code. Use an Official API number |
422 |
Lead sem telefone cadastrado. |
The lead must have a phone number |
502 |
Provedor retornou erro: … with raw |
Meta rejected it. raw carries Meta's original error |
Example of the header 422:
{
"success": false,
"message": "O template \"fatura_mensal\" tem cabecalho de document e exige `header_media_url` com a URL publica do arquivo.",
"skip_reason": "header_media_required",
"header_format": "DOCUMENT"
}
This error comes before the send and before the conversation is created — a looping integration can retry without littering the inbox.
What the API does not do
- It does not accept file uploads. Public URL only; there is no
multipart/form-dataand no base64. The file stays hosted on your side. - It does not send documents outside a template.
POST /leads/{id}/send-whatsapponly acceptstype: "text"andtype: "image". - It does not create templates. Creation — with the media header and the sample file Meta requires for approval — happens in the dashboard.