Templates
Approved WhatsApp templates: read what each needs, create new ones.
A template is a message WhatsApp approved in advance. It is the only way to start a conversation or to write after the 24-hour window, so order updates, reminders, verification codes and campaigns all use one.
How it works: TemplatesFind what a template needs · Send a template · Create a template · Approval · Delete a template
Find what a template needs#
GET /templates lists them, and each one says what a send must fill in:
{
"id": "tpl_27",
"name": "order_update",
"language": "ar",
"status": "approved",
"variables": { "body": 2, "buttons": [{ "index": 0, "type": "url" }] },
"send_example": {
"type": "template",
"template": {
"name": "order_update",
"language": "ar",
"variables": { "body": ["value 1", "value 2"], "buttons": { "0": { "url_suffix": "value" } } }
}
}
}send_example is a ready body for POST /messages: add to, replace the values, send. Only approved templates can be sent.
Send a template#
{
"to": "+966501234567",
"type": "template",
"template": {
"name": "order_update",
"language": "ar",
"variables": {
"body": ["سارة", "#10482"],
"buttons": { "0": { "url_suffix": "10482" } }
}
}
}| Variable | Fills in |
|---|---|
body | {{1}}, {{2}}… of the body, in order |
header_text | a text header's {{1}} |
header_media_link | an image, video or document header, as a public https:// link |
buttons | by button index: url_suffix (a URL button's {{1}}), coupon_code (copy-code), payload (quick reply) |
A wrong number of body values is refused at once with template_variables_mismatch, instead of failing later at WhatsApp.
Create a template#
POST /templates submits a template to WhatsApp. It takes WhatsApp's own components, and every {{n}} needs an example value:
{
"name": "order_shipped",
"language": "ar",
"category": "utility",
"components": [
{
"type": "BODY",
"text": "مرحبًا {{1}}، شُحن طلبك رقم {{2}} وسيصلك خلال يومين.",
"example": { "body_text": [["سارة", "10482"]] }
},
{
"type": "BUTTONS",
"buttons": [
{ "type": "URL", "text": "تتبّع الشحنة", "url": "https://shop.example.com/track/{{1}}", "example": ["https://shop.example.com/track/10482"] }
]
}
]
}- Categories.
utilityis for something the customer is waiting for (an order, an appointment).marketingis for promotions.authenticationis for one-time codes, and takesotpinstead ofcomponents. - Media headers. Upload the file with
POST /mediaand put itsmed_…id in the header'sexample.header_handle: we hand it to WhatsApp, and later sends use that file unless you passheader_media_link. - The checks come first. Name format (lowercase, digits,
_), component lengths, button counts, the language list and name uniqueness on the number's WhatsApp account are checked before anything reaches WhatsApp.
Approval#
A new template is pending. WhatsApp usually decides within minutes, sometimes up to 24 hours, and you get template.status_changed:
| Status | Meaning |
|---|---|
approved | Ready to send |
rejected | Refused; rejection_reason gives WhatsApp's reason when it gave one |
paused | Temporarily stopped by WhatsApp after poor feedback |
disabled | Stopped for good |
WhatsApp may also move an approved template to another category (for example utility to marketing), which changes its price. The template's category always shows the current one.
Delete a template#
DELETE /templates/{id} deletes it here and at WhatsApp. It is refused while a scheduled or running campaign uses it. WhatsApp does not let the same name be used again for 30 days.
Endpoints
List templates
https://api.saei.automize.sa/v1/templates- Scope:
templates:read - Works in test mode
Your WhatsApp message templates. Each one says what it needs filled in (variables) and carries a send_example you can paste into POST /v1/messages.
Query parameters
limitintegeroptionalHow many objects to return, 1 to 100.
cursorstringoptionalThe
next_cursorfrom the previous page.statusstringoptionalOne of
approvedpendingrejectedpauseddisableddraftcategorystringoptionalOne of
marketingutilityauthenticationlanguagestringoptionalA language code, e.g.
aroren_US.namestringoptionalThe exact template name.
Response fields200· A page of templates.
object"list"requireddataarray<Template>requiredChild fields (12)
idstringrequiredobject"template"requirednamestringrequiredlanguagestring | nullrequiredcategorystring | nulloptionalOne of
marketingutilityauthenticationnullstatusstringrequiredOnly
approvedtemplates can be sent.rejection_reasonstring | nulloptionalcomponentsarrayrequiredHEADER, BODY, FOOTER and BUTTONS, exactly as WhatsApp holds them.
variablesobjectrequiredWhat a send must fill in:
header(the header type that needs a value),body(how many {{n}} placeholders) andbuttons(which buttons take a value).Child fields (3)
headerstringoptionalbodyintegeroptionalbuttonsarray<object>optionalChild fields (2)
indexintegeroptionaltypestringoptional
send_exampleobjectrequiredA
POST /v1/messagesbody for this template with placeholder values. Addtoand your values.created_atstring | nulloptionalupdated_atstring | nulloptional
has_morebooleanrequirednext_cursorstring | nullrequired
Errors this can return2
- 422parameter_invalidInvalid parameter
- 429rate_limitedToo many requests
Try it
curl -X GET https://api.saei.automize.sa/v1/templates \
-H "Authorization: Bearer $API_KEY"A page of templates.
{
"object": "list",
"data": [
{
"id": "tpl_27",
"object": "template",
"name": "string",
"language": "string",
"category": "marketing",
"status": "string",
"rejection_reason": "string",
"components": [],
"variables": {
"header": "string",
"body": 0,
"buttons": [
{
"index": null,
"type": null
}
]
},
"send_example": {},
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}
],
"has_more": false,
"next_cursor": "string"
}Create a template
https://api.saei.automize.sa/v1/templates- Scope:
templates:write - Live keys only
- Accepts Idempotency-Key
Submits a new template to WhatsApp for approval. It comes back pending; WhatsApp usually decides within minutes (sometimes up to 24 hours), and you get template.status_changed when it does.
components are WhatsApp's own: HEADER, BODY (required), FOOTER, BUTTONS. Every {{n}} placeholder needs an example value, or WhatsApp rejects the template. The builder's own checks run first (lengths, button counts, the language list, name unique per WhatsApp account), so most mistakes come back at once as parameter_invalid.
For an image, video or document header, upload the file with POST /v1/media and put its med_… id in example.header_handle: we hand it to WhatsApp for you, and the template then sends with that file by default.
Authentication (OTP) templates take otp instead of components, need a plan with OTP verification, and a business verified by Meta.
Headers
Idempotency-KeystringoptionalAny unique string (a UUID is ideal). Retrying with the same key and body returns the first response instead of acting twice. Remembered for 24 hours.
Request body
namestringrequiredLowercase letters, digits and underscores, e.g.
order_shipped.languagestringrequiredcategorystringrequiredOne of
marketingutilityauthenticationnumber_idstringoptionalWhich number's WhatsApp account holds the template. Default: your default number.
componentsarrayoptionalWhatsApp template components (HEADER, BODY, FOOTER, BUTTONS), each
{{n}}with anexample.otpobjectoptionalFor
authentication:button_text(e.g. "Copy code"), optionalcode_expiration_minutesandshow_security_recommendation.
Response fields201· Submitted to WhatsApp; `status` is `pending`.
idstringrequiredobject"template"requirednamestringrequiredlanguagestring | nullrequiredcategorystring | nulloptionalOne of
marketingutilityauthenticationnullstatusstringrequiredOnly
approvedtemplates can be sent.rejection_reasonstring | nulloptionalcomponentsarrayrequiredHEADER, BODY, FOOTER and BUTTONS, exactly as WhatsApp holds them.
variablesobjectrequiredWhat a send must fill in:
header(the header type that needs a value),body(how many {{n}} placeholders) andbuttons(which buttons take a value).Child fields (3)
headerstringoptionalbodyintegeroptionalbuttonsarray<object>optionalChild fields (2)
indexintegeroptionaltypestringoptional
send_exampleobjectrequiredA
POST /v1/messagesbody for this template with placeholder values. Addtoand your values.created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return9
- 403capability_disabledCapability turned off
- 403test_mode_unsupportedNot in test mode
- 422parameter_missingMissing parameter
- 422parameter_invalidInvalid parameter
- 404resource_missingNot found
- 422sender_not_configuredNo sending number
- 422channel_errorWhatsApp rejected it
- 409resource_existsAlready exists
- 429rate_limitedToo many requests
Try it
curl -X POST https://api.saei.automize.sa/v1/templates \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "order_shipped",
"language": "ar",
"category": "utility",
"components": [
{
"type": "BODY",
"text": "مرحبًا {{1}}، شُحن طلبك رقم {{2}} وسيصلك خلال يومين.",
"example": {
"body_text": [
[
"سارة",
"10482"
]
]
}
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "URL",
"text": "تتبّع الشحنة",
"url": "https://shop.example.com/track/{{1}}",
"example": [
"https://shop.example.com/track/10482"
]
}
]
}
]
}'Submitted to WhatsApp; `status` is `pending`.
{
"id": "tpl_27",
"object": "template",
"name": "string",
"language": "string",
"category": "marketing",
"status": "string",
"rejection_reason": "string",
"components": [],
"variables": {
"header": "string",
"body": 0,
"buttons": [
{
"index": 0,
"type": "string"
}
]
},
"send_example": {},
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}Get a template
https://api.saei.automize.sa/v1/templates/{id}- Scope:
templates:read - Works in test mode
One template, its components as WhatsApp approved them, and for a rejected template WhatsApp's reason when it gave one.
Path parameters
idstringrequiredThe object's id.
Response fields200· The template.
idstringrequiredobject"template"requirednamestringrequiredlanguagestring | nullrequiredcategorystring | nulloptionalOne of
marketingutilityauthenticationnullstatusstringrequiredOnly
approvedtemplates can be sent.rejection_reasonstring | nulloptionalcomponentsarrayrequiredHEADER, BODY, FOOTER and BUTTONS, exactly as WhatsApp holds them.
variablesobjectrequiredWhat a send must fill in:
header(the header type that needs a value),body(how many {{n}} placeholders) andbuttons(which buttons take a value).Child fields (3)
headerstringoptionalbodyintegeroptionalbuttonsarray<object>optionalChild fields (2)
indexintegeroptionaltypestringoptional
send_exampleobjectrequiredA
POST /v1/messagesbody for this template with placeholder values. Addtoand your values.created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return2
- 404resource_missingNot found
- 429rate_limitedToo many requests
Try it
curl -X GET https://api.saei.automize.sa/v1/templates/tpl_27 \
-H "Authorization: Bearer $API_KEY"The template.
{
"id": "tpl_27",
"object": "template",
"name": "order_update",
"language": "ar",
"category": "utility",
"status": "approved",
"rejection_reason": null,
"components": [
{
"type": "BODY",
"text": "مرحبًا {{1}}، طلبك {{2}} في الطريق."
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "URL",
"text": "تتبّع الطلب",
"url": "https://shop.example.com/track/{{1}}"
}
]
}
],
"variables": {
"body": 2,
"buttons": [
{
"index": 0,
"type": "url"
}
]
},
"send_example": {
"type": "template",
"template": {
"name": "order_update",
"language": "ar",
"variables": {
"body": [
"value 1",
"value 2"
],
"buttons": [
{
"url_suffix": "value"
}
]
}
}
},
"created_at": "2026-08-01T10:00:00Z",
"updated_at": "2026-08-02T07:30:00Z"
}Delete a template
https://api.saei.automize.sa/v1/templates/{id}- Scope:
templates:write - Live keys only
Deletes the template here and at WhatsApp. Refused with resource_in_use while a scheduled or running campaign uses it. WhatsApp does not let the same name be reused for 30 days.
Path parameters
idstringrequiredThe object's id.
Response fields200· Deleted.
idstringrequiredobjectstringrequireddeletedtruerequired
Errors this can return4
- 403test_mode_unsupportedNot in test mode
- 404resource_missingNot found
- 409resource_in_useStill in use
- 429rate_limitedToo many requests
Try it
curl -X DELETE https://api.saei.automize.sa/v1/templates/tpl_27 \
-H "Authorization: Bearer $API_KEY"Deleted.
{
"id": "tpl_27",
"object": "template",
"deleted": true
}