Skip to main content
Templates define reusable message content. Create and manage them in the dashboard (/templates) or via the public REST API (/v1/templates) and the MCP server (templates_create / templates_update / templates_delete). When sending, reference the template by templateId and pass a variables object with matching keys.
All requests use the x-api-key: ps_... header (or x-api-key-id). Base URL: https://pilotstatus.com.br/v1.

Category

Set at creation time; cannot be changed later.
  • MARKETING — promotional messages (more sensitive to WhatsApp policies).
  • UTILITY — transactional messages (account updates, alerts, reminders).
  • OTP — one-time / verification code messages.

Template structure

Only body is required.
ComponentRequiredWhat it is
HeaderoptionalText or one media item (image, video, PDF).
BodyrequiredMain text with {{variable}} placeholders.
FooteroptionalShort static line under the body.
ButtonsoptionalUp to 10 interactive buttons.
TypeValueNotes
NONEDefault.
TEXTtextUp to 60 chars, 0 or 1 variable. No line breaks/emojis/formatting.
IMAGEurl or base64JPG/PNG.
VIDEOurl or base64MP4.
DOCUMENTurl or base64PDF.
  • REST API: pass either header.url (public http(s) URL) or header.base64 (data URI) — base64 is re-hosted server-side automatically.
  • MCP: header.url only — base64 is not supported over MCP.
There is no LOCATION header.

Body

  • Up to 1024 characters.
  • Variables written as {{nome}} (named style).
  • The body must not start or end with a variable.
  • Emojis and multiple variables allowed.
Static text up to 60 characters. No variables.

Buttons

Up to 10 buttons total; quick-reply and CTA buttons can be mixed.
TypeFieldsLimit
QUICK_REPLYtextup to 10
URLtext, url (static or dynamic)up to 2
PHONE_NUMBERtext, phone_number (E.164)up to 1
COPY_CODEexample (code to copy)up to 1
  • Dynamic URL button: URL ends with a variable (e.g. https://loja.com/promo/{{link}}) — one variable max, never in the domain. Sample value goes in examples.
  • Copy-code: value goes on the button as example (array, e.g. ["PROMO10"]), alphanumeric only, up to 15 chars. Not for PIX keys or e-mails — put those in the body as a {{variable}} instead.
  • Buttons are allowed together with a video or document (PDF) header.

Variables & examples (required)

When creating/updating via REST or MCP you must include an examples object mapping every variable used (body + header text + dynamic URL) to a real sample value. The copy-code value is the only exception (it lives on the button).
400 { "code": "TEMPLATE_EXAMPLES_REQUIRED", "details": { "missing": ["desconto"] } }
After saving, GET /v1/templates/{id} returns all detected keys in latestVersion.variables — supply all of them in variables on send.

Character limits

ComponentLimitRules
Header (text)60No line breaks/emojis/formatting; at most 1 variable.
Body1024Can’t start or end with a variable.
Footer60No variables.
Button label25
Copy-code value15Alphanumeric only.

Create via REST API

curl -X POST https://pilotstatus.com.br/v1/templates \
  -H "Content-Type: application/json" \
  -H "x-api-key: ps_your_token_here" \
  -d '{
  "name": "promo_cupom",
  "category": "MARKETING",
  "language": "pt_BR",
  "body": {
    "header": { "type": "IMAGE", "url": "https://cdn.exemplo.com/banner.png" },
    "body":   { "text": "Oi {{nome}}! Use e ganhe {{desconto}} de desconto." },
    "footer": { "text": "Promoção por tempo limitado" },
    "buttons": [
      { "type": "QUICK_REPLY",  "text": "Quero!" },
      { "type": "URL",          "text": "Comprar", "url": "https://loja.com/promo/{{link}}" },
      { "type": "PHONE_NUMBER", "text": "Falar",   "phone_number": "+5511999998888" },
      { "type": "COPY_CODE",    "example": ["PROMO10"] }
    ]
  },
  "examples": { "nome": "Maria", "desconto": "10%", "link": "abc123" }
}'
  • body may be an object (recommended), a JSON string, or plain text (body-only templates).
  • Edit with PUT /v1/templates/{id} (same shape); remove with DELETE /v1/templates/{id} (also deletes from Meta for Meta templates; returns { deleted: true, id }).
  • GET /v1/templates / GET /v1/templates/{id} return source (META | PILOT_STATUS), metaStatus (APPROVED | PENDING | REJECTED | DISABLED | null), metaLanguage, and sendable — on a Meta number only META templates with metaStatus: "APPROVED" are sendable.

Approval

  • Meta numbers: templates are submitted to Meta for review (“Submit to Meta” in /templates, or on save). Categories, language and status follow Meta’s rules.
  • Unofficial (Evolution) numbers: templates are created locally and immediately usable — no approval step.

Not supported

FLOW, LOCATION (header or button), CAROUSEL, CATALOG/MPM, LIMITED_TIME_OFFER, OTP autofill/one-tap/zero-tap, VOICE_CALL buttons, and the NAMED parameter_format.

Submit & rejection errors

Link/URL buttons accept a single variable that must be at the end of the URL and never in the domain; call buttons need the country code (e.g. +55).

Checked before submitting to Meta

CauseFixMeta code
Body starts/ends with a variableAdd literal text at the edges2388299
Button combination over limits≤10 total, ≤10 quick-reply, ≤2 URL, ≤1 call, ≤1 copy-code100
Call button without country codeUse E.164 (+55 21 99999-8888)192
Link button on placeholder domain (example.com…)Use your real business URL368/1346003
Variable in the URL domainVariable only at the end of the path100
More than one URL variable / not at endOne variable, at the end100
Copy-code with symbols/spaces or >15 charsAlphanumeric ≤15100
Footer contains a variableRemove it2388073
Text header with emoji/line break/formatting/2+ variablesPlain text, ≤1 variable2388047
Field over character limitHeader 60, body 1024, footer 60, button 252388040

API-side validation

CauseFixMeta code
Too many variables vs fixed textAdd wording or reduce variables2388293

Meta rejected the submission

CauseFixMeta code
Media header but number missing Meta App IDSet App ID in number settings
Invalid parameter (Meta reason shown)Review indicated field100
Content flagged abusive (usually button URL domain)Review button links368/1346003
Display name not approved yetWait for Meta approval131008
URL button invalid link/variableCheck link and {{…}}100
Media upload to Meta failedHeader file reachable + valid format
Header file too large / unsupportedImage ≤5MB JPEG/PNG, video ≤16MB MP4, PDF ≤10MB131002/131003
Number temporarily blocked (policy)Resolve with Meta368
Token missing WhatsApp permissionsReconnect number granting permissions10/200/3
Token invalid/expiredUpdate System Token190
WABA inaccessible/removedReconnect the number on Meta100/subcode 33

Rejected after review

ReasonMeta code
Threatening/abusive/policy-violating contentABUSIVE_CONTENT
Category doesn’t match contentINCORRECT_CATEGORY
Formatting: bad/adjacent variables, missing examplesINVALID_FORMAT
Utility template with promotional content
Looks like a scam (generic, fake urgency)SCAM
Selected language ≠ written text

Blocks when sending (even approved)

CauseMeta code
Business verification not completed141010
No payment method / outstanding invoice on WABA131042 / 141006
Template permanently disabled after repeated pauses132016
Template not approved yet131053
Variable count ≠ approved template132000
Template paused for quality drop132015

Common error when sending

404 — template without an approved version (doesn’t exist for the key, or Meta template has no approved version yet).