Skip to content
Start free

WhatsApp templates

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 started

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 refresh
Terminal window
wabery 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,
});
Terminal window
wabery templates wait "tmpl_..." --wait=86400

Filter 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.