Channels
A channel is a connected messaging source: WhatsApp, Telegram, Instagram, SIP telephony, etc. Through the public REST API you read the channel list and its connection state, manage the lifecycle of an already-connected channel (pause/resume/reconnect/disconnect), and configure operator access rules for it. Connecting and initial provisioning happen through the wizard in the client dashboard, not through this API.
Connecting a channel
Connecting and provisioning a new channel (QR pairing, Meta OAuth, SIP setup) happens through the onboarding wizard in the client dashboard (my.aisar.app/settings/channels/add) rather than directly through this API — the wizard uses separate, provider-specific setup endpoints.
Lifecycle
A channel lifecycle is expressed by two fields:
setup_state(draft → pairing → ready | failed) — the initial setup stage.status(connected | disconnected | connecting | reconnecting | paused | expired | banned) — the current state of an already-configured channel.bannedis not terminal: once the provider lifts the account ban, the channel can be reconnected via the regular reconnect/pairing flow; if the ban still stands, the provider rejects the connection and the channel returns tobanned.
WhatsApp number profile
The avatar and profile texts are read and changed through /v1/channels/{channel}/whatsapp/profile. Which fields are available depends on the connection rather than on the channel type, so the response always carries capabilities: WhatsApp Business exposes about, description, address, email, websites and category, while a QR-connected WhatsApp exposes the photo and about, with a description only when the number runs the WhatsApp Business app. Branch on capabilities and limits from the response: sending an unsupported field rejects the whole request instead of applying it in part.
WhatsApp blocked users
GET /channels/{channel}/whatsapp/blocked-users (since 2026-09-04) reads the list of numbers the PROVIDER itself has blocked on this channel — it is not AISAR's own blocked-contact list (that is managed by POST /contacts/{contact}/block and /unblock, see the "Contacts" group). The shape of numbers[] depends on the connection: WhatsApp Business (Cloud API) returns the provider's number format (e.g. +77001111111), QR-based WhatsApp (whatsmeow) returns a WhatsApp JID (e.g. 77009998877@s.whatsapp.net). Pagination is cursor-based: pass after set to the previous response's next_cursor to get the next page; next_cursor: null means the end of the list. limit ranges 1–1000, default 100.
Available only for WhatsApp channels (whatsapp/whatsapp_business) — a channel of another type returns 422 {error_code: "channel_not_whatsapp"}; a disconnected channel returns 409 {error_code: "channel_offline"}. Authorization is the channel:view permission (not contact:update, unlike block/unblock) — this reads channel state rather than acting on a contact; a foreign channel returns 403.
Temporary SIP-trunk outbound hold (`sip_outbound_gated`)
A sip_telephony channel connected via the operator equipment's IP address (see the channel-connection guide, "SIP telephony (BYO trunk)" section) may have its outbound calls temporarily held if the same address is already in use by another AISAR company with the same operator. This is reflected in the boolean sip_outbound_gated field — present on EVERY channel (not just sip_telephony), false when no hold applies. While sip_outbound_gated: true, the channel still accepts inbound calls, but POST /calls/originate and POST /softphone/external-call behave as if the company had no connected SIP channel at all. The hold lifts automatically, with no endpoint call needed, as soon as the channel's number receives its first confirmed inbound call.
Archived channels
A channel deleted with its history kept (DELETE /channels/{channel} without keep_history=false — the default, see below) does not disappear: it is soft-deleted, stamped with archived_at, and its conversation history stays readable inside AISAR. The regular GET /channels never returns it, and there is no parameter that puts it back in that list — include_archived is not part of GET /channels validation, so any value for it is silently ignored. The only way to see an archived channel is the separate GET /channels/archived list.
GET /channels/archived returns the same ChannelListResource as the regular list, with archived_at and messages_count filled in (the channel's message count, including messages later deleted individually). The moment of archiving is marked by the channel.archived webhook event (see the webhook events reference) — this list is where the channel that event notified you about can be found afterwards. GET /channels/{channel} by an archived channel's id returns 404 — that is expected (route-model binding does not resolve a soft-deleted model), not a sign that the channel was lost.
Permanently and irreversibly deleting an archived channel together with its history is DELETE /channels/archived/{channelId} (channelId is a plain integer: a soft-deleted channel is not resolved via route-model binding, so the path takes the id directly rather than {channel}). A 200 response means the deletion was queued as a background job, not that it has already finished.
Lifecycle request bodies
Pause/resume/disconnect take no request body, whereas reconnect (POST /channels/{channel}/reconnect) accepts a provider-specific body for OAuth/bot channels (Instagram/Threads — { code }, WhatsApp Business — { authorization_code, waba_id, phone_number_id }, Telegram Bot — { bot_token }), otherwise 422; WhatsApp/Telegram QR and Live Chat take an empty body. The full per-type contract is covered in the partner documentation (channel-connection guide, "Direct API" section).
provider_key and channel type
The provider_key field is a public, neutral provider identifier; internal runtime-library names are never exposed. The full list of values and the QR-channel mapping rules live in the «Types: messaging» reference, the Channel type. To distinguish the channel type in code, rely on channel_type.key rather than the display name.
Channel log pagination
GET /channels/{channel}/logs is paginated: page/per_page (the perPage alias is accepted too), capped at 500, defaulting to 200. Until 2026-08-25 the endpoint silently ignored every paging parameter and always returned the newest 200 rows — there was no way to look further back into the history. Sorting is created_at desc, then id desc: the runtime writes bursts of log rows within the same second, and without the id tiebreaker the same row could repeat on one page and vanish from another. The response is wrapped like other paginated lists: items in data, paging info in meta (current_page, last_page, per_page, total); the shape of an individual log entry is unchanged.
Send-failure codes in the channel log
Besides connection codes (connection.ready, connection.lost, etc.), GET /channels/{channel}/logs (since 2026-08-26) records two outbound-message-fate entries. message.send.failed.{error_code} — error level: one entry per send that exhausted all retries (not per attempt, or a broadcast would flood the channel log), {error_code} is the last attempt's error code or unknown; context carries message_id, attempts, error_code and a truncated response (only reason/status/response from the runtime/provider response — the runtime's internal address is stripped from response for security reasons). message.status.failed_suppressed — warning level: the provider sent a failure receipt AFTER the message had already reached delivered/read/played — the message's status is not downgraded (see the message.status.updated event), but the provider-side failure is still recorded here; context carries message_id and reason (a human-readable cause).
sip_status in the eligibility response
sip_status inside eligibility.calling (in the GET .../whatsapp-calling response, and also POST .../whatsapp-calling/enable|disable) is an AISAR-derived field, not Meta's raw status: ENABLED once calling is turned on for the channel (config.calling_did is set), NOT_SET when calling isn't enabled, UNKNOWN when the Graph API call itself failed (see the top-level unknown_reason/detail). To decide whether calling is actually available right now, rely on active (true only when can_receive_call_sip === "AVAILABLE") and can_receive_call_sip itself — both always reflect Meta's current state, while sip_status is a local mirror of AISAR's last successful enable/disable and can miss a change made directly in WhatsApp Manager.
Endpoints
| Method | Path | Summary |
|---|---|---|
| GET | /v1/channelsList the company's channels (setup drafts excluded by default). | List the company's channels (setup drafts excluded by default). |
| GET | /v1/channels/{channel}Get a channel by id along with its provider configuration. | Get a channel by id along with its provider configuration. |
| POST | /v1/channelsCreate a channel (optionally starting pairing right away); channels are usually connected through the in-dashboard wizard. | Create a channel (optionally starting pairing right away); channels are usually connected through the in-dashboard wizard. |
| PATCH | /v1/channels/{channel}Update channel settings: name, description, account_name and the allow_broadcasts / allow_automations / allow_inbound_handling toggles. POST and PUT on this path are accepted too. | Update channel settings: name, description, account_name and the allow_broadcasts / allow_automations / allow_inbound_handling toggles. POST and PUT on this path are accepted too. |
| GET | /v1/channel-typesReference list of channel types with their capabilities and providers. | Reference list of channel types with their capabilities and providers. |
| POST | /v1/channels/{channel}/connect/startStart connecting a runtime channel (WhatsApp/Telegram/Instagram via QR): body { "mode": "qr" | "code" | "phone", "phone_number"? }. Then poll GET /channels/{channel}/connection. | Start connecting a runtime channel (WhatsApp/Telegram/Instagram via QR): body { "mode": "qr" | "code" | "phone", "phone_number"? }. Then poll GET /channels/{channel}/connection. |
| GET | /v1/channels/{channel}/connectionConnection-state snapshot for polling a custom QR UI: connection.status (draft, qr_required, pairing_required, authorizing, 2fa_required, connected, reconnecting, expired, error, disconnected), a qr object, pairing_code (for code mode), and pairing_state. | Connection-state snapshot for polling a custom QR UI: connection.status (draft, qr_required, pairing_required, authorizing, 2fa_required, connected, reconnecting, expired, error, disconnected), a qr object, pairing_code (for code mode), and pairing_state. |
| POST | /v1/channels/{channel}/auth-codeSubmit an SMS code or a 2FA password to the runtime (Telegram Personal login). | Submit an SMS code or a 2FA password to the runtime (Telegram Personal login). |
| POST | /v1/channels/{channel}/disconnectDisconnect a channel (stop sending/receiving messages). | Disconnect a channel (stop sending/receiving messages). |
| POST | /v1/channels/{channel}/reconnectReconnect a previously disconnected channel. The request body depends on the channel type: OAuth/bot channels require provider fields (Instagram/Threads — { code }, WhatsApp Business — { authorization_code, waba_id, phone_number_id }, Telegram Bot — { bot_token }), otherwise 422; WhatsApp/Telegram QR and Live Chat take an empty body. Requires channel:update; a foreign channel returns 404. Full per-type contract — in the partner documentation (channel-connection guide, "Direct API" section). | Reconnect a previously disconnected channel. The request body depends on the channel type: OAuth/bot channels require provider fields (Instagram/Threads — { code }, WhatsApp Business — { authorization_code, waba_id, phone_number_id }, Telegram Bot — { bot_token }), otherwise 422; WhatsApp/Telegram QR and Live Chat take an empty body. Requires channel:update; a foreign channel returns 404. Full per-type contract — in the partner documentation (channel-connection guide, "Direct API" section). |
| POST | /v1/channels/{channel}/pausePause a channel (temporarily, without tearing down the session). | Pause a channel (temporarily, without tearing down the session). |
| POST | /v1/channels/{channel}/resumeResume a paused channel. | Resume a paused channel. |
| DELETE | /v1/channels/{channel}Delete a channel (soft delete). By default (`keep_history` omitted or `true`) the conversation history is kept and the channel becomes archived — retrievable via GET /channels/archived; `keep_history=false` deletes the channel together with its history for good. | Delete a channel (soft delete). By default (`keep_history` omitted or `true`) the conversation history is kept and the channel becomes archived — retrievable via GET /channels/archived; `keep_history=false` deletes the channel together with its history for good. |
| GET | /v1/channels/archivedArchived channels — deleted with history kept (see "Archived channels" above). Not returned by the regular list; there is no parameter that adds them back. | Archived channels — deleted with history kept (see "Archived channels" above). Not returned by the regular list; there is no parameter that adds them back. |
| DELETE | /v1/channels/archived/{channelId}Permanently and irreversibly delete an archived channel together with its history (runs as a background job). | Permanently and irreversibly delete an archived channel together with its history (runs as a background job). |
| GET | /v1/channels/{channel}/logsChannel logs (connection events, errors), paginated: `page`/`per_page` (`perPage` accepted too; max 500, default 200), sorted by `created_at` desc, then `id` desc. | Channel logs (connection events, errors), paginated: `page`/`per_page` (`perPage` accepted too; max 500, default 200), sorted by `created_at` desc, then `id` desc. |
| GET | /v1/channels/{channel}/whatsapp-callingWhatsApp calling readiness (eligibility): Meta prerequisites and blocking issues. Meta/WABA channels only (otherwise 404); requires telephony-management rights (otherwise 403). | WhatsApp calling readiness (eligibility): Meta prerequisites and blocking issues. Meta/WABA channels only (otherwise 404); requires telephony-management rights (otherwise 403). |
| POST | /v1/channels/{channel}/whatsapp-calling/enableEnable WhatsApp calling for the number. Meta/WABA channels, telephony rights. Unmet prerequisites return HTTP 422 with ok:false and error_code. | Enable WhatsApp calling for the number. Meta/WABA channels, telephony rights. Unmet prerequisites return HTTP 422 with ok:false and error_code. |
| POST | /v1/channels/{channel}/whatsapp-calling/disableDisable WhatsApp calling for the number. Meta/WABA channels, telephony rights. | Disable WhatsApp calling for the number. Meta/WABA channels, telephony rights. |
| GET | /v1/channels/{channel}/whatsapp/profileThe WhatsApp number's profile: the avatar and the texts a contact sees on the business card. The response carries `capabilities` — the fields this particular channel supports — and `limits` with length ceilings; branch on those, not on the channel type. When the provider is unreachable, the last saved copy is returned with `stale: true`. Requires channel:view. | The WhatsApp number's profile: the avatar and the texts a contact sees on the business card. The response carries `capabilities` — the fields this particular channel supports — and `limits` with length ceilings; branch on those, not on the channel type. When the provider is unreachable, the last saved copy is returned with `stale: true`. Requires channel:view. |
| POST | /v1/channels/{channel}/whatsapp/profileUpdate the number's profile. Send only what changes; a field the channel does not support rejects the whole request with HTTP 422 and `field_not_supported`. The avatar goes as a multipart `picture` file (JPG/PNG/WebP, up to 5 MB, at least 192 px per side) — we crop it to a square and strip the capture metadata ourselves. `about` cannot be empty. Requires channel:update; the change rate is limited. | Update the number's profile. Send only what changes; a field the channel does not support rejects the whole request with HTTP 422 and `field_not_supported`. The avatar goes as a multipart `picture` file (JPG/PNG/WebP, up to 5 MB, at least 192 px per side) — we crop it to a square and strip the capture metadata ourselves. `about` cannot be empty. Requires channel:update; the change rate is limited. |
| DELETE | /v1/channels/{channel}/whatsapp/profile/pictureClear the number's avatar. Not supported by every provider: check `capabilities.picture_remove` in the GET response — a WhatsApp Business photo can only be replaced. Requires channel:update. | Clear the number's avatar. Not supported by every provider: check `capabilities.picture_remove` in the GET response — a WhatsApp Business photo can only be replaced. Requires channel:update. |
| GET | /v1/channels/{channel}/whatsapp/blocked-usersList of numbers the provider has blocked on this WhatsApp channel (query: after, limit) — not AISAR's own blocked-contact list. WhatsApp channels only; requires channel:view. | List of numbers the provider has blocked on this WhatsApp channel (query: after, limit) — not AISAR's own blocked-contact list. WhatsApp channels only; requires channel:view. |
| GET | /v1/channels/{channel}/accessOperator/team access rules for the channel. | Operator/team access rules for the channel. |
| POST | /v1/channels/{channel}/accessUpdate channel access rules (allow/block per team or user). | Update channel access rules (allow/block per team or user). |
| GET | /v1/channels/{channel}/templates/sendableTemplates available for this channel's in-chat picker. For WhatsApp Business — channel-bound templates with `status=published` and `meta_status=approved` (sent via POST /messages/send-template). For every other channel type — the company's published templates of the same channel_type (not bound to a channel, no Meta moderation); the frontend inserts their filled text into the chat input as a plain message rather than through the template-send API. | Templates available for this channel's in-chat picker. For WhatsApp Business — channel-bound templates with `status=published` and `meta_status=approved` (sent via POST /messages/send-template). For every other channel type — the company's published templates of the same channel_type (not bound to a channel, no Meta moderation); the frontend inserts their filled text into the chat input as a plain message rather than through the template-send API. |
Examples
List connected channels
Request
curl -X GET "https://api.aisar.app/v1/channels?status=connected" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Response
{
"data": [
{
"id": 3,
"company_id": 1,
"channel_type_id": 1,
"provider_key": "whatsapp",
"name": "Основной WhatsApp",
"account_name": "+77001234567",
"status": "connected",
"setup_state": "ready",
"allow_broadcasts": true,
"allow_automations": true,
"allow_inbound_handling": true,
"connected_at": "2026-01-15T09:00:00Z",
"last_inbound_at": "2026-02-09T18:00:00Z",
"channel_type": { "id": 1, "key": "whatsapp", "name": "WhatsApp" }
}
]
}Pause a channel
Request
curl -X POST "https://api.aisar.app/v1/channels/3/pause" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"message": "Channel status updated.",
"channel": {
"id": 3,
"status": "paused",
"status_changed_at": "2026-02-09T18:30:00Z"
}
}
}Reconnect a channel (Instagram — with a body)
Request
curl -X POST "https://api.aisar.app/v1/channels/9/reconnect" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "code": "AQB..." }'Response
{
"data": {
"message": "Channel reconnected.",
"channel": {
"id": 9,
"status": "connected",
"setup_state": "ready"
}
}
}Rename a channel and toggle its flags
Request
curl -X PATCH "https://api.aisar.app/v1/channels/3" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Отдел продаж — WhatsApp",
"allow_broadcasts": false,
"allow_automations": true
}'Response
{
"data": {
"message": "Channel updated.",
"channel": {
"id": 3,
"name": "Отдел продаж — WhatsApp",
"allow_broadcasts": false,
"allow_automations": true,
"allow_inbound_handling": true,
"status": "connected",
"setup_state": "ready"
}
}
}A channel with its provider config
Request
curl -X GET "https://api.aisar.app/v1/channels/3" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Response
{
"data": {
"channel": {
"id": 3,
"company_id": 1,
"channel_type_id": 1,
"provider_key": "whatsapp",
"name": "Основной WhatsApp",
"account_name": "+77000000001",
"status": "connected",
"setup_state": "ready",
"channel_type": { "id": 1, "key": "whatsapp", "name": "WhatsApp" }
},
"provider_config": {
"mark_online_on_connect": {
"value": true,
"label": "Отмечать онлайн при подключении",
"description": "Показывать аккаунт онлайн, пока канал подключён"
}
}
}
}Create a channel and start pairing
Request
curl -X POST "https://api.aisar.app/v1/channels" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_type_id": 1,
"provider_key": "whatsapp",
"name": "Sales WhatsApp",
"account_name": "+77000000002",
"start_pairing": true,
"pairing_mode": "qr"
}'Response
{
"data": {
"message": "Channel created.",
"channel": {
"id": 7,
"provider_key": "whatsapp",
"status": "connecting",
"setup_state": "pairing"
},
"pairing": {
"mode": "qr",
"request_id": "00000000-0000-0000-0000-000000000000"
}
}
}Poll the connection state (QR)
Request
curl -X GET "https://api.aisar.app/v1/channels/7/connection" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"channel_id": 7,
"setup_state": "pairing",
"connection": {
"status": "qr_required",
"mode": "qr",
"qr": {
"value": "2@EXAMPLE_QR_PAIRING_PAYLOAD_REDACTED",
"expires_at": "2026-02-09T18:00:20Z",
"expires_in_seconds": 18,
"is_expired": false,
"attempt": 1
},
"pairing_code": null,
"pairing_code_expires_at": null,
"pairing_state": "qr",
"last_error_message": null,
"retry_count": null,
"next_retry_at": null,
"status_message": null,
"updated_at": "2026-02-09T18:00:05Z"
},
"metrics": {}
}
}Submit an auth code (Telegram Personal)
Request
curl -X POST "https://api.aisar.app/v1/channels/8/auth-code" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"code": "12345",
"phone_code_hash": "EXAMPLE_PHONE_CODE_HASH"
}'Response
{
"data": {
"message": "Auth code submitted.",
"channel_id": 8
}
}Channel logs
Request
curl -X GET "https://api.aisar.app/v1/channels/3/logs" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": [
{
"id": "1042",
"level": "info",
"code": "connection.ready",
"message": "Channel connected",
"context": {},
"created_at": "2026-02-09T18:00:00Z"
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 200, "total": 1 }
}Channel logs — paging through the history
Request
curl -X GET "https://api.aisar.app/v1/channels/3/logs?per_page=50&page=2" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": [
{
"id": "992",
"level": "error",
"code": "connection.lost",
"message": "Runtime session dropped",
"context": { "reason": "device_removed" },
"created_at": "2026-02-08T21:14:07Z"
}
],
"meta": { "current_page": 2, "last_page": 3, "per_page": 50, "total": 121 }
}Channel logs — a message send failure
Request
curl -X GET "https://api.aisar.app/v1/channels/3/logs" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": [
{
"id": "1108",
"level": "error",
"code": "message.send.failed.rate_limit_hit",
"message": "Too many messages sent, please wait before sending more",
"context": {
"message_id": 1042,
"attempts": 3,
"error_code": "rate_limit_hit",
"response": "{\"status\":429,\"reason\":\"rate_limited\"}"
},
"created_at": "2026-08-26T10:02:11Z"
},
{
"id": "1107",
"level": "warning",
"code": "message.status.failed_suppressed",
"message": "Delivery failure receipt arrived after the message was already delivered",
"context": {
"message_id": 1039,
"reason": "Message expired (131053)"
},
"created_at": "2026-08-26T09:47:03Z"
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 200, "total": 2 }
}List archived channels
Request
# GET /channels никогда не возвращает архивные каналы, и параметра
# ?include_archived=1 не существует — если его передать, валидация молча
# его проигнорирует. Единственный способ увидеть архивный канал — этот список.
curl -X GET "https://api.aisar.app/v1/channels/archived" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Response
{
"data": [
{
"id": 12,
"name": "WhatsApp — старый номер",
"account_name": "+77001112233",
"status": "disconnected",
"provider_key": "whatsapp",
"setup_state": "ready",
"archived_at": "2026-08-20T09:15:00.000000Z",
"messages_count": 4213,
"channel_type": { "id": 1, "key": "whatsapp", "name": "WhatsApp" }
}
]
}Permanently delete an archived channel
Request
curl -X DELETE "https://api.aisar.app/v1/channels/archived/12" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"message": "Archived channel purged."
}
}WhatsApp calling readiness (eligibility)
Request
curl -X GET "https://api.aisar.app/v1/channels/3/whatsapp-calling" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Response
{
"data": {
"eligibility": {
"calling": {
"sip_status": "NOT_SET",
"can_receive_call_sip": null,
"active": false
},
"prerequisites": {
"business_verified": false,
"payment_ok": true,
"name_approved": true,
"number_registered": true
},
"blocking_issues": [
{
"key": "business_verification",
"severity": "error",
"title": "Business is not verified with Meta",
"detail": "The business owner must complete Business Verification in Meta Business Manager.",
"fix_url": "https://business.facebook.com/settings/security"
}
],
"can_enable": false,
"name_status": "APPROVED",
"checked_at": "2026-02-09T18:00:00Z"
}
}
}Enable WhatsApp calling
Request
curl -X POST "https://api.aisar.app/v1/channels/3/whatsapp-calling/enable" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": {
"ok": true,
"error": null,
"error_code": null,
"outbound_trunk_provisioned": true,
"eligibility": {
"calling": {
"sip_status": "ENABLED",
"can_receive_call_sip": "AVAILABLE",
"active": true
},
"prerequisites": {
"business_verified": true,
"payment_ok": true,
"name_approved": true,
"number_registered": true
},
"blocking_issues": [],
"can_enable": true,
"name_status": "APPROVED",
"checked_at": "2026-02-09T18:05:00Z"
}
}
}Channel types and providers catalog
Request
curl -X GET "https://api.aisar.app/v1/channel-types?published=true" \
-H "Authorization: Bearer YOUR_API_TOKEN"Response
{
"data": [
{
"id": 1,
"key": "whatsapp",
"name": "WhatsApp",
"description": "WhatsApp через QR-сопряжение",
"category": "messaging",
"order_id": 1,
"badge_label": "Popular",
"badge_variant": "primary",
"is_published": true,
"capabilities": { "send_text": true, "send_media": true },
"limits": {},
"provider_config": {
"mark_online_on_connect": {
"value": true,
"label": "Отмечать онлайн при подключении",
"description": "Показывать аккаунт онлайн, пока канал подключён"
}
}
}
]
}Templates for the chat picker (non-WABA channel)
Request
# Для WhatsApp/Telegram/Instagram и т.п. отдаются опубликованные шаблоны
# компании того же channel_type — без привязки к каналу (channel_id: null)
# и без модерации Meta (meta_status: null). Фронт вставляет body как готовый
# текст в поле ввода, а не отправляет через POST /messages/send-template.
curl -X GET "https://api.aisar.app/v1/channels/3/templates/sendable" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Response
{
"data": [
{
"id": 58,
"company_id": 1,
"template_group_id": 58,
"channel_type_id": 1,
"channel_type": { "id": 1, "key": "whatsapp", "name": "WhatsApp" },
"channel": null,
"name": "greeting",
"slug": "greeting",
"status": "published",
"meta_status": null,
"meta_status_reason": null,
"last_synced_at": null,
"language": "ru",
"category": null,
"body": "Здравствуйте, {{first_name}}! Чем можем помочь?",
"parameters": [
{ "id": 101, "name": "first_name", "type": "text", "sample_value": "Иван", "position": 1 }
],
"buttons": [],
"uses_count": 12
}
]
}Blocked numbers (WhatsApp Business/Cloud)
Request
curl -X GET "https://api.aisar.app/v1/channels/3/whatsapp/blocked-users?limit=50" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Response
{
"data": {
"numbers": ["+77001111111"],
"next_cursor": "CURSOR_1"
}
}Blocked numbers (QR-based WhatsApp)
Request
curl -X GET "https://api.aisar.app/v1/channels/7/whatsapp/blocked-users" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Response
{
"data": {
"numbers": ["77009998877@s.whatsapp.net"],
"next_cursor": null
}
}