Skip to content

Messages API

Send messages to your AI agents programmatically via channels.

Overview

Use your channel to send messages programmatically. The channel identifier routes messages to the configured default agent automatically.

Required Fields

FieldDescription
contentThe message text
fromChannelIdentifierYour channel's identifier (routes to the default agent)

Optional Fields

FieldDescription
sessionIdGroup messages in a conversation (auto-generated if omitted)
sessionNameDisplay name for the chat session (also used as CRM card title)
externalUserIdYour customer's identifier for tracking
attachmentsArray of file attachments
isEchoSet to true to sync messages from external systems without AI processing
agentIdTarget agent ID — triggers session transfer if different from current
kanbanIdTarget kanban ID — triggers session transfer if different from current

Send Message

http
POST /messages

Request Parameters

FieldTypeRequiredDescription
contentstringYes*The message text (*or attachments required)
fromChannelIdentifierstringYesYour channel's identifier
channelTypestringNoChannel type (see table below). Defaults to api
sessionIdstringNoConversation ID (auto-generated if omitted)
sessionNamestringNoDisplay name for the session
externalUserIdstringNoYour customer's identifier
attachmentsarrayNoFile attachments (see File Attachments)
isEchoboolNoSet true to sync without AI processing
agentIdstringNoTarget agent ID — triggers a session transfer if different from current
kanbanIdstringNoTarget kanban ID — triggers a session transfer if different from current

Channel Types

The channelType field determines how the fromChannelIdentifier is routed. You must pass the correct type matching your channel, otherwise routing will fail.

ValueDescription
apiAPI channel (default)
whatsapp_byotWhatsApp Custom App (Bring Your Own Token)
whatsapp_noWhatsApp Non-Official (QR Code)
whatsappWhatsApp Cloud API (OAuth)
webWeb chat widget
telegramTelegram bot
smsSMS channel

Channel Type is Required for Routing

If fromChannelIdentifier is provided, the channelType must match the type of the channel you created. For example, a WhatsApp QR Code channel requires channelType: "whatsapp_no", and a WhatsApp Custom App channel requires channelType: "whatsapp_byot". Omitting channelType defaults to "api" and will fail to find non-API channels.

Basic Request

bash
curl -X POST https://api.maiacompany.io/messages \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Hello, I need help!",
    "fromChannelIdentifier": "YOUR_CHANNEL_IDENTIFIER",
    "externalUserId": "customer-123",
    "sessionId": "YOUR_SESSION_ID",
    "sessionName": "Customer Support Chat"
  }'

Response

Returns 202 Accepted. The AI processes the message asynchronously and delivers the response via webhook.

json
{
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "isNewSession": true,
  "userMessage": {
    "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "role": "user",
    "content": "Hello, I need help!",
    "timestamp": 1704067200000
  },
  "message": "Message received. AI response will be delivered via webhook."
}

File Attachments

Step 1: Request Upload URL

Request a presigned upload URL from S3.

bash
curl -X POST https://api.maiacompany.io/messages/upload \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fileName": "photo.jpg",
    "contentType": "image/jpeg",
    "size": 1024000
  }'

Response

json
{
  "uploadUrl": "https://s3.amazonaws.com/...",
  "fileKey": "attachments/acc123/2024/12/uuid-photo.jpg",
  "expiresAt": 1703001234567
}

Step 2: Upload File to S3

Upload the file using the presigned URL from Step 1.

bash
curl -X PUT "UPLOAD_URL_FROM_RESPONSE" \
  -H "Content-Type: image/jpeg" \
  --data-binary @photo.jpg

Step 3: Get Download URL (Optional)

Generate a presigned download URL for a previously uploaded file. This is useful when you need a direct URL to the file — for example, when sending WhatsApp Template messages with media headers.

bash
curl "https://api.maiacompany.io/attachments/attachments/acc123/2024/12/uuid-photo.jpg" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Response

json
{
  "downloadUrl": "https://s3.amazonaws.com/...",
  "expiresAt": 1703005200000,
  "contentType": "image/jpeg",
  "size": 1024000
}
FieldTypeDescription
downloadUrlstringPresigned S3 URL for downloading the file (1h expiry)
expiresAtnumberURL expiration timestamp (milliseconds)
contentTypestringMIME type of the file
sizenumberFile size in bytes

TIP

The download URL expires after 1 hour. Request a new one if needed.

Step 4: Send Message with Attachment

Include the fileKey in your message.

bash
curl -X POST https://api.maiacompany.io/messages \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Here is the document you requested",
    "fromChannelIdentifier": "YOUR_CHANNEL_IDENTIFIER",
    "externalUserId": "customer-123",
    "sessionId": "YOUR_SESSION_ID",
    "attachments": [
      {
        "fileKey": "attachments/acc123/2024/12/uuid-photo.jpg",
        "fileName": "photo.jpg",
        "contentType": "image/jpeg",
        "size": 1024000
      }
    ]
  }'

Send Voice Message

Voice messages are sent as audio attachments. Audio files are automatically converted to OGG Opus for WhatsApp.

bash
curl -X POST https://api.maiacompany.io/messages \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "",
    "fromChannelIdentifier": "YOUR_CHANNEL_IDENTIFIER",
    "externalUserId": "customer-123",
    "sessionId": "YOUR_SESSION_ID",
    "attachments": [
      {
        "fileKey": "attachments/acc123/2024/12/uuid-voice.ogg",
        "fileName": "voice-message.ogg",
        "contentType": "audio/ogg",
        "size": 256000
      }
    ]
  }'

Supported File Types

CategoryFormatsMax Size
ImagesJPEG, PNG, GIF, WebP10 MB
AudioMP3, WAV, OGG, M4A, WebM, AAC, AMR25 MB
VideoMP4, WebM, MOV50 MB
DocumentsPDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT, CSV25 MB

Audio Conversion

Audio files are automatically converted to OGG Opus format for WhatsApp compatibility.

Limits

  • Maximum 10 attachments per message
  • Total size limit: 100 MB per message

Echo Messages

Use isEcho: true to sync messages from your external system into MAIA without triggering AI processing. Echo messages appear in the conversation as if sent by the customer/human, keeping the chat history complete.

When to Use Echo

  • Syncing customer messages received on external platforms (WhatsApp, etc.)
  • Maintaining complete conversation history in MAIA
  • Messages that should appear as customer messages but not trigger AI responses

Request Parameters

FieldTypeRequiredDescription
contentstringYes*The message text (*or attachments required)
fromChannelIdentifierstringYesYour channel's identifier
externalUserIdstringYesYour customer's identifier
isEchoboolYesMust be true for echo messages
channelTypestringNoChannel type (see Channel Types). Defaults to api
sessionIdstringNoConversation ID (auto-generated if omitted)
attachmentsarrayNoFile attachments

Echo Request

bash
curl -X POST https://api.maiacompany.io/messages \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Customer message from WhatsApp",
    "fromChannelIdentifier": "YOUR_CHANNEL_IDENTIFIER",
    "externalUserId": "customer-123",
    "sessionId": "YOUR_SESSION_ID",
    "isEcho": true
  }'

Response

Returns 200 OK (not 202 Accepted) since no async processing occurs.

json
{
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "isNewSession": false,
  "userMessage": {
    "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "role": "user",
    "content": "Customer message from WhatsApp",
    "timestamp": 1704067200000
  },
  "message": "Message synced successfully."
}

Required Fields for Echo

Echo messages require both fromChannelIdentifier and externalUserId for proper channel routing and CRM linking.


Message Status & Reactions

Sync message delivery status and reactions from your external system back to MAIA.

Integration Flow

After receiving our webhook, link your external message ID with our messageId.

bash
curl -X POST "https://api.maiacompany.io/sessions/{sessionId}/messages/{messageId}/link" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "providerMsgId": "whatsapp_msg_123",
    "setStatusToSent": true
  }'

Update Message Status

Update delivery status using the providerMsgId.

bash
curl -X POST "https://api.maiacompany.io/sessions/{sessionId}/messages/status" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "providerMsgId": "whatsapp_msg_123",
    "status": "delivered"
  }'

Status values: sent | delivered | read | failed

Sync Reactions (from external)

Sync reactions from your external system when customers react to messages.

bash
curl -X POST "https://api.maiacompany.io/sessions/{sessionId}/messages/reactions" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "providerMsgId": "whatsapp_msg_123",
    "action": "upsert",
    "emoji": "👍"
  }'

Action values:

ActionDescription
addAdd a reaction
removeRemove a reaction
upsertClear all reactions, then add emoji (if provided). Omit emoji to clear all.

Session Management

The sessionId groups messages into a conversation. Use the same sessionId for follow-up messages from the same customer.

  • You can generate any unique string (e.g., UUID, customer ID + timestamp)
  • If omitted, a new session will be created automatically

TIP

Use sessionName to set a display name for the chat session. This is also used as the CRM card title.


Session Transfer via Message

You can trigger an implicit session transfer by including agentId and/or kanbanId in your POST /messages request. When the provided values differ from the session's current agent or kanban, the session is automatically transferred before the message is processed.

How It Works

  1. Send a message with agentId and/or kanbanId in the request body
  2. If the session already exists and the provided agent/kanban differs from the current one, a transfer is triggered
  3. A system message is recorded in the chat history documenting the transfer
  4. If the kanban changes, a new CRM record is created on the target kanban

Transfer Request

bash
curl -X POST https://api.maiacompany.io/messages \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Route this to the sales team",
    "fromChannelIdentifier": "YOUR_CHANNEL_IDENTIFIER",
    "externalUserId": "customer-123",
    "sessionId": "EXISTING_SESSION_ID",
    "agentId": "TARGET_AGENT_ID",
    "kanbanId": "TARGET_KANBAN_ID"
  }'

Transfer Scenarios

Params ProvidedBehavior
agentId onlyAgent is set explicitly; kanbanId is resolved from the channel's agent-kanban config
kanbanId onlyKanban is set explicitly; agentId is resolved from the channel's default agent
Both agentId + kanbanIdBoth are set explicitly — full control over the transfer target
NeitherNo transfer — message is routed to the session's current agent

TIP

Transfer only triggers on existing sessions. For new sessions (first message), the agentId and kanbanId simply set the initial assignment.

Channel Configuration Required

The target agent must be in the channel's allowedAgentIds. For automatic kanban resolution, configure agentKanbanConfigs on the channel.


AI Pause / Unpause

Control whether the AI responds to messages in a session. When paused, incoming messages are stored but the AI won't generate responses until resumed.

Pause or Resume AI

http
PATCH /sessions/{sessionId}/ai-paused
bash
curl -X PATCH "https://api.maiacompany.io/sessions/{sessionId}/ai-paused" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "aiPaused": true
  }'

Request Body:

FieldTypeRequiredDescription
aiPausedbooleanYestrue to pause AI, false to resume AI

Response:

json
{
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "aiPaused": true,
  "message": "AI responses paused for this session"
}

Webhook Notification

When the AI is paused or resumed, an ai_pause webhook event is sent. See CRM Webhooks for details.

Use Cases

  • Human takeover: Pause AI when a human agent needs to handle the conversation
  • After-hours support: Pause AI during business hours for human agents
  • Escalation handling: Pause AI when complex issues require human intervention

Error Responses

StatusDescription
400Bad request - invalid parameters
401Unauthorized - invalid or missing token
404Resource not found
429Rate limit exceeded
500Server error

Example Error

json
{
  "error": "Bad Request",
  "message": "content or attachments required"
}

MAIA Platform Documentation