Submit a template to WhatsApp
Submit a draft template to Meta for approval, naming the WhatsApp number by its address (from).
Authorization
AuthorizationheaderrequiredBearer YOUR_API_KEY. Create a key in the dashboard.
Path parameters
templateIdstringrequired
Body
application/json
fromstringrequiredThe WhatsApp number whose Business Account receives the template: an address with a
whatsappentry inGET /v2/channels.categorystringWhatsApp template category.
One ofUTILITYMARKETINGAUTHENTICATION
Responses
202Submitted; status becomes `pending`.
idstringrequirednamestringrequiredTemplate name. For WhatsApp, must match the approved template name in Meta.
languagestringrequiredLanguage code.
bodystringrequiredDefault template body with variables: positional ({{1}}, {{2}}) or named ({{customer_name}}, {{contact.first_name}}). Templates created in Zavu are submitted to Meta as positional; templates imported from a WhatsApp Business Account keep their original format (named or positional). Used when no channel-specific body is set.
smsBodystringChannel-specific body for SMS messages. Falls back to
bodyif not set.telegramBodystringChannel-specific body for Telegram messages. Falls back to
bodyif not set.instagramBodystringChannel-specific body for Instagram messages. Falls back to
bodyif not set.categorystringrequiredThe category the template is billed under. For a template linked to WhatsApp this is the category Meta currently assigns, not the one it was submitted with: Meta can recategorize a template at approval or at any point afterwards, and that changes what the message costs.
A recategorization reaches this field through the
template.status_changedwebhook, which carriesdata.category, and throughPOST /v1/templates/sync, which reconciles it against Meta. Read one of those rather than assuming the category you sent is the one in force.For a template that was never submitted to WhatsApp, this is the category stored locally, defaulting to
UTILITY.One ofUTILITYMARKETINGAUTHENTICATIONstatusstringOne ofdraftpendingapprovedrejectedDefaultdraftvariablesstring[]List of variable names for documentation.
headerTypestringType of header (text, image, video, document).
headerContentstringHeader content (text or media URL).
footerstringFooter text for the template.
buttonsobject[]Template buttons.
8 properties
typestringOne ofquick_replyurlphoneotprequest_contact_infotextstringurlstringexamplestringSample value used to substitute
{{1}}in the URL when submitting the template to Meta for review. Only present for dynamic URL buttons.phoneNumberstringotpTypestringOTP button type. Required when type is 'otp'.
One ofCOPY_CODEONE_TAPpackageNamestringAndroid package name. Required for ONE_TAP buttons.
signatureHashstringAndroid app signature hash. Required for ONE_TAP buttons.
addSecurityRecommendationbooleanAdd 'Do not share this code' disclaimer. Only for AUTHENTICATION templates.
codeExpirationMinutesintegerCode expiration time in minutes. Only for AUTHENTICATION templates.
Limitsmin 1 · max 90whatsappobjectWhatsApp-specific template information.
3 properties
templateNamestringWhatsApp template name.
namespacestringWhatsApp Business Account namespace.
statusstringWhatsApp approval status.
createdAtstring<date-time>updatedAtstring<date-time>
400Not a draft, or `no_whatsapp`: the `from` address exists but has no WhatsApp Business Account (`details.types` lists what it has).
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring
401Unauthorized.
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring
404Template not found, or no channel of this project has the `from` address.
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring
409`ambiguous_from`: two of your senders have a `whatsapp` entry with this address.
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring