Create a template and submit it to Meta for review
Build a request to copy
This page never sends a request. Fill in the fields, then copy the request and run it from your server.
curl -X POST 'https://api.whatsable.app/v1/templates' \
-H 'Content-Type: application/json' \
-d '{
"number_id": "cm2v8a1b20002qz8h9i0j1k2l",
"name": "order_shipped",
"display_name": "Order shipped",
"language": "en_US",
"category": "utility",
"header": {
"type": "image",
"url": "https://acme.example/box.jpg"
},
"body": "Hi {{1}}, your order {{2}} is on its way.",
"body_examples": [
"Ana",
"#1042"
],
"footer": "Reply STOP to stop these messages",
"buttons": [
{
"type": "url",
"text": "Track",
"url": "https://acme.example/t/{{1}}",
"example": "1042"
},
{
"type": "quick_reply",
"text": "Talk to us"
}
]
}'Creates a template and submits it to Meta for review.
A 201 means that Meta accepted the template for review, not that Meta approved it. The template starts as
pendingorapproved. A later rejection changesstatus, and never returns an HTTP error.
A refused request stores no template. A check that fails before the call to Meta submits nothing to Meta.
bearerAuthAuthorizationBearer <nfy_live_<32 characters>>An API key from Settings > API keys, sent as Authorization: Bearer <key>.
Idempotency-Key?stringAny string up to 255 characters. A repeat with the same key and body answers the stored response; with another body, 409 idempotency_key_reused.
length <= 255application/json- body
A template to submit to Meta for review. Every rule here is checked before Meta is called, and a 400 submits nothing.
number_id?stringA number on the WhatsApp Business Account the template is created in. Absent, the key's default number decides.
1 <= length <= 64name?stringMeta's identifier: lowercase letters, digits and underscores, starting with a letter. Derived from display_name when absent.
^[a-z][a-z0-9_]*$1 <= length <= 512display_name?stringThe name people read. With name, it must derive to name.
1 <= length <= 512language*stringMeta's language code, such as en_US.
2 <= length <= 15category*string"marketing""utility""authentication"header?||||none (the default), text, or a media header, by url or by media_id, whose file the server uploads to Meta and keeps.
body?stringUp to 1,024 characters, with {{1}}, {{2}}, ... numbered from 1 without gaps. Named variables are not accepted. Absent only for an authentication template.
length <= 1024body_examples?array<>One example per body variable, in order. Absent, placeholders are submitted; real examples are what Meta's reviewers read.
items <= 100footer?string1 <= length <= 60buttons?array<||||>items <= 10authentication?For the authentication category only.
Meta accepted the template for review.
application/json- response
A WhatsApp message template, with the variable schema a send needs.
object*stringid*string1 <= length <= 64name*stringMeta's identifier: lowercase letters, digits and underscores.
display_name*|The name people read. Null for a template created outside Whatsable.
language*stringMeta's language code, such as en_US.
category*|Meta's category, which Meta may change during review.
status*|Meta's review status. Only approved templates send.
rejected_reason*|Meta's reason when status is rejected, otherwise null.
waba_id*stringThe WhatsApp Business Account the template belongs to. Every number on it can send it.
body*stringThe body text, with its {{n}} variables.
parameter_format*|positional ({{1}}) or named ({{customer_name}}). The API lists a named template but cannot send it yet.
variables*array<>Every value a send must or may supply. Build a send's template.variables from it.
buttons*array<>created_at*stringdate-timeupdated_at*stringdate-timecurl -X POST 'https://api.whatsable.app/v1/templates' \ -H 'Content-Type: application/json' \ -d '{ "number_id": "cm2v8a1b20002qz8h9i0j1k2l", "name": "order_shipped", "display_name": "Order shipped", "language": "en_US", "category": "utility", "header": { "type": "image", "url": "https://acme.example/box.jpg" }, "body": "Hi {{1}}, your order {{2}} is on its way.", "body_examples": [ "Ana", "#1042" ], "footer": "Reply STOP to stop these messages", "buttons": [ { "type": "url", "text": "Track", "url": "https://acme.example/t/{{1}}", "example": "1042" }, { "type": "quick_reply", "text": "Talk to us" } ]}'{ "object": "template", "id": "cm2v8t1a00001qz8habcd1234", "name": "order_shipped", "display_name": "Order shipped", "language": "en_US", "category": "utility", "status": "approved", "rejected_reason": null, "waba_id": "9876543210", "body": "Hi {{1}}, your order {{2}} is on its way.", "parameter_format": "positional", "variables": [ { "key": "header_image", "component": "header", "type": "image", "required": true, "example": null }, { "key": "1", "component": "body", "type": "text", "required": true, "example": "Ana" }, { "key": "2", "component": "body", "type": "text", "required": true, "example": "#1042" }, { "key": "button_0", "component": "button", "type": "text", "required": true, "example": "1042" } ], "buttons": [ { "type": "url", "text": "Track", "url": "https://acme.example/t/{{1}}", "phone": null } ], "created_at": "2026-09-01T12:00:00Z", "updated_at": "2026-09-02T08:00:00Z"}