Sending messages
Send an approved template by id, or by name plus language.
Outside the 24-hour window, WhatsApp only
allows approved templates. A template is submitted to Meta for review, moves
through an approval lifecycle, and — once APPROVED — can be sent to opted-in
contacts. This page covers creating and tracking templates; see
Sending messages for sending an
approved one. Read paths need templates:read; create needs templates:write.
Templates can only be submitted on a dedicated WhatsApp channel whose Meta
business account is verified and has a Meta payment method. The shared
Wabery sandbox cannot submit templates — they belong to Wabery’s own account.
Read why WhatsApp templates need a payment method
if Wabery reports NO_PAYMENT_METHOD. Check readiness first:
const channel = await wabery.channels.get("channel_...");if (!channel.publish_readiness?.can_submit_templates) { console.log("Blocked by:", channel.publish_readiness?.blockers); // e.g. ["BUSINESS_NOT_VERIFIED", "NO_PAYMENT_METHOD"]}Submitting when not ready returns 412 with the same publish_readiness
blockers — Wabery rejects it rather than queueing work that Meta will refuse.
Open Build tools → Templates to create and monitor templates in the dashboard, or use the SDK or API below.
One call creates the template and submits it to Meta. category is one of
UTILITY, MARKETING, or AUTHENTICATION; components follow Meta’s template
component schema (header, body, footer, buttons).
const template = await wabery.templates.create({ channelId: "channel_...", name: "order_shipped", // a-z, 0-9, underscores language: "en", category: "UTILITY", components: [ { type: "BODY", text: "Your order {{1}} has shipped." }, ],});
console.log(template.status); // "PENDING" — review has startedcurl https://api.wabery.com/v1/templates \ -H "Authorization: Bearer $WABERY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "channel_id": "channel_...", "name": "order_shipped", "language": "en", "category": "UTILITY", "components": [ { "type": "BODY", "text": "Your order {{1}} has shipped." } ] }'A template response:
{ "object": "whatsapp_template", "id": "tmpl_...", "channel_id": "channel_...", "meta_template_id": "1234567890", "name": "order_shipped", "language": "en", "category": "UTILITY", "status": "PENDING", "submitted_at": "2026-06-20T14:00:00Z"}Review is asynchronous and can take up to 24 hours. status moves through:
| Status | Meaning |
|---|---|
PENDING |
Submitted to Meta; awaiting review. |
APPROVED |
Ready to send. |
REJECTED |
Meta declined it; see rejection_reason. |
DISABLED |
Previously approved, later disabled (e.g. quality drop). |
Track it in one of three ways — prefer the first two in production over blocking a request:
1. Webhook (recommended). Meta status changes arrive as a signed
template.status webhook — no polling.
2. On-demand refresh. status(id) forces a live Meta status check:
const latest = await wabery.templates.status("tmpl_..."); // GET with refreshwabery templates status "tmpl_..."3. Block until resolved. For scripts and CI, waitUntilApproved polls until
APPROVED, throwing if the template is REJECTED/DISABLED or the timeout
elapses:
const approved = await wabery.templates.waitUntilApproved("tmpl_...", { timeoutMs: 60 * 60 * 1000, // default 24h intervalMs: 60_000,});wabery templates wait "tmpl_..." --wait=86400Filter by channelId and/or status. Requires templates:read.
const { data } = await wabery.templates.list({ channelId: "channel_...", status: "APPROVED",});Once a template is APPROVED, send it — including flow-type templates for
proactive WhatsApp Flows — from
Sending messages.
Sending messages
Send an approved template by id, or by name plus language.
WhatsApp Flows
Flow-type templates open a Flow proactively, outside the 24-hour window.
Webhooks
Track approval with signed template.status events.