WhatsApp Templates API
Create and send WhatsApp message templates programmatically for meta-direct companies.
Authentication
Every request must include an X-API-KEY header
containing your company's API secret. This authenticates and identifies your company — no company ID is needed in the URL.
X-API-KEY: your-api-secret
Always include Accept: application/json
Without this header, Laravel treats the request as a browser request. Any error (validation failure, auth issue) will return an HTML redirect instead of a JSON error response — making debugging impossible in Postman or curl.
Base URL
https://hooks.chatworks.co.za/api
Create Template
/api/templates/whatsapp-templates
Creates a new WhatsApp template in a single request. If the header is a media file, you can upload
it inline — no separate upload call is required. Set auto_submit=true
to also submit the template to Meta for approval in the same call.
Content-Type: multipart/form-data
Request Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | Lowercase letters, digits and underscores only. Unique per company. |
| display_name | string | yes | Human-readable label. Max 255 chars. |
| category | string | yes | marketing · utility · authentication |
| language | string | yes | BCP-47 code, e.g. en, en_US, af. |
| body | string | yes | Template body text. Max 1024 chars. Use {{1}}, {{2}} for variables. |
| header_type | string | no | none · text · image · video · document |
| header_content | string | conditional | Text value when header_type=text (max 60 chars). Pre-uploaded file handle when header_type is a media type and you already have a handle. |
| header_file | file | conditional | Raw file upload for media headers. Alternative to passing a pre-uploaded header_content handle. Max 20 MB. |
| footer | string | no | Footer text. Max 60 chars. Not allowed for authentication templates. |
| buttons | array | no | Up to 10 buttons for marketing/utility; 1 button for authentication. |
| auto_submit | boolean | no | Submits to Meta immediately after creation. Status is set to pending. Default: draft only. Use 1 for true and 0 for false — string values like true/false are not accepted. |
| add_security_recommendation | boolean | no | Authentication templates only. |
| code_expiry_minutes | integer | no | Authentication templates only. 1–90 minutes. |
cURL Samples
No Header — draft only
curl --location 'https://hooks.chatworks.co.za/api/templates/whatsapp-templates' \
--header 'X-API-KEY: your-api-secret' \
--header 'Accept: application/json' \
--form 'name=order_confirmed' \
--form 'display_name=Order Confirmed' \
--form 'category=utility' \
--form 'language=en' \
--form 'body=Hello {{1}}, your order {{2}} has been confirmed.' \
--form 'auto_submit=0'
Text Header — submit immediately
curl --location 'https://hooks.chatworks.co.za/api/templates/whatsapp-templates' \
--header 'X-API-KEY: your-api-secret' \
--header 'Accept: application/json' \
--form 'name=promo_launch' \
--form 'display_name=Promo Launch' \
--form 'category=marketing' \
--form 'language=en_US' \
--form 'header_type=text' \
--form 'header_content=Big Sale This Weekend' \
--form 'body=Hi {{1}}, use code {{2}} for 20% off.' \
--form 'footer=Reply STOP to unsubscribe' \
--form 'auto_submit=1'
Use auto_submit=1 to submit to Meta immediately, or auto_submit=0 to save as draft and submit later.
Media Header — raw file upload
curl --location 'https://hooks.chatworks.co.za/api/templates/whatsapp-templates' \
--header 'X-API-KEY: your-api-secret' \
--header 'Accept: application/json' \
--form 'name=product_showcase' \
--form 'display_name=Product Showcase' \
--form 'category=marketing' \
--form 'language=en' \
--form 'header_type=image' \
--form 'header_file=@/path/to/banner.jpg' \
--form 'body=Check out our new product, {{1}}!' \
--form 'auto_submit=0'
Replace @/path/to/banner.jpg with the actual file path. In Postman, set header_file as type File in the form-data body.
Alternatively pass a pre-uploaded handle as header_content instead of header_file.
Success Response 201 Created
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000", // UUID — use this for submit
"name": "order_confirmed",
"display_name": "Order Confirmed",
"category": "utility",
"language": "en",
"status": "draft", // "pending" when auto_submit=true and submission succeeded
"header_type": null,
"header_content": null,
"body": "Hello {{1}}, your order {{2}} has been confirmed.",
"footer": null,
"buttons": null,
"wa_template_id": null, // populated when auto_submit=true
"created_at": "2026-05-13T10:00:00.000000Z",
"updated_at": "2026-05-13T10:00:00.000000Z"
},
"wa_template_id": null // Meta's template ID when auto_submit=true
}
Submit Template for Approval
/api/templates/whatsapp-templates/{uuid}/submit
Submits a template to Meta for approval. Use this when a template was created without
auto_submit=true,
or to re-submit a rejected template after corrections.
Templates in any status (draft,
rejected,
pending) can be submitted.
On success the status is updated to pending.
URL Parameter
| Parameter | Type | Notes |
|---|---|---|
| {uuid} | UUID | The id value returned by the Create Template endpoint. |
cURL Sample
curl --location --request POST \
'https://hooks.chatworks.co.za/api/templates/whatsapp-templates/550e8400-e29b-41d4-a716-446655440000/submit' \
--header 'X-API-KEY: your-api-secret' \
--header 'Accept: application/json'
Replace the UUID with the id returned when the template was created.
Success Response 200 OK
{
"message": "Template submitted for approval.",
"wa_template_id": "123456789"
}
Delete Template
/api/templates/whatsapp-templates/{uuid}
Deletes a template from Meta and soft-deletes the local record.
The template must have a wa_template_id
(i.e. it must have been submitted at least once). Drafts that were never submitted can be discarded
without calling this endpoint.
This action is irreversible. Once deleted from Meta the template cannot be recovered.
URL Parameter
| Parameter | Type | Notes |
|---|---|---|
| {uuid} | UUID | The id returned by the Create Template endpoint. |
cURL Sample
curl --location --request DELETE \
'https://hooks.chatworks.co.za/api/templates/whatsapp-templates/550e8400-e29b-41d4-a716-446655440000' \
--header 'X-API-KEY: your-api-secret' \
--header 'Accept: application/json'
Replace the UUID with the id returned when the template was created.
Success Response 200 OK
{ "message": "Template deleted." }
Error — not submitted to Meta yet 422
{ "error": "Template has not been submitted to Meta yet — nothing to delete remotely." }
Send Template Message
/api/templates/whatsapp-templates/send
Sends an approved WhatsApp template message to a recipient phone number. You can identify the template by its local database ID (recommended — name and language are resolved automatically) or by passing the template name and language directly.
Content-Type: application/json or multipart/form-data
Request Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| to | string | yes | Recipient phone number. Any format — non-digits are stripped and + is prepended automatically. E.g. 27821234567. |
| template_id | integer | one of | Local database ID of an approved template. Name and language are resolved automatically. Required unless template_name is provided. |
| template_name | string | one of | Exact snake_case template name. Required unless template_id is provided. |
| language | string | no | BCP-47 code. Default: en. Ignored when template_id is supplied. |
| body_values | string[] | no | Ordered values for body variables {{1}}, {{2}} … Index 0 maps to {{1}}. |
| header_values | string[] | no | Ordered values for text-header variables. Only relevant when the template has a text header with variables. |
| header_type | string | no | none (default) · text. Pass text together with header_values when the template has a text header with variables. |
cURL Samples
By template_id (recommended)
curl --location 'https://hooks.chatworks.co.za/api/templates/whatsapp-templates/send' \
--header 'X-API-KEY: your-api-secret' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"to": "27821234567",
"template_id": 42,
"body_values": ["John", "ORD-9981"]
}'
By template_name with text header variables
curl --location 'https://hooks.chatworks.co.za/api/templates/whatsapp-templates/send' \
--header 'X-API-KEY: your-api-secret' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"to": "27821234567",
"template_name": "promo_launch",
"language": "en_US",
"header_type": "text",
"header_values": ["Weekend Sale"],
"body_values": ["John", "SAVE20"]
}'
Success Response 200 OK
{
"message": "Template message sent."
}
Reference — All Fields
Button object (Create Template)
| Field | Required | Notes |
|---|---|---|
| type | yes |
Marketing/Utility: URL · PHONE_NUMBER · QUICK_REPLY · COPY_CODEAuthentication: COPY_CODE · ONE_TAP
|
| text | yes | Button label. Max 25 chars. |
| url | URL type | Valid URL. Required when type=URL. |
| phone_number | PHONE type | Required when type=PHONE_NUMBER. |
Authentication category restrictions
When category=authentication, the fields
header_type,
header_content,
header_file, and
footer are prohibited.
buttons is limited to a single item of type
COPY_CODE or ONE_TAP.
Error Responses
| Status | Cause | Body |
|---|---|---|
| 401 | Missing or invalid X-API-KEY |
{"error": "Unauthorized"} |
| 422 | Validation failed or non-meta-direct company | {"error": "...", "message": "..."} |
| 404 | Template not found or not approved (send endpoint) | {"error": "Template not found or not approved."} |
| 500 | Meta API call failed | {"error": "Failed to send template message.", "detail": "..."} |