Skip to main content

Chat & conversations

LeadX has one unified inbox. WhatsApp, Instagram and website webchat all write to the same UnifiedMessage collection, so a conversation reads the same regardless of channel.

Everything chat-related except bulk campaigns is owned by leadx-ms-unified-chat. You reach it through leadx-api.

Read conversations

# Contacts with conversation history
curl https://api.leadx.in/api/key/protected/unified-chat -H "apikey: $KEY"

# Messages for one contact
curl -G https://api.leadx.in/api/key/protected/unified-chat/messages \
-H "apikey: $KEY" \
--data-urlencode 'contact=665f...' \
--data-urlencode 'p=1' --data-urlencode 'n=50'

Send a message

curl -X POST https://api.leadx.in/api/key/protected/unified-chat/messages \
-H "apikey: $KEY" -H "Content-Type: application/json" \
-d '{
"contact": "665f...",
"mode": "whatsapp",
"messageType": "message",
"content": { "text": "Thanks for getting in touch — are you free Thursday?" },
"leadId": "6660..."
}'
FieldNotes
modewhatsapp, instagram, smtp / email, or webchat. An unknown mode is a 400.
contactContact id. Required for every mode except instagram, which uses recipientId.
recipientIdInstagram-scoped user id.
contentObject, or a plain string for Instagram. Pass a template as content.template (id or document — only the id is stored).
messageTypeDefault message.
app / appTypeWhich connected app sends, when you have several.
senderIdSpecific sending identity.
leadIdAttach the message to a lead's timeline.
scheduled + scheduledAtSend later.
contactSpecificMessagePer-contact override text.

:::note webchat is delivered inline mode: "webchat" is written directly rather than dispatched to the send service, because there is no external provider behind it. It requires contact. :::

Human handover

Bots hold a conversation until a person takes over. Intercept is that takeover, and it is channel-agnostic:

# Current handover state
curl -G https://api.leadx.in/api/key/protected/conversation/handover \
-H "apikey: $KEY" \
--data-urlencode 'channel=whatsapp' \
--data-urlencode 'app=665f...' \
--data-urlencode 'externalThreadId=919876543210'

# Take over
curl -X PUT https://api.leadx.in/api/key/protected/conversation/intercept \
-H "apikey: $KEY" -H "Content-Type: application/json" \
-d '{ "channel": "whatsapp", "app": "665f...", "externalThreadId": "919876543210", "intercept": true }'

A conversation is keyed by { channel, app, account?, externalThreadId } — the same key the bot session uses. One pair of endpoints serves every channel.

The older PUT /chat-widget/session/:sessionId/intercept still exists for the widget client specifically.

Chat widgets

The embeddable website widget.

MethodEndpointPurpose
GET / POST / DELETE/chat-widgetList / create / bulk delete.
GET / PUT/chat-widget/:idRead / update.
PUT/chat-widget/:id/statusEnable or disable.
PUT/chat-widget/:id/rotate-tokenRotate the public embed token.
GET/chat-widget/:id/sessionsVisitor sessions.
PUT/chat-widget/session/:sessionId/interceptWidget-specific takeover.

Rotate the token if a widget's embed snippet leaks — it is a public credential by design.

Chatbots

Rule-based bots that answer before a human is involved.

MethodEndpointPurpose
GET / POST / DELETE/manual-chatbotManage bots.
GET / PUT / DELETE/manual-chatbot/:idOne bot.
POST/manual-chatbot/keywordsExtract trigger keywords from text.
POST/manual-chatbot/ai-generateDraft a whole bot with AI.

Routing

Which bot answers on which channel:

MethodEndpointPurpose
GET / PUT/manual-chatbot/chatbot-routerRouter configuration.
GET/manual-chatbot/chatbot-router/botsBots eligible for routing.
GET/manual-chatbot/chatbot-router/appsApps usable as entry points.
POST/manual-chatbot/chatbot-router/entry-pointsCreate an entry point.
PUT / DELETE/manual-chatbot/chatbot-router/entry-points/:entryPointIdUpdate / remove.
POST/manual-chatbot/chatbot-router/entry-points/:entryPointId/testTest routing without a real message.
POST/manual-chatbot/chatbot-router/rebuildRebuild keyword indexes.
GET / PUT/manual-chatbot/chatbot-router/session/stopRead or end a live bot session.

Run /rebuild after bulk keyword changes, or routing will keep using the stale index.

AI CRM chat

A conversational agent over your own CRM data — ask it questions, and approve any write it proposes.

MethodEndpointPurpose
GET / POST/ai-crm-chatList / start a chat.
GET / PUT / DELETE/ai-crm-chat/:idRead / rename / soft-delete.
POST/ai-crm-chat/:id/messageSend a message.
POST/ai-crm-chat/:id/tool/:messageId/:callIdApprove or reject a proposed write.
GET/ai-crm-chat/usageUsage against your plan.

Approving a tool call is the moment the write actually happens — it is a POST for that reason. Chats are never hard-deleted.

Hitting the plan's AI ceiling returns AIUsageLimitReached_429.