Developer Docs Logo
Customer Chat

Customer Chat Integration

This section covers everything specific to building a chat integration app for customers, an app that bridges an external messaging platform (e.g. Telegram) with the CRM, routing two-way conversations between platform users and CRM agents.

This guide builds on the generic third-party app foundation. Before diving in, make sure you have read the Third-Party App Foundation docs (app setup, OAuth, webhook security, and distribution).


Key Entities

Channel

A Channel in the CRM represents a communication inbox (e.g. "Telegram Support TH", "Telegram Sales"). Every conversation belongs to exactly one channel.

Your third-party app currently cannot create channels via the API. The agent must create them through the CRM Dashboard UI. Your app then discovers them by calling GET /v1/channels and presents a channel picker to the admin during setup.

A single installation of your third-party app can link multiple platform accounts to the same CRM workspace. Each platform account is mapped to a channel, multiple accounts can share the same channel if the agent configures them that way.

Warning: Do not link multiple platform accounts from the same platform to the same CRM channel.

The CRM enforces a one active conversation per contact per channel rule: a contact can only have one non-finalized conversation open on a given channel at a time. Contact identity is derived from the platform user ID scoped to the workspace, so the same person (e.g. the same Telegram user ID) across two different Telegram bots resolves to the same CRM contact. If both Telegram bots are linked to the same CRM channel, that contact's second message will attempt to open a second conversation on the same channel and will be rejected with 409 Conflict. The integration cannot route both message streams simultaneously.

If you need to manage multiple accounts from the same platform, map each one to a different CRM channel.

Channel IDs are workspace-scoped, a channel ID from one workspace has no meaning in another.

Contact

A Contact is a person in the CRM - typically a customer. Contacts have a name, phone number, email, and optional custom attributes.

For chat integrations, each external platform user (e.g. a Telegram user ID) must be mapped to a CRM contact. Your third-party app is responsible for maintaining this mapping in its own database.

Agent

An Agent is a human support staff member who belongs to the CRM workspace. Agents handle conversations assigned to them, send replies, and resolve or finalize conversations. In message payloads, an agent appears as sender.type = AGENT.

Bot

A Bot is an automated chatbot configured within the CRM workspace. Bots can send messages in conversations, for example, to greet a contact or answer common questions, without human intervention. In message payloads, a bot appears as sender.type = BOT. Your third-party app should deliver bot messages to the platform user the same way it delivers agent messages.

Conversation

A Conversation is a thread of messages between a contact and the workspace's agents on a specific channel. Conversations have a status:

StatusMeaning
OPENActive - agents can send and receive messages
RESOLVEDClosed by an agent, but can be reopened
FINALIZEDPermanently closed - no more messages can be added. Attempting to send a message will return a 4xx error (as documented in the OpenAPI spec). A new conversation must be created if the contact messages again

Message

A Message is a single item in a conversation. Messages have a sender (who sent it) and a message_type.

These are the message types supported for the third-party app:

message typeMeaning
MESSAGEPlain text
ATTACHMENTA file, image, video, or audio

The sender type field tells you who sent the message:

sender typeMeaning
AGENTA CRM agent
BOTChatbot from the CRM system
CONTACTThe customer
SYSTEMAutomated system message (from automation rule)

Entity Relationships

Chat integration adds two more entities on top of the general App → Installation → Workspace foundation: Platform Account and Conversation. A Platform Account (one per Telegram bot) is linked to a CRM Channel and is the origin of conversations, each conversation tracks which Platform Account it came from.

For the base layer, how App, Installation, Access Token, and Workspace relate, see Third-Party App Foundation - Entity Relationships.

RelationshipCardinalityNotes
Platform Account → CRM ChannelMany-to-oneMultiple platform accounts can funnel into the same channel, but only if they are from different platforms. Linking two accounts from the same platform (e.g. two Telegram bots) to the same channel causes 409 Conflict when the same contact messages both: see the warning above
Platform Account → ConversationOne-to-manyEach conversation records which platform account it originated from, stored as platform_channel_id in your conversation mapping, needed to look up the correct access token for outbound messages
CRM Channel → ConversationOne-to-manyEvery conversation belongs to exactly one channel

Architecture

Your third-party app backend sits between the messaging platform and the CRM.

Inbound (user → CRM): The platform pushes a webhook when a user sends a message. Your backend looks up (or creates) the corresponding CRM contact and conversation, then POSTs the message to the CRM API. The agent sees it in real time.

Outbound (agent → user): When an agent replies, the CRM fires a message.created webhook event to your backend. Your backend looks up the platform user ID and the originating platform account (both from the conversation mapping), then calls that platform account's push API to deliver the reply to the user.

Your database holds everything that bridges the two systems, the CRM does not store any of this on your behalf:

What to storeDetails
CRM access tokenPer workspace. Used to call the CRM API on behalf of that workspace.
Platform account credentialsPer platform account (bot / OA / phone number): the CRM channel ID it is linked to, the platform app/channel ID, webhook secret (for signature verification), and access token (for outbound push messages).
Contact mappingsplatform_user_id → crm_contact_id, scoped to workspace. Used to look up (or create) the CRM contact on inbound messages, and to identify the platform user on outbound events.
Conversation mappingscrm_conversation_id → platform_user_id + platform_channel_id + crm_channel_id. platform_channel_id is the specific platform account (e.g. a Telegram bot) the conversation originated from, required to look up the correct platform_access_token when forwarding outbound messages.
Pending conversation recordscontact_id + platform_user_id + channel_id + platform_channel_id + workspace_id, written immediately after POST /v1/conversations. Because the conversation_id is not returned in the response, this record is what the conversation.created webhook handler uses to look up the originating request, verify the contact_id match, and complete the conversation mapping. Delete the record once the mapping is saved.
Message queueInbound messages that arrive after POST /v1/conversations but before conversation.created fires. These cannot be forwarded yet because there is no conversation_id. Queue them against the pending record (keyed by contact_id + channel_id + workspace_id) and forward them in order once the webhook is received and the mapping is complete.
Idempotency recordsProcessed platform message IDs to prevent duplicate handling when the platform retries delivery. Only recent records need to be kept, platform retry windows are typically hours, not days.

Typically, your backend will receive HTTP requests from two different sources:

SourceWhat It IsHow to Verify
Messaging platform (e.g. Telegram)Platform webhook - user sent a messagePlatform's own security mechanism - refer to your messaging platform's security documentation
CRMWebhook event - agent replied, conversation status changed, etc.X-Data-Signature header using your app's CRM Signing Secret

It is recommended to verify both webhooks before acting on the payload. See Webhook Handling.


Documents in This Section

#DocumentWhat It Covers
1Incoming MessagesReceiving platform webhooks, creating contacts & conversations, idempotency
2Outgoing MessagesReceiving CRM webhook events, forwarding agent replies to the platform, delivery status, all event payloads
3File and Media MessagesHandling image, video, audio, and file attachments in both directions; limits and allowed types
4Contact MappingMapping platform user IDs to CRM contacts, enrichment, custom attributes
5Platform Account SetupAdmin setup flow, platform account data model, multi-account management, and channel validation
6Error HandlingCommon failure scenarios and recommended strategies
7CRM API ReferenceAll CRM REST endpoints your third-party app will call: full OpenAPI specifications available in the API Requests guide

Quick-Start Checklist

Before you write a single line of code, complete these steps:

On the CRM Dashboard (see App Setup in the Dashboard):

  1. Create your app and copy all four credentials (App ID, Client ID, Client Secret, Signing Secret) to your backend environment variables.
  2. Add your OAuth callback URL to Redirect URLs.
  3. Select the minimum required scopes: chat:read, chat:write, contact:read, contact:write, channel:read.
  4. Enable webhook events and set your Request URL.
  5. Subscribe to webhook events: message.created, conversation.created, conversation.state-changed.

On the messaging platform side:

  1. Create a developer app / Official Account on the platform.
  2. Obtain credentials: App ID, App Secret, Channel Access Token.
  3. Configure the platform's Webhook URL to point to your third-party app backend.

On your backend:

  1. Expose public HTTPS endpoints for platform webhooks, CRM OAuth callback, and CRM webhook events.
  2. Implement signature verification for both sources (see Webhook Handling).
  3. Implement the OAuth callback and token exchange (see OAuth Flow).
  4. Implement the incoming message handler (see Incoming Messages).
  5. Implement the outgoing message / webhook event handler (see Outgoing Messages).

On this page