Skip to main content
The Channels API lets you send messages to contacts through a configured API channel in your workspace. When you post a message, the platform creates or resolves the contact by contactIdentifier, routes the message to your AI agent, and returns the agent’s response synchronously in the same API call.
Conversations through an API channel are handled exclusively by AI agents. There is no interface for human agents to join these conversations, so transfer to a human is not supported.

Endpoint

POST /api/v1/channels/{channelId}/messages

Authentication

Include your Workspace API Key and, optionally, an idempotency key in the request headers.
X-API-Key: your_workspace_api_key
Content-Type: application/json
X-Idempotency-Key: optional_key_to_prevent_duplicates

Path parameters

channelId
string
required
The ID of the API channel configured in your workspace.

Request body parameters

type
string
required
The message type. One of: TEXT, IMAGE, AUDIO, VIDEO, DOCUMENT.
contactIdentifier
string
required
A unique identifier for the contact. Used to create or look up the contact across requests. We recommend using the contact’s email address.
contactName
string
Display name for the contact. Used when creating a new contact record.
content
object
required
The message payload. The shape of this object depends on the type field — see the message type examples below.
Always use the same contactIdentifier value for the same person. Using different identifiers for the same contact (for example, joao@example.com in one request and user@example.com in another) creates separate contact records and breaks conversation history.

Message types

Text

{
  "content": {
    "text": {
      "body": "Hello, how can I help you?"
    }
  },
  "type": "TEXT",
  "contactIdentifier": "user@example.com",
  "contactName": "User Name"
}

Image

{
  "content": {
    "image": {
      "url": "https://example.com/image.jpg",
      "caption": "Image caption"
    }
  },
  "type": "IMAGE",
  "contactIdentifier": "user@example.com"
}

Audio

{
  "content": {
    "audio": {
      "url": "https://example.com/audio.mp3"
    }
  },
  "type": "AUDIO",
  "contactIdentifier": "user@example.com"
}

Video

{
  "content": {
    "video": {
      "url": "https://example.com/video.mp4",
      "caption": "Video caption"
    }
  },
  "type": "VIDEO",
  "contactIdentifier": "user@example.com"
}

Document

{
  "content": {
    "document": {
      "url": "https://example.com/document.pdf",
      "filename": "document.pdf",
      "caption": "Document description"
    }
  },
  "type": "DOCUMENT",
  "contactIdentifier": "user@example.com"
}

Response fields

success
boolean
required
Indicates whether the operation succeeded.
contactId
string
required
The unique ID of the contact that was created or matched by contactIdentifier.
conversationId
string
required
The unique ID of the conversation.
messageId
string
required
The unique ID of the message that was sent.
conversation
object
required
Details about the conversation and its assignment.
aiMessages
array
required
The AI agent’s response messages, ordered ascending (earliest first). This is an array because the AI may split its response across multiple sequential messages.
usage
object
required
Credit consumption information.

HTTP status codes

CodeDescription
200Success — message processed
400Invalid request data or channel not found
401Missing or invalid API key
404Channel not found
500Internal server error

Integration examples

async function sendMessage(channelId, apiKey, message) {
  const response = await fetch(`/api/v1/channels/${channelId}/messages`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': apiKey
    },
    body: JSON.stringify({
      content: {
        text: {
          body: message
        }
      },
      type: 'TEXT',
      contactIdentifier: 'user@example.com'
    })
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }

  return await response.json();
}

try {
  const result = await sendMessage('channel_123', 'your_api_key', 'Hello!');
  console.log('Message sent:', result);
} catch (error) {
  console.error('Error:', error);
}

Limitations

  • AI only: Conversations are exclusive to AI agents — human agent handoff is not available.
  • Consistent contactIdentifier: Always use the same value for the same contact. We recommend using the contact’s email address.
  • Public media URLs: Image, audio, video, and document URLs must be publicly accessible.
  • File size limit: Maximum 10 MB per file.
  • Download timeout: Media downloads time out after 30 seconds.
  • Idempotency: Use X-Idempotency-Key to avoid duplicate messages on retried requests.