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.

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 & events

Track approval with signed template.status events.