Messaging

Templates

Pre-approved WhatsApp copy. Required for every out-of-session message on production. Submitted to Meta, approved asynchronously, then usable by name.

Lifecycle

draft  →  submitted  →  approved    (sendable)
               ↓
             rejected   (edit + resubmit)
               ↓
              paused | disabled

Create a draft

POST/v1/templates

Template language is a string WhatsApp language code such as pt_BR or en_US. Do not send Meta's nested {"code":"pt_BR"} object shape.

curl https://api.tyxter.com/v1/templates \
  -H "authorization: Bearer $TYXTER_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "name": "order_update",
    "language": "pt_BR",
    "category": "utility",
    "components": [
      {
        "type": "BODY",
        "text": "Olá {{1}}, seu pedido {{2}} saiu para entrega.",
        "example": { "body_text": [["Diego", "ORD-123"]] }
      }
    ]
  }'

Generate a draft

POST/v1/templates/generate

Returns editable components from a short brief. Tyxter provides the generation provider; customers do not need to configure an LLM route before using this helper. In production each successful generation is a small billable operation (metered as template.generation); sandbox generations are free.

curl https://api.tyxter.com/v1/templates/generate \
  -H "authorization: Bearer $TYXTER_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "description": "Avisar que a conferencia online comeca em 15 minutos",
    "language": "pt_BR",
    "category": "utility",
    "template_type": "text"
  }'

Submit for approval

POST/v1/templates/{'{id}'}/submit

Snapshots the current components into a fresh TemplateVersion, transitions the template to submitted, and enqueues the Meta sync worker. Returns 202 — actual Meta approval is async.

Sandbox auto-approves templates without calling Meta. Your integration can exercise the full lifecycle end-to-end before touching real App Review.

Campaign readiness

Before a campaign or broadcast, list templates and verify that the exact requested name/language has an approved version. A targeted send returns template_not_approved when the template is missing, still draft, rejected, paused, or disabled.

If no approved template exists, complete the create → submit → approval lifecycle first. Do not silently switch to another template or language.

Edit a draft

PATCH/v1/templates/{'{id}'}

Draft and rejected templates can be edited. Image, document, and video headers must includeexample.header_handle[0], a Meta media handle used for review. Body and text header placeholders must include matching sample values in example.body_text orexample.header_text.

Duplicate a template

POST/v1/templates/{'{id}'}/duplicate

Duplicating creates a new draft with copied components and no provider template id. Supply a new name when you want a predictable slug, or omit it to let Tyxter choose the next available_copy name.

Authoring and quality signals

Template responses include provider_quality andauthoring_signals. Provider quality is derived from the durable Meta lifecycle state. Authoring signals warn about likely category mismatches, such as promotional language inside a utility template, before you submit for review.

Approval webhooks

Estimate cost before a broadcast

POST/v1/templates/{'{id}'}/estimate-cost
curl https://api.tyxter.com/v1/templates/tmpl_.../estimate-cost \
  -H "authorization: Bearer $TYXTER_API_KEY" \
  -H "content-type: application/json" \
  -d '{ "recipients": 10000 }'

Returns the meter id, per-recipient BRL amount, and total. Approved templates only — drafts and rejected templates 400 so you don't budget for sends Meta won't accept.

Inspect template analytics

GET/v1/templates/{'{id}'}/analytics

Analytics combine TemplateVersion approval outcomes with message sends bound totemplate_id. Legacy rows that only have template_name are included as a compatibility fallback.

Use in a send

curl https://api.tyxter.com/v1/messages \
  -H "authorization: Bearer $TYXTER_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "channel": "whatsapp",
    "sender": { "type": "whatsapp_phone_number", "id": "pn_..." },
    "recipient": { "type": "phone_e164", "id": "+5511999999999" },
    "message": {
      "type": "template",
      "template": {
        "name": "order_update",
        "language": "pt_BR",
        "variables": { "1": "Diego", "2": "ORD-123" }
      }
    }
  }'

SDK lifecycle

const template = await tyxter.templates.create({
  name: "order_update",
  language: "pt_BR",
  category: "utility",
  components: [
    {
      type: "BODY",
      text: "Olá {{1}}",
      example: { body_text: [["Diego"]] },
    },
  ],
});

await tyxter.templates.update(template.id, {
  components: [
    {
      type: "BODY",
      text: "Olá {{1}}, seu pedido foi atualizado.",
      example: { body_text: [["Diego"]] },
    },
  ],
});
await tyxter.templates.submit(template.id);
await tyxter.templates.analytics(template.id);