BotInbox API Reference

Build powerful integrations with the BotInbox REST API. Manage conversations, contacts, messages, and more programmatically.

Base URL: https://your-domain.com/api/v1JSON responses

Authentication

How to authenticate your API requests

All API requests must include an API key. Two header formats are accepted:

- X-API-Key: bi_... (recommended)

- Authorization: Bearer bi_... (standard OAuth2 style)

Create API keys from the Manage > API Playground page. Keys are prefixed bi_ and shown only once on creation — store them securely.

Permission scopes (set per key):

- read — list and retrieve resources (GET endpoints)

- write — create and update resources (POST, PATCH)

- delete — remove resources (DELETE)

- admin — implies all of the above

Requests using a key that lacks the required scope return 403 Forbidden with a message naming the missing permission.

Limited keys. A key can be limited to some channels (for example one WhatsApp number) and, for email channels, to some email addresses — set when creating the key, or edit it later under Manage > Integrations > API Keys. Empty means no limit, which is the default.

- Conversations, messages, search, contacts, analytics and counts cover only what the key may see. Anything outside answers 404 exactly like something that does not exist.

- An email-address limit narrows email channels only: threads sent to or from one of the addresses, and sending only as one of them (from_not_allowed otherwise). Mail with no recorded To/Cc (stored before August 2026) counts as sent to the mailbox's own address.

- Sends without a channelId use the first channel the key may use; send_email without a channel uses the first allowed mailbox, never the platform sender.

- Contacts are visible when they have a conversation the key may see, or none yet. Bookings and sales documents are listed per contactId or conversationId. Templates and users stay workspace-wide; /api/v1/webhooks is refused.

- GET /api/v1/channels returns a keyScope block describing the limits.

MCP connections made through Claude's connector dialog can pick the same limits on the consent screen, and always keep the connecting person's own team and channel access.

Example request:

`bash

curl https://your-domain.com/api/v1/conversations \

-H "X-API-Key: bi_your_api_key_here"

`

Errors:

- 401 — missing, invalid, expired, or inactive key

- 403 — key lacks required permission, or org is suspended

- 404 — resource not found in your org

- 400 — invalid request body or query

Example Request
curl -X GET "https://your-domain.com/api/v1/conversations" \
  -H "X-API-Key: bi_your_api_key_here" \
  -H "Content-Type: application/json"

Conversations

Create, list, and manage conversations

Messages

Send and retrieve messages

Contacts

Manage contacts and customer profiles

Labels

Manage conversation labels and tags

Users

List agents and team members

Channels

List communication channels

Webhooks

Subscribe to real-time events

Webhooks allow you to receive real-time HTTP POST notifications when events occur in BotInbox. Configure webhooks from Manage > Webhooks.

Channel scope: a webhook can optionally be restricted to specific channels. Leave it empty to receive events from every channel. Events with no channel of their own (contact.*, channel.*) are always delivered. Email addresses: for a mailbox with several addresses, a webhook can also be narrowed to some of them: incoming email counts when sent (To or Cc) to a listed address, replies when sent from one; other channels are unaffected. WhatsApp group chats: for numbers connected by QR with groups switched on, a webhook can take all group messages, only those that @mention or reply to the connected number (mentionsMe in the message metadata), or none; direct chats are always sent.

Media on messages: every message.* payload carries data.message.media — media.attachments[] with an absolute url, kind (image/audio/video/pdf/document/sticker/file), mimeType, size and for voice notes durationMs/voice; plus media.status (none/pending/ready/failed) and media.transcript. The raw attachments/metadata strings are unchanged. With Transcribe voice notes enabled a voice note arrives as media.status: "pending" and a message.updated follows with the transcript.

Bursts: subscribe to conversation.burst_ready to receive several inbound WhatsApp or LINE messages from one contact as one event, n8n-style: every message resets the gap — short (default 3 s) for text runs and for files once the instruction arrived, long (default 15 s, 5–120) while bare files wait for the text/voice note that says what to do (both on Manage > Webhooks; each channel can set its own long gap in its settings; 120 s hard cap). The event carries messages[] (fully serialized), combinedText, windowType, quietMs, assets[] (files) plus instructionText (the text or voice-note transcript). closedReason is instruction_received, idle_timeout (assets only — check with a human rather than invent a task) or max_items. AI agents should act on this event rather than on each message.created.

Context: every message.* and burst payload carries data.context — orgId/channelId/conversationId/messageId/contactId plus the organization, channel (non-secret config incl. status, verifiedName), contact (tags array, customFields object) and conversation.

Delivery: outbound WhatsApp/SMS messages report message.delivery_updated with delivery.status (queued → sending → sent → delivered → read → played; failed is terminal) and retryRequested when the recipient asked for a resend. Every serialized message carries delivery (null until reported). GET /channels carries health.state per channel.

Headers on every delivery:

- X-BotInbox-Event — the event type (e.g. message.created)

- X-BotInbox-Signature — HMAC-SHA256 of the raw request body, signed with your webhook secret

- X-BotInbox-Delivery — unique id of this delivery, the same on every retry; skip ids you have already handled

- Content-Type: application/json

- Any custom headers configured on the endpoint (e.g. Authorization: Bearer …), up to 10. Reserved names — Content-Type, X-BotInbox-*, Host and hop-by-hop headers — cannot be overridden. Always verify X-BotInbox-Signature, not your own header, to authenticate a delivery.

Payload shape:

`json

{

"event": "message.created",

"data": { /* resource payload */ },

"timestamp": "2025-01-15T10:30:00.000Z"

}

`

Verifying signatures (Node.js):

`js

import crypto from "crypto"

function verify(req, secret) {

const sig = req.headers["x-botinbox-signature"]

const expected = crypto

.createHmac("sha256", secret)

.update(req.rawBody)

.digest("hex")

return crypto.timingSafeEqual(

Buffer.from(sig),

Buffer.from(expected)

)

}

`

Retry behavior: BotInbox retries up to 3 times on transport failures and 5xx / 408 / 429 responses, with delays of 0s, 3s, and 10s. A delivery not answered within 10 s is not retried (the receiver usually has it already); reply 2xx at once and do the work afterwards. 4xx responses (other than 408 / 429) are treated as permanent rejections and not retried. The final error is stored on the webhook record.

Available event types:

- conversation.created / conversation.updated / conversation.closed / conversation.assigned / conversation.burst_ready

- message.created / message.updated / message.delivery_updated

- contact.created / contact.updated / contact.deleted

- channel.created / channel.updated

- * (subscribe to all events)