WhatsApp Templates API
For schema reference, validation rules, supported languages, and component details, see whatsapp_templates.md.
This document describes how to call each WhatsApp template endpoint with curl examples, request/response formats, and per-endpoint errors.
First Template Walkthrough
A typical journey to deliver a template to your users:
- Upload media (only if your template has an
IMAGE/VIDEO/DOCUMENTheader) → Upload Media returns a handle - Create template → Create Template submits to Meta for review. Use the upload's
handleinsidecreation[*].example.header_handleif you have a media header - Wait for approval → Meta reviews asynchronously. Watch the
template_status_updatewebhook forunder_review→approved(orrejected) - Send template message → use the template
idastempMsgIDin Send Message once status isapproved - Update / Delete later via Update Template or Delete Template
Create Template
Create a new WhatsApp template and submit it for review.
Endpoint
POST /v2/whatsapp/templates
Authentication
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key |
Content-Type | Yes | application/json |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Template name (lowercase letters, digits, underscores only) |
category | string | Yes | One of AUTHENTICATION, MARKETING, UTILITY |
language | string | Yes | Language code (e.g. en_US, ar). See whatsapp_templates.md |
creation | array | Yes | Components array. Must contain a BODY component |
compose is auto-generated from creation by the gateway - do not send it.
For component structure (HEADER, BODY, FOOTER, BUTTONS, CAROUSEL), see whatsapp_templates.md.
Example - Text-only template
curl -X POST "https://api.experiaapp.com/v2/whatsapp/templates" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "welcome_simple",
"category": "UTILITY",
"language": "en_US",
"creation": [
{ "type": "BODY", "text": "Welcome to our service!" }
]
}'
Example - Template with media header
For an IMAGE / VIDEO / DOCUMENT header, first upload the media via Upload Media and pass the returned handle in example.header_handle:
curl -X POST "https://api.experiaapp.com/v2/whatsapp/templates" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "promo_with_image",
"category": "MARKETING",
"language": "en_US",
"creation": [
{
"type": "HEADER",
"format": "IMAGE",
"example": {
"header_handle": ["4::aW...=="]
}
},
{ "type": "BODY", "text": "Limited time offer just for you!" }
]
}'
Response
{
"id": "cac845bf-910d-48f5-b70e-77f3fe806134",
"name": "welcome_simple",
"title": "welcome_simple",
"category": "UTILITY",
"language": "en_US",
"status": "submitted",
"creation": "[{\"type\":\"BODY\",\"text\":\"Welcome to our service!\"}]",
"compose": "{\"to\":\"<accountID>\",\"type\":\"template\",\"template\":{...}}",
"whatsappID": "",
"rejectReason": "",
"qualityRating": "",
"isMinExperia": false,
"createdAt": "2026-01-15T10:30:00Z"
}
The template enters status submitted, then transitions to under_review once submitted to Meta, then approved or rejected. See Template Statuses.
Errors
| Status | Error | Cause |
|---|---|---|
| 400 | Category must be one of AUTHENTICATION, MARKETING, or UTILITY | Invalid category value |
| 400 | At least one component is required in the creation field | Empty creation array |
| 400 | A BODY component is required in the creation field | Missing required BODY component |
| 400 | Invalid request body | Malformed JSON |
| 401 | Unauthorized | Missing or invalid API key |
| 502 | Bad gateway | Service temporarily unavailable |
List / Get Templates
Retrieve all templates for the consumer's channel, or a specific template by ID.
Endpoint
GET /v2/whatsapp/templates
GET /v2/whatsapp/templates?templateID={id}
Authentication
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
templateID | string | No | If provided, returns the single matching template. Omit to list all |
Example - List all
curl "https://api.experiaapp.com/v2/whatsapp/templates" \
-H "X-API-Key: YOUR_API_KEY"
Example - Single template
curl "https://api.experiaapp.com/v2/whatsapp/templates?templateID=cac845bf-910d-48f5-b70e-77f3fe806134" \
-H "X-API-Key: YOUR_API_KEY"
Response
Returns an array of template objects:
[
{
"id": "cac845bf-910d-48f5-b70e-77f3fe806134",
"name": "welcome_simple",
"title": "welcome_simple",
"category": "UTILITY",
"language": "en_US",
"status": "approved",
"creation": "[{\"type\":\"BODY\",\"text\":\"Welcome to our service!\"}]",
"compose": "{\"to\":\"<accountID>\",\"type\":\"template\",\"template\":{...}}",
"whatsappID": "1008681241488740",
"rejectReason": "",
"qualityRating": "",
"isMinExperia": false,
"createdAt": "2026-01-15T10:30:00Z",
"updateAt": { "Valid": true, "Time": "2026-01-15T11:00:00Z" },
"deleteAt": { "Valid": false, "Time": "0001-01-01T00:00:00Z" }
}
]
Errors
| Status | Error | Cause |
|---|---|---|
| 401 | Unauthorized | Missing or invalid API key |
| 502 | Bad gateway | Service temporarily unavailable |
Update Template
Update content (and optionally name/category) of an existing template. Only templates with status APPROVED, REJECTED, or PAUSED can be edited.
Endpoint
POST /v2/whatsapp/templates/update
Authentication
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key |
Content-Type | Yes | application/json |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Template ID to update |
creation | string | No | New components as JSON-encoded string. e.g. "[{\"type\":\"BODY\",\"text\":\"new text\"}]" |
title | string | No | New title. Cannot be changed for APPROVED templates. If omitted, existing title is kept |
category | string | No | New category. Ignored for APPROVED templates (Meta restriction) |
compose is auto-generated from creation by the gateway - do not send it.
Editing Rules
APPROVEDtemplates: onlycreation(content) can be changed; max 10 edits per 30-day window or 1 per 24 hoursREJECTED/PAUSEDtemplates: all fields can be changed freely- Templates in any other status (
submitted,under_review) cannot be edited
Example
curl -X POST "https://api.experiaapp.com/v2/whatsapp/templates/update" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "cac845bf-910d-48f5-b70e-77f3fe806134",
"creation": "[{\"type\":\"BODY\",\"text\":\"Updated content\"}]"
}'
Response
{
"id": "cac845bf-910d-48f5-b70e-77f3fe806134",
"name": "welcome_simple",
"title": "welcome_simple",
"category": "UTILITY",
"language": "en_US",
"status": "submitted",
"creation": "[{\"type\":\"BODY\",\"text\":\"Updated content\"}]",
"compose": "{\"to\":\"<accountID>\",\"type\":\"template\",\"template\":{...}}",
"whatsappID": "1008681241488740",
"rejectReason": "",
"qualityRating": "",
"isMinExperia": false,
"updateAt": { "Valid": true, "Time": "2026-01-15T12:00:00Z" }
}
After Meta accepts the update, status transitions to under_review, then to approved or rejected once Meta finishes its review. Webhooks fire on each transition.
Errors
| Status | Error | Cause |
|---|---|---|
| 400 | Only APPROVED, REJECTED, or PAUSED templates can be edited | Template is not in an editable status |
| 400 | Cannot change name of an approved template | title was provided and differs from existing title on an APPROVED template |
| 400 | Approved template edit limit reached (max 10 edits in 30 days or 1 in 24h) | Edit rate limit hit |
| 400 | Invalid creation format | creation field is not valid JSON |
| 404 | Template not found | No template with given id |
| 401 | Unauthorized | Missing or invalid API key |
| 500 | Internal server error | Server-side error |
| 502 | Bad gateway | Service temporarily unavailable |
Delete Template
Delete an existing template. The deletion is propagated to Meta.
Endpoint
DELETE /v2/whatsapp/templates
Authentication
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key |
Content-Type | Yes | application/json |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Template ID to delete |
Example
curl -X DELETE "https://api.experiaapp.com/v2/whatsapp/templates" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "id": "cac845bf-910d-48f5-b70e-77f3fe806134" }'
Response
Returns the deleted template object:
{
"id": "cac845bf-910d-48f5-b70e-77f3fe806134",
"name": "welcome_simple",
"title": "welcome_simple",
"category": "UTILITY",
"language": "en_US",
"status": "approved",
"creation": "[{\"type\":\"BODY\",\"text\":\"Welcome to our service!\"}]",
"compose": "{\"to\":\"<accountID>\",\"type\":\"template\",\"template\":{...}}",
"whatsappID": "1008681241488740",
"deleteAt": { "Valid": true, "Time": "2026-01-15T13:00:00Z" }
}
Errors
| Status | Code | Message | Cause |
|---|---|---|---|
| 400 | - | Invalid request body | Missing or malformed id |
| 400 | 1033 | template not found | No template with given id |
| 401 | - | Unauthorized | Missing or invalid API key |
| 500 | 1029 | Internal server error | Server-side error |
| 502 | - | Bad gateway | Service temporarily unavailable |
Upload Media
Upload media (image, video, document) and get a handle/URL to use in template HEADER components.
Endpoint
POST /v2/whatsapp/upload
Authentication
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key |
Content-Type | Yes | multipart/form-data |
Form Fields
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | Media file to upload |
Size Limits
| Format | Max Size |
|---|---|
| IMAGE | 5 MB |
| VIDEO | 16 MB |
| DOCUMENT | 100 MB |
Example
curl -X POST "https://api.experiaapp.com/v2/whatsapp/upload" \
-H "X-API-Key: YOUR_API_KEY" \
-F "file=@/path/to/image.jpg"
Response
{
"h": "4::aW...=="
}
Use the returned h value inside a HEADER component's example.header_handle array when creating templates - see the Create Template - media header example.
Errors
| Status | Code | Message | Cause |
|---|---|---|---|
| 400 | 1029 | Upload error: ... | Missing file or read error |
| 500 | 1029 | Upload error: ... | Internal upload failure |
| 502 | - | Bad gateway | Service temporarily unavailable |
Template Lifecycle
A template moves through these statuses:
submitted → under_review → approved
→ rejected
→ submit_failed (validation/transport error before Meta accepted)
For full status descriptions see Template Statuses.
Webhook Events
A TemplateStatus webhook is published on every status transition. Example payload:
{
"Type": "TemplateStatus",
"SourceID": "CHANNEL_ID",
"Event": {
"Type": "template_status_update",
"templateID": "cac845bf-910d-48f5-b70e-77f3fe806134",
"status": "approved",
"rejectReason": "",
"qualityRating": "",
"updatedAt": "2026-01-15T12:59:05Z"
}
}
For all webhook payload formats see webhook_response.md.
Rate Limiting
- 200 requests per hour per API key
- HTTP
429returned when limit is exceeded