Message templates
Create an official WABA template through Gateway API — POST /templates/. Use lowercase [a-z0-9_] for name. body_text is required; header_text/footer_text are optional. channel_id goes in the request body. The response is always PENDING: Meta’s APPROVED/REJECTED decision arrives asynchronously in the templates stream or a later GET /templates/ response:
curl -X POST https://dialogs.tehprof.kz/api/v1/gw/templates/ \
-H "Authorization: Bearer gw_xxx" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 32,
"name": "order_shipped",
"language": "en",
"category": "UTILITY",
"body_text": "Order {{1}} shipped, courier {{2}}.",
"footer_text": "TehProf.kz"
}'
201 { "template_id": "123", "status": "PENDING" }List templates — GET /templates/?channel_id=. From the synced mirror, no live Meta call. Each status is APPROVED | PENDING | REJECTED | PAUSED | DISABLED — only APPROVED can be sent via template:
curl "https://dialogs.tehprof.kz/api/v1/gw/templates/?channel_id=32" \
-H "Authorization: Bearer gw_xxx"
{
"templates": [
{
"template_id": "123",
"name": "order_shipped",
"language": "en",
"status": "APPROVED",
"category": "UTILITY",
"rejection_reason": "",
"quality_rating": "GREEN",
"components": [ { "type": "BODY", "text": "Order {{1}} shipped, courier {{2}}." } ]
}
]
}Edit a template — PATCH /templates/<id>/. Trap: Meta replaces components WHOLESALE. An edit without body_text (header_text/footer_text alone) silently changes nothing, while body_text without header/footer WIPES the existing HEADER and FOOTER. The rule: when you edit text, send all three text fields together. name and language are immutable; an edit re-triggers review, the verdict arrives on the templates stream. channel_id in the body:
curl -X PATCH https://dialogs.tehprof.kz/api/v1/gw/templates/123/ \
-H "Authorization: Bearer gw_xxx" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 32,
"body_text": "Order {{1}} delivered.",
"header_text": "TehProf.kz",
"footer_text": "Thank you"
}'
200 { "template_id": "123", "status": "APPROVED" }Delete — DELETE /templates/<id>/?channel_id=. Note: channel_id is in the query here, not the body (unlike PATCH). The response is 204 with no body. A deleted APPROVED template’s name is reserved for 30 days — “delete then re-create” is not an edit strategy, use PATCH:
curl -X DELETE "https://dialogs.tehprof.kz/api/v1/gw/templates/123/?channel_id=32" \
-H "Authorization: Bearer gw_xxx"
204 No ContentTemplate health — GET /templates/<id>/health/?channel_id=. A live pre-flight at Meta: a template can fail AFTER the 201 (e.g. the WABA has no billing), so ask health BEFORE sending rather than judging by the code. can_send: available | limited | blocked; when not available, reasons carries the error text and fix per entity (the phone number, the WABA, the business, the app, the template):
curl "https://dialogs.tehprof.kz/api/v1/gw/templates/123/health/?channel_id=32" \
-H "Authorization: Bearer gw_xxx"
200 {
"can_send": "blocked",
"reasons": [
{
"code": "141006",
"description": "There is an error with the payment method...",
"solution": "Add a new payment method to the account.",
"entity": "WABA"
}
]
}