Message templates
Message templates are used to send structured, variable-driven messages outside the 24-hour free-form messaging window — primarily WhatsApp Business HSM templates that go through Meta moderation. The API covers template CRUD, submitting for approval (submit), archiving, and syncing approval status back from Meta.
Sending and variables
An approved template is sent to a contact via POST /messages/send-template (see the Messages group). Variables in the body are named — {{first_name}}, not {{1}} — and every one must be declared under parameters with a sample_value.
Logical template
For WhatsApp Business a "logical template" model applies: one template (by name/slug) can be rolled out across several WABA channels and languages — under the hood Aisar creates a separate instance per (channel × language) pair, and each one is submitted to Meta review independently.
Because of this, GET /v1/templates returns one row per logical group (template_group_id) with a logical_template aggregate: the overall Meta status plus a per-channel breakdown (meta_status / meta_status_reason / last_synced_at). Editing is master-content based — changes propagate to sibling instances of the same language. When a template is deleted, each WABA instance is also removed from Meta best-effort so a later sync cannot restore it.
Language versions
Language versions are managed separately from channels. POST /v1/templates/{template}/languages adds a new language (language, up to 12 chars; the body is the same content as on create: body, parameters, buttons, header/footer) to the logical group and creates one instance of that language for each already-assigned WABA channel of the group; if the group has no assigned channel yet it returns 422 ("assign a channel first"), and repeating an already-existing language also returns 422.
DELETE /v1/templates/{template}/languages/{language} removes all instances of that language (best-effort removing them from Meta), but refuses to delete the only remaining language — delete the whole template for that. Both responses return a versions aggregate — a flat list of the group instances shaped { id, language, channel_id, status, meta_status }.
Header media
An image, video or document header needs a file or a direct link to it. The recommended way is to upload the file via POST /v1/uploads and pass the returned media_id as header_media_id on create, update or when adding a language version. The file is stored in Aisar and attached automatically to every send of the template; template responses return it as header_media (media_id, filename, mime_type, size, preview_url). preview_url is a temporary signed link to the file (valid for 20 minutes, opens without a token) for showing a thumbnail; do not store it, a fresh one comes with every template response.
- Formats and size:
image— JPG or PNG up to 5 MB,video— MP4 or 3GPP up to 16 MB,document— PDF up to 100 MB. header_media_idandheader_media_urlare mutually exclusive: the one sent in the request replaces the other.header_media_id: nullremoves the file. Disabling the header or switching it totextclears both.header_media_urlmust point to the file itself at a public http(s) address (ports 80/443). Links to viewer pages (Google Drive/file/d/…/view, docs.google.com, Dropbox withoutdl=1/raw=1, Yandex Disk, yadi.sk, iCloud, Google Photos) are rejected: WhatsApp would receive an HTML page and fail the message with error 131053. An already saved link is not re-validated when other fields are edited.- Validation errors return
422underheader_media_id(unknown, foreign or expired file, wrong format or size) andheader_media_url. - Templates created in WhatsApp Manager and pulled in by sync arrive without a header file: upload one before sending. A broadcast with such a template will not start (
422, see the broadcasts section).
Endpoints
| Method | Path | Summary |
|---|---|---|
| GET | /v1/templatesList templates (one row per logical group) with pagination, search, and facets by status/language/channel type. | List templates (one row per logical group) with pagination, search, and facets by status/language/channel type. |
| GET | /v1/templates/channel-typesChannel types that templates can be created for. | Channel types that templates can be created for. |
| GET | /v1/templates/{template}Get a template by id (body, parameters, buttons) and its language versions. | Get a template by id (body, parameters, buttons) and its language versions. |
| GET | /v1/templates/{template}/channelsLogical-template availability across WABA channels: per channel — Meta status (`meta_status` / `meta_status_reason` / `last_synced_at`) and an `added` / `not_added` flag. | Logical-template availability across WABA channels: per channel — Meta status (`meta_status` / `meta_status_reason` / `last_synced_at`) and an `added` / `not_added` flag. |
| GET | /v1/templates/{template}/eventsEvent history of the logical group: created/updated, submitted to Meta, moderation results, published/archived (with channel and actor). | Event history of the logical group: created/updated, submitted to Meta, moderation results, published/archived (with channel and actor). |
| POST | /v1/templatesCreate a draft template. For WhatsApp Business you can pass `channel_ids` — Aisar creates one instance per selected WABA channel and submits each to Meta. | Create a draft template. For WhatsApp Business you can pass `channel_ids` — Aisar creates one instance per selected WABA channel and submits each to Meta. |
| PATCH | /v1/templates/{template}Update a draft template (changes propagate to sibling instances of the same language). | Update a draft template (changes propagate to sibling instances of the same language). |
| POST | /v1/templates/{template}Update a draft template (POST variant of PATCH). | Update a draft template (POST variant of PATCH). |
| POST | /v1/templates/{template}/channelsAssign a WhatsApp Business template to more channels; body `{ channel_ids: number[] }`. Creates one instance per new channel and submits published ones to Meta. | Assign a WhatsApp Business template to more channels; body `{ channel_ids: number[] }`. Creates one instance per new channel and submits published ones to Meta. |
| POST | /v1/templates/{template}/languagesAdd a language version to the logical template (WhatsApp Business): creates one instance of that language per already-assigned channel. | Add a language version to the logical template (WhatsApp Business): creates one instance of that language per already-assigned channel. |
| DELETE | /v1/templates/{template}/languages/{language}Delete a language version (all its instances; the only language cannot be deleted). Each WABA instance is also removed from Meta (best-effort). | Delete a language version (all its instances; the only language cannot be deleted). Each WABA instance is also removed from Meta (best-effort). |
| DELETE | /v1/templates/{template}Delete the template and every instance of the logical group. For WhatsApp Business each instance is also removed from Meta (best-effort). | Delete the template and every instance of the logical group. For WhatsApp Business each instance is also removed from Meta (best-effort). |
| POST | /v1/templates/{template}/submitSubmit/resubmit all assigned WABA channel instances of the template to Meta moderation. | Submit/resubmit all assigned WABA channel instances of the template to Meta moderation. |
| POST | /v1/templates/{template}/publishPublish an approved template (make it available for sending). | Publish an approved template (make it available for sending). |
| POST | /v1/templates/{template}/archiveArchive a template. | Archive a template. |
| POST | /v1/templates/{template}/unarchiveUnarchive a template. | Unarchive a template. |
| POST | /v1/templates/syncSync moderation statuses of all company WABA templates from Meta. | Sync moderation statuses of all company WABA templates from Meta. |
Examples
Create a WhatsApp Business template on several channels
Request
# channel_ids раскатывает шаблон на выбранные WABA-каналы: Aisar создаёт по
# экземпляру на каждый канал (и язык) и отправляет каждый в Meta. В ответе —
# представитель логической группы (template_group_id). Переменные — именованные.
curl -X POST "https://api.aisar.app/v1/templates" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_type": "whatsapp_business",
"channel_ids": [44, 45],
"name": "Order shipped",
"slug": "order_shipped",
"language": "ru",
"category": "utility",
"body": "Здравствуйте, {{first_name}}! Ваш заказ №{{order_number}} передан в доставку.",
"parameters": [
{ "name": "first_name", "type": "text", "sample_value": "Иван", "position": 1 },
{ "name": "order_number", "type": "text", "sample_value": "1045", "position": 2 }
]
}'Response
{
"data": {
"message": "Template created.",
"template": {
"id": 12,
"company_id": 1,
"template_group_id": 8,
"channel_type": { "id": 4, "key": "whatsapp_business", "name": "WhatsApp Business" },
"channel": { "id": 44, "name": "WABA — Sales", "account_name": "+1 202 555 01 70" },
"name": "Order shipped",
"slug": "order_shipped",
"status": "draft",
"meta_status": "local",
"meta_status_reason": null,
"last_synced_at": null,
"language": "ru",
"category": "utility",
"body": "Здравствуйте, {{first_name}}! Ваш заказ №{{order_number}} передан в доставку.",
"parameters": [
{ "id": 1, "name": "first_name", "type": "text", "sample_value": "Иван", "position": 1 },
{ "id": 2, "name": "order_number", "type": "text", "sample_value": "1045", "position": 2 }
],
"buttons": [],
"uses_count": 0,
"created_at": "2026-02-09T18:00:00Z",
"updated_at": "2026-02-09T18:00:00Z"
}
}
}List templates with filters, facets, and the logical_template aggregate
Request
curl -G "https://api.aisar.app/v1/templates" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
--data-urlencode "status=published" \
--data-urlencode "language=ru" \
--data-urlencode "channelType=whatsapp_business" \
--data-urlencode "sortBy=updated_at" \
--data-urlencode "sortDir=desc" \
--data-urlencode "includeFacets=true"Response
{
"data": {
"items": [
{
"id": 12,
"template_group_id": 8,
"name": "Order shipped",
"status": "published",
"meta_status": "approved",
"language": "ru",
"category": "utility",
"body": "Здравствуйте, {{first_name}}! Ваш заказ №{{order_number}} передан в доставку.",
"channel_type": { "id": 4, "key": "whatsapp_business", "name": "WhatsApp Business" },
"channel": { "id": 44, "name": "WABA — Sales", "account_name": "+1 202 555 01 70" },
"logical_template": {
"instances_count": 3,
"assigned_channels_count": 2,
"uses_count": 34,
"languages": ["kk", "ru"],
"channels": [
{
"id": 44,
"name": "WABA — Sales",
"account_name": "+1 202 555 01 70",
"meta_status": "approved",
"meta_status_reason": null,
"last_synced_at": "2026-05-15T20:40:00Z"
},
{
"id": 45,
"name": "WABA — Support",
"account_name": "+1 202 555 01 71",
"meta_status": "pending",
"meta_status_reason": null,
"last_synced_at": "2026-05-15T20:41:00Z"
}
],
"meta_status_counts": { "approved": 2, "pending": 1 },
"meta_overall_status": "pending"
},
"labels": ["orders"],
"send_params": [
{ "key": "first_name", "component": "body" },
{ "key": "order_number", "component": "body" }
],
"uses_count": 34,
"created_at": "2026-02-09T18:00:00Z",
"updated_at": "2026-02-10T09:15:00Z"
}
],
"pagination": { "page": 1, "perPage": 15, "total": 1, "lastPage": 1 },
"facets": {
"statuses": { "draft": 2, "published": 1, "archived": 0 },
"languages": { "ru": 3 },
"channel_types": { "whatsapp_business": 3 }
}
}
}Logical-template availability across channels
Request
curl -X GET "https://api.aisar.app/v1/templates/12/channels" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"items": [
{
"channel": {
"id": 44,
"name": "WABA — Sales",
"account_name": "+1 202 555 01 70",
"status": "connected",
"external_ids": {}
},
"template": {
"id": 12,
"external_id": "1180000000000012",
"status": "published",
"meta_status": "approved",
"meta_status_reason": null,
"last_synced_at": "2026-05-15T20:40:00Z"
},
"availability": "added"
},
{
"channel": {
"id": 46,
"name": "WABA — Marketing",
"account_name": "+1 202 555 01 72",
"status": "connected",
"external_ids": {}
},
"template": null,
"availability": "not_added"
}
]
}
}Assign the template to an additional WABA channel
Request
curl -X POST "https://api.aisar.app/v1/templates/12/channels" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "channel_ids": [46] }'Response
{
"data": {
"message": "Template channels updated.",
"items": [
{
"channel": { "id": 44, "name": "WABA — Sales", "account_name": "+1 202 555 01 70", "status": "connected", "external_ids": {} },
"template": { "id": 12, "external_id": "1180000000000012", "status": "published", "meta_status": "approved", "meta_status_reason": null, "last_synced_at": "2026-05-15T20:40:00Z" },
"availability": "added"
},
{
"channel": { "id": 46, "name": "WABA — Marketing", "account_name": "+1 202 555 01 72", "status": "connected", "external_ids": {} },
"template": { "id": 27, "external_id": null, "status": "published", "meta_status": "local", "meta_status_reason": null, "last_synced_at": null },
"availability": "added"
}
]
}
}Event history of the logical template
Request
curl -X GET "https://api.aisar.app/v1/templates/12/events" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"items": [
{
"id": 210,
"type": "meta_approved",
"meta_status": "approved",
"reason": null,
"metadata": null,
"channel": { "id": 44, "name": "WABA — Sales", "account_name": "+1 202 555 01 70" },
"actor": null,
"created_at": "2026-05-15T20:40:00Z"
},
{
"id": 208,
"type": "submitted",
"meta_status": null,
"reason": null,
"metadata": null,
"channel": { "id": 44, "name": "WABA — Sales", "account_name": "+1 202 555 01 70" },
"actor": { "id": 3, "name": "Айгуль Смагулова" },
"created_at": "2026-05-15T18:05:00Z"
},
{
"id": 205,
"type": "created",
"meta_status": null,
"reason": null,
"metadata": null,
"channel": { "id": 44, "name": "WABA — Sales", "account_name": "+1 202 555 01 70" },
"actor": { "id": 3, "name": "Айгуль Смагулова" },
"created_at": "2026-05-15T18:00:00Z"
}
]
}
}Template with a header, footer, and buttons
Request
curl -X POST "https://api.aisar.app/v1/templates" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_type": "whatsapp_business",
"name": "Appointment reminder",
"slug": "appointment_reminder",
"language": "ru",
"category": "utility",
"body": "Здравствуйте, {{first_name}}! Напоминаем о записи {{appointment_at}}.",
"header_enabled": true,
"header_type": "text",
"header_text": "Напоминание о визите",
"footer_enabled": true,
"footer_text": "Клиника «Ромашка»",
"buttons_enabled": true,
"labels": ["reminders"],
"parameters": [
{ "name": "first_name", "type": "text", "sample_value": "Айгуль", "position": 1 },
{ "name": "appointment_at", "type": "text", "sample_value": "12 марта, 10:00", "position": 2 }
],
"buttons": [
{ "type": "quick_reply", "label": "Подтвердить", "value": null, "position": 1 },
{ "type": "url", "label": "Перенести", "value": "https://example.com/appointments/{{1}}", "position": 2 },
{ "type": "phone", "label": "Позвонить", "value": "+1 202 555 01 59", "position": 3 }
]
}'Response
{
"data": {
"message": "Template created.",
"template": {
"id": 15,
"company_id": 1,
"template_group_id": 9,
"channel_type": { "id": 4, "key": "whatsapp_business", "name": "WhatsApp Business" },
"channel": null,
"name": "Appointment reminder",
"slug": "appointment_reminder",
"status": "draft",
"meta_status": null,
"meta_status_reason": null,
"last_synced_at": null,
"language": "ru",
"category": "utility",
"body": "Здравствуйте, {{first_name}}! Напоминаем о записи {{appointment_at}}.",
"header_enabled": true,
"header_type": "text",
"header_text": "Напоминание о визите",
"header_media": null,
"header_media_url": null,
"footer_enabled": true,
"footer_text": "Клиника «Ромашка»",
"buttons_enabled": true,
"labels": ["reminders"],
"parameters": [
{ "id": 5, "name": "first_name", "type": "text", "sample_value": "Айгуль", "position": 1 },
{ "id": 6, "name": "appointment_at", "type": "text", "sample_value": "12 марта, 10:00", "position": 2 }
],
"buttons": [
{ "id": 7, "type": "quick_reply", "label": "Подтвердить", "value": null, "position": 1 },
{ "id": 8, "type": "url", "label": "Перенести", "value": "https://example.com/appointments/{{1}}", "position": 2 },
{ "id": 9, "type": "phone", "label": "Позвонить", "value": "+1 202 555 01 59", "position": 3 }
],
"uses_count": 0,
"created_at": "2026-03-01T08:00:00Z",
"updated_at": "2026-03-01T08:00:00Z"
}
}
}Template with an uploaded media header
Request
curl -X POST "https://api.aisar.app/v1/templates" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_type": "whatsapp_business",
"name": "Promotion with image",
"slug": "promo_with_image",
"language": "ru",
"category": "marketing",
"body": "Здравствуйте, {{first_name}}! Ознакомьтесь с нашим новым каталогом.",
"header_enabled": true,
"header_type": "image",
"header_media_id": "med_01arc7z0z0000000001234567",
"footer_enabled": true,
"footer_text": "Интернет-магазин",
"parameters": [
{ "name": "first_name", "type": "text", "sample_value": "Мария", "position": 1 }
]
}'Response
{
"data": {
"message": "Template created.",
"template": {
"id": 20,
"company_id": 1,
"template_group_id": 10,
"channel_type": { "id": 4, "key": "whatsapp_business", "name": "WhatsApp Business" },
"channel": null,
"name": "Promotion with image",
"slug": "promo_with_image",
"status": "draft",
"meta_status": null,
"meta_status_reason": null,
"last_synced_at": null,
"language": "ru",
"category": "marketing",
"body": "Здравствуйте, {{first_name}}! Ознакомьтесь с нашим новым каталогом.",
"header_enabled": true,
"header_type": "image",
"header_text": null,
"header_media": {
"media_id": "med_01arc7z0z0000000001234567",
"filename": "catalog-march-2026.jpg",
"mime_type": "image/jpeg",
"size": 2457600,
"preview_url": "https://api.aisar.app/v1/media/template-header/01ARC7Z0Z0000000001234567?company=42&expires=1791180000&signature=…"
},
"header_media_url": null,
"footer_enabled": true,
"footer_text": "Интернет-магазин",
"buttons_enabled": false,
"labels": [],
"parameters": [
{ "id": 42, "name": "first_name", "type": "text", "sample_value": "Мария", "position": 1 }
],
"buttons": [],
"uses_count": 0,
"created_at": "2026-03-02T10:00:00Z",
"updated_at": "2026-03-02T10:00:00Z"
}
}
}Submit a template for moderation
Request
curl -X POST "https://api.aisar.app/v1/templates/12/submit" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"message": "Template submitted to Meta.",
"submitted_count": 2,
"items": [
{
"channel": { "id": 44, "name": "WABA — Sales", "account_name": "+1 202 555 01 70", "status": "connected", "external_ids": {} },
"template": { "id": 12, "external_id": null, "status": "published", "meta_status": "local", "meta_status_reason": null, "last_synced_at": null },
"availability": "added"
},
{
"channel": { "id": 45, "name": "WABA — Support", "account_name": "+1 202 555 01 71", "status": "connected", "external_ids": {} },
"template": { "id": 20, "external_id": null, "status": "published", "meta_status": "local", "meta_status_reason": null, "last_synced_at": null },
"availability": "added"
}
]
}
}Publish, archive, and unarchive
Request
# Публикация одобренного шаблона (архивирование/разархивирование — аналогично, тело пустое)
curl -X POST "https://api.aisar.app/v1/templates/12/publish" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"message": "Template status updated.",
"template": {
"id": 12,
"status": "published"
}
}
}Add a language version to a template
Request
curl -X POST "https://api.aisar.app/v1/templates/12/languages" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"language": "en",
"body": "Hello, {{first_name}}! Your order #{{order_number}} has been shipped.",
"parameters": [
{ "name": "first_name", "type": "text", "sample_value": "John", "position": 1 },
{ "name": "order_number", "type": "text", "sample_value": "1045", "position": 2 }
]
}'Response
{
"data": {
"message": "Template language version created.",
"template": {
"id": 30,
"company_id": 1,
"template_group_id": 8,
"channel_type": { "id": 4, "key": "whatsapp_business", "name": "WhatsApp Business" },
"channel": { "id": 44, "name": "WABA — Sales", "account_name": "+1 202 555 01 70" },
"name": "Order shipped",
"slug": "order_shipped",
"status": "draft",
"meta_status": "local",
"language": "en",
"category": "utility",
"body": "Hello, {{first_name}}! Your order #{{order_number}} has been shipped.",
"parameters": [
{ "id": 40, "name": "first_name", "type": "text", "sample_value": "John", "position": 1 },
{ "id": 41, "name": "order_number", "type": "text", "sample_value": "1045", "position": 2 }
],
"buttons": [],
"uses_count": 0,
"created_at": "2026-03-01T09:00:00Z",
"updated_at": "2026-03-01T09:00:00Z"
},
"versions": [
{ "id": 12, "language": "ru", "channel_id": 44, "status": "published", "meta_status": "approved" },
{ "id": 20, "language": "ru", "channel_id": 45, "status": "published", "meta_status": "pending" },
{ "id": 30, "language": "en", "channel_id": 44, "status": "draft", "meta_status": "local" },
{ "id": 31, "language": "en", "channel_id": 45, "status": "draft", "meta_status": "local" }
]
}
}Delete a language version of a template
Request
curl -X DELETE "https://api.aisar.app/v1/templates/12/languages/en" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"message": "Template language version deleted.",
"versions": [
{ "id": 12, "language": "ru", "channel_id": 44, "status": "published", "meta_status": "approved" },
{ "id": 20, "language": "ru", "channel_id": 45, "status": "published", "meta_status": "pending" }
]
}
}