AISARAISAR

Sending messages: endpoint reference

A full endpoint reference for external systems (AI assistants, chatbots, CRMs): channels, media and voice uploads, sending text and WhatsApp templates.

This reference complements the "Sending messages from your system" walkthrough with per-endpoint detail: request fields, response shape, and edge cases. Every request uses the company's Bearer token and runs in that company's context.

GET /channels

Fetch the channels available to the current user within the company — use it to find the channel_id you'll send through.

Query paramDescription
typeFilter by channel type key: whatsapp, whatsapp_business, telegram, telegram_bot, instagram, instagram_business, facebook_messenger, tiktok, live_chat, sms
statusFilter by status: connected, disconnected, paused, etc.
setup_stateFilter by setup state: Draft, Setup, Active, Paused
Response (abridged)
{
  "data": [
    {
      "id": 57,
      "name": "WhatsApp test",
      "account_name": "+77084252291",
      "status": "connected",
      "message_operations": {
        "can_create": true,
        "can_edit": true,
        "edit_window_seconds": 900,
        "revoke_window_seconds": 172800
      },
      "limits": {
        "max_text_length": 4096,
        "file_limits": { "image": { "max_size_mb": 16 }, "video": { "max_size_mb": 64 } }
      },
      "channel_type": { "id": 1, "key": "whatsapp", "name": "WhatsApp" },
      "broadcast_rate_limits": { "daily_limit": 1500, "messages_per_minute": 15 }
    }
  ]
}

Before sending, check that status === "connected" and message_operations.can_create === true.

POST /uploads

Uploads a file to AISAR and returns a compact media_id you then pass to /messages/send. Delivery to the messenger is handled by the connector without re-downloading. Two modes are supported.

Mode A — multipart upload

http
POST /v1/uploads
Authorization: Bearer YOUR_API_TOKEN
Content-Type: multipart/form-data

file=@photo.jpg

Maximum 64 MB. Allowed extensions: jpg, jpeg, png, gif, webp, bmp, svg, mp4, mov, avi, wmv, webm, mkv, mp3, ogg, wav, aac, flac, m4a, opus, amr, pdf, doc, docx, xls, xlsx, csv, txt, rtf, ppt, pptx, zip, rar, 7z, gz, json, xml.

Mode B — upload by URL

http
POST /v1/uploads
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json

{ "url": "https://cdn.example.com/photo.jpg" }

AISAR downloads the file once, stores it, and returns a media_id. The URL must be http/https, the size ≤ 64 MB, download timeout 20 sec.

Response (both modes)
{
  "media_id": "med_01HZABCDEFGHIJKLMNOPQRSTUV",
  "type": "image",
  "filename": "photo.jpg",
  "mime_type": "image/jpeg",
  "size": 123456,
  "width": null,
  "height": null,
  "duration": null,
  "expires_at": "2026-05-16T10:30:00.000000Z"
}
The result is idempotent by content (SHA-256 within the company) — re-uploading the same file (multipart or URL) returns the same media_id; the file isn't duplicated in storage. A broadcast of one image to 100 contacts needs only one POST /uploads, even if you accidentally call it twice.

Requires the conversation.view permission.

POST /uploads/voice

Uploads an audio recording and transcodes it to OGG/Opus — the format WhatsApp and Telegram render as a voice note rather than an attached file. This is the only correct way to send a voice message via the API: a plain /uploads call stores the file as-is (type audio), and the recipient gets an audio file, not a voice note.

http
POST /v1/uploads/voice
Authorization: Bearer YOUR_API_TOKEN
Content-Type: multipart/form-data

file=@voice.m4a

Accepts audio/webm, audio/ogg, audio/mp4, audio/mpeg, audio/wav, audio/aac, audio/x-m4a (and video/webm — the browser-recording container). The server transcodes the recording to OGG/Opus itself.

Response
{
  "media_id": "med_01HZABCDEFGHIJKLMNOPQRSTUV",
  "type": "audio",
  "filename": "voice.ogg",
  "mime_type": "audio/ogg",
  "size": 24576,
  "duration": 7,
  "expires_at": "2026-05-16T10:30:00.000000Z"
}
The type field in the response is audio (it's a media asset). To make the message send as a voice note, set attachments[].type: "voice" when sending (see below). Voice notes are supported on WhatsApp (personal), WhatsApp Business, Telegram (personal), and Telegram Bot; on other channels the attachment goes out as a regular audio file. Requires the conversation.view permission.

POST /messages/send

Sends an outbound message on behalf of a channel to a specific recipient. If the conversation doesn't exist yet, it will be created.

FieldTypeRequiredDescription
channel_idintegerYesThe sending channel ID (from /channels)
recipientstringYesThe recipient identifier in the format the channel expects: an E.164 number, a Telegram username, an IGSID, etc. For WhatsApp groups — the group JID <id>@g.us. Max 255 chars.
is_groupbooleanNotrue — the recipient is a WhatsApp group. Not required if recipient is already in the <id>@g.us form (the suffix is recognized automatically). Defaults to false.
is_silentbooleanNotrue — a "silent" send: the operator's unread counter is not reset. Defaults to false. Useful for programmatic/service messages.
message_contentstringConditionalMessage text, max 65,535 chars (the channel's actual limit is in limits.max_text_length from /channels). Required if attachments is absent.
attachmentsarrayConditional1–10 attachments. Required if message_content is absent. Each item: media_id (required) + optional type (image/video/audio/voice/document/file).
Example — text
{
  "channel_id": 42,
  "recipient": "+79001234567",
  "message_content": "Здравствуйте! Чем могу помочь?"
}
Example — WhatsApp group
{
  "channel_id": 42,
  "recipient": "120363398017778174@g.us",
  "message_content": "Всем привет в группе!"
}

Where to get the group identifier: the JID <id>@g.us arrives in inbound-message webhooks and is available in GET /v1/conversations — the group thread's threads[].contact_account.external_id (threads[].is_group: true). Constraints: groups are only supported on WhatsApp channels; the channel's account must be a member of the group; a contradictory request (recipient ends with @g.us but is_group: false) is rejected with 422.

Success response
{ "success": true }

Behaviour. If a conversation with the recipient already exists on this channel it is reused; otherwise a new one is created (contact account, thread, conversation). After the message is created, subscribed webhook integrations receive message.created with direction: outbound. The endpoint creates the message synchronously, but delivery to the messenger runs asynchronously through the connector queue — the final delivery status arrives as message.status.updated. Requires the conversation.create permission, otherwise 403 Forbidden.

GET /templates

Fetches the company's message templates — use it to find Meta-approved WhatsApp Business templates and their id for /messages/send-template.

Query paramDescription
channel_idFilter by a specific WhatsApp Business channel
metaStatuses[]Meta approval status: approved, rejected, pending. For sendable templates use metaStatuses[]=approved
channelTypeChannel type key (e.g. whatsapp_business)
languageBCP-47, e.g. en, ru
searchSearch by name/text/slug/labels
sortBy / sortDirname, status, created_at, updated_at, uses_count, language; asc/desc
Response (abridged)
{
  "data": {
    "items": [
      {
        "id": 42,
        "name": "order_update",
        "meta_status": "approved",
        "language": "en",
        "body": "Здравствуйте, {{name}}! Ваш заказ {{order_id}} готов.",
        "parameters": [
          { "name": "name", "type": "text", "sample_value": "Иван", "position": 1 },
          { "name": "order_id", "type": "text", "sample_value": "A-100", "position": 2 }
        ],
        "channel_type": { "id": 1, "key": "whatsapp_business", "name": "WhatsApp Business" },
        "channel": { "id": 57, "name": "WhatsApp test", "account_name": "+77084252291" }
      }
    ],
    "pagination": { "page": 1, "perPage": 15, "total": 1, "lastPage": 1 }
  }
}

meta_status is the Meta review status; only `approved` can be sent. body carries the placeholders ({{name}} or {{1}}) that tell you which params /messages/send-template needs. Requires the template.view permission.

To avoid polling this endpoint constantly, subscribe to the template.approved and template.rejected webhook events — they fire when meta_status changes, letting you invalidate a cache.

POST /messages/send-template

Sends an approved WhatsApp Business template to a specific recipient — for initiating conversations outside the 24-hour window and for broadcasts (call once per recipient). If a conversation with the recipient doesn't exist yet, it will be created.

FieldTypeRequiredDescription
channel_idintegerYesMust be of type whatsapp_business
recipientstringYesE.164 number, max 255 chars
template_idintegerYesTemplate ID from /templates, must belong to the company and have meta_status = approved
paramsobject/arrayNoTemplate variable values (see below). Omit for templates without variables.
header_media_urlstring (url)NoFor templates with a media header (image/video/document)
is_silentbooleanNoSame as /messages/send — does not reset the unread counter

The server builds the Meta components structure from the template definition for you. params values are passed one of two ways: a named map for named placeholders {{name}} ({ "name": "Иван", "order_id": "A-100" }), or positional for numeric placeholders {{1}}, {{2}} — a map with numeric keys or a plain array (["Иван", "A-100"], values in order: header → body → buttons).

Example request
{
  "channel_id": 57,
  "recipient": "+79001234567",
  "template_id": 42,
  "params": { "name": "Иван", "order_id": "A-100" }
}
Success response
{
  "success": true,
  "message_id": 12345
}

Behaviour. Sending is only allowed for whatsapp_business channels and templates with meta_status = approved — otherwise 422. If a variable's value is missing, 422 lists the missing parameters. The sent message keeps the rendered template structure in message_content.display (visible in GET /messages): header, body, footer, buttons[] — each button is { "type": "quick_reply" | "url" | "phone", "label": "...", "value": "..." }. When a contact taps a quick-reply button, the tap arrives back as an inbound message of type: "text" carrying the button's label and content.interactive_reply_payload. Requires the conversation.create permission.

Errors and status codes

CodeCauseHow to handle
401Invalid or missing tokenCheck Authorization: Bearer {token}
403No permission to create conversationsThe token owner needs the conversation.create permission
404Company not foundThe token isn't bound to a company
422Validation error or the channel doesn't belong to the companyCheck the request body
429Rate limitRetry with exponential backoff

The full request → webhook loop and media-broadcast walkthrough live in the "Sending messages from your system" guide.