Developer Docs Logo
Customer Chat

Platform Account Setup

This document covers how to set up and manage the connection between platform accounts and CRM channels. For channel concepts and constraints, see Customer Chat Integration - Channel.


Admin Setup Flow

This is the process an admin follows when connecting a new platform account to the CRM.


Discovering Channels

Call GET /v1/channels with the workspace's access token to get the list of channels. Present these to the admin as a dropdown during platform account setup.

GET /v1/channels
Authorization: Bearer {workspace_access_token}

Response:

{
  "data": [
    {
      "id": "ch_aaa111",
      "name": "Telegram - TH Support"
    },
    {
      "id": "ch_bbb222",
      "name": "Web Widget"
    }
  ],
  "metadata": {
    "after": "...",
    "before": "..."
  }
}

The response is paginated. Use the after cursor to fetch additional pages if needed. Each item has id and name, there is no type field in the channel list response.

Validate the admin-selected channel_id exists in the list before saving - don't trust user input blindly.


Platform Account Data Model

Each row in this table represents one platform account linked to one CRM channel in one workspace.

Note: This schema is provided as an example/guideline. You may adapt it to your specific requirements, database system, and naming conventions.

CREATE TABLE platform_account_mappings (
    id                    UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    account_id            TEXT NOT NULL UNIQUE,  -- platform's stable account/bot identifier
    workspace_id          TEXT NOT NULL,
    channel_id            TEXT NOT NULL,          -- CRM channel ID
    platform_app_id       TEXT NOT NULL,          -- admin-entered platform app/channel ID
    platform_secret       TEXT NOT NULL,          -- for webhook signature verification
    platform_access_token TEXT NOT NULL,          -- for push API
    created_at            TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_account_mappings_workspace ON platform_account_mappings(workspace_id);

account_id is the stable identifier the platform includes in every webhook (e.g. the Telegram bot's id). This is how your webhook handler knows which platform account received the message. It is also stored as platform_channel_id in your conversation mapping table, used when forwarding outbound messages to look up the correct platform_access_token for the originating platform account.


Webhook Routing

Every incoming platform webhook includes the account/bot identifier. Your handler extracts it first (before or as part of signature verification), then uses it to look up the correct workspace and channel:

// Called after signature has been verified using mapping.platformSecret
async routeWebhook(accountId: string, payload: RawPayload): Promise<void> {
  const mapping = await this.db.getAccountMapping(accountId);
  if (!mapping) {
    // This webhook is from an account we don't manage - ignore silently
    return;
  }

  // mapping.workspaceId → which CRM workspace to use
  // mapping.channelId   → which channel to create conversations in

  await this.processMessage(mapping, payload);
}

Supporting Multiple Platform Accounts

A single installation of your third-party app can manage multiple platform accounts for the same workspace. This is a common requirement (e.g. a company with Telegram bots in Thai and English).

Warning: Multiple accounts from the same platform must not share a CRM channel.

The CRM enforces a one active conversation per contact per channel rule. Contact identity is scoped to (platform_user_id, workspace_id), so the same person across two Telegram bot accounts is still the same CRM contact. If both Telegram bots point to the same CRM channel, that contact can have one ongoing conversation through each account, but the CRM only allows one non-finalized conversation per contact per channel. The second conversation attempt will be rejected with 409 Conflict, making it impossible to route both message streams.

The correct configuration: each platform account from the same platform must map to a distinct CRM channel. Accounts from different platforms may safely share a channel because their user IDs are separate and would never resolve to the same contact.

Your admin settings page should:

  1. List all currently linked accounts (from your DB for that workspace).
  2. Provide an "Add Account" button that triggers the platform credential form + channel picker.
  3. Allow the admin to remove an account (delete the mapping row).

Channel Validation During Setup

When the admin selects a channel ID from your picker, verify it before saving:

async validateChannel(crmToken: string, channelId: string): Promise<void> {
  const channels = await this.crmClient.listChannels(crmToken);

  const found = channels.some((ch) => ch.id === channelId);
  if (!found) {
    throw new Error(`channel "${channelId}" not found in workspace`);
  }
}

Channel Best Practices

  • Index your platform_account_mappings table by account_id for fast webhook lookups.
  • When an admin deletes a platform account, also clean up any conversation mapping rows that referenced its account_id (stored as platform_channel_id) for that workspace.
  • Cache the channel list from GET /v1/channels for a short period (e.g. 5 minutes) to avoid repeated API calls during setup - but re-fetch before saving a mapping to ensure freshness.

On this page