Guides

Social channels — Messenger, Instagram, Telegram, Discord, SMS, Apple, LINE, Viber

AdminUpdated Sep 19, 2026

Social channels — Messenger, Instagram, Telegram, Discord, SMS, Apple, LINE, Viber

One inbox, every social DM. All BYOK access tokens — Chatly never owns your audience.

Every social channel in Chatly follows the same pattern: you bring the access token from the platform's developer console, paste it into a new channel, and we handle webhooks, threading, attachments, and outbound.

The credentials remain yours — if you ever stop using Chatly, you keep your Page, your bot, your phone numbers, your audience.

Info — One inbound URL for every channel

There are no per-provider ingest paths. Every provider that delivers over HTTP posts to /v1/channels/webhook/{publicId}, where publicId is the id you chose when you created the channel. The channel detail screen prints the exact URL for copy-paste — use that, not a hand-written one.

POST /v1/channels/webhook/{publicId} — Public

GET /v1/channels/webhook/{publicId} — Public

The GET handler exists purely for Meta's hub.challenge handshake and Slack's url_verification POST is answered before any channel lookup, so both platforms can save a Request URL while you are still configuring.

Every channel below produces the same conversations + messages rows. Routing, AI, RAG, copilot and reports are channel-agnostic; the channel-specific logic lives in apps/api/src/modules/channels/adapters and is invisible to the rest of the app.

Warning — Creating a channel needs a publicId you choose

POST /v1/channels requires publicId (1–64 characters, unique across the deployment) and rejects a body without one. It cannot be changed afterwards, because it is part of your webhook URL. Saving a channel never test-calls the provider — a wrong credential looks connected until traffic arrives.

Facebook Messenger

Setup

  1. Create a Facebook App and connect it to a Page you own in Meta Business Manager.

  2. Subscribe the Page to the messages webhook field.

  3. Generate a Page Access Token (long-lived, via a system user).

  4. Channels → New → Messenger. All four fields are required:

Parameters

Name

Type

Description

pageId (required)

string

Facebook Page ID.

pageAccessToken (required)

password

Long-lived Page access token.

appSecret (required)

password

Verifies the X-Hub-Signature-256 header on every inbound POST.

webhookVerifyToken (required)

password

A random string you choose. Type the same value into Meta's Callback URL form.

Webhook

In Meta App → Webhooks → Page → Callback URL:

https://api.chatlychat.com/v1/channels/webhook/{publicId}

Signature failures are rejected with 403, verified over the exact bytes Meta signed.

The 24-hour window

Messenger enforces a 24-hour rolling window after the user's last interaction, and outside it Meta requires a message tag.

Warning — Chatly does not send message tags

Outbound Messenger sends are hardcoded to messaging_type: 'RESPONSE'. There is no tag field, no HUMAN_AGENT support, and no composer prompt for one — a send outside the window will simply be refused by Meta.

Instagram DMs

Instagram Direct rides the Meta Graph API, so this is set up exactly like Messenger — through the linked Facebook Page.

Setup

  1. Your Instagram account must be a Business or Creator account linked to a Facebook Page.

  2. Required permissions on the Meta App: instagram_basic, instagram_manage_messages, pages_messaging.

  3. Channels → New → Instagram. The fields are the same four as Messenger — note the first one:

Parameters

Name

Type

Description

pageId (required)

string

The linked Facebook Page ID, not the Instagram Business Account ID.

pageAccessToken (required)

password

Token for the Page that owns the IG account.

appSecret (required)

password

Webhook signature verification.

webhookVerifyToken (required)

password

Your chosen handshake string.

Same callback URL shape as Messenger. Inbound Instagram messages are stamped with the instagram channel type (not messenger), so the Instagram inbox filter and Instagram reporting see them.

Info — What is not wired

Story replies, ice-breakers, mentions and comment-to-DM automations are Meta webhook fields the adapter does not parse. Only direct messages become conversations.

Telegram

The simplest social channel — no business approval, no 24-hour window.

Setup

  1. Open Telegram, message @BotFather, send /newbot. Save the token.

  2. Channels → New → Telegram:

Parameters

Name

Type

Description

botToken (required)

password

From BotFather's reply to /newbot.

botUsername (required)

text

e.g. @yourbot.

webhookSecret

password

Optional — leave blank and Chatly generates one. Telegram echoes it on every delivery, which is how we know a request really came from Telegram.

  1. On save, Chatly calls Telegram's setWebhook for you, pointing at /v1/channels/webhook/{publicId} with the secret token and allowed_updates: ["message", "edited_message", "callback_query"]. The result rides back on the API response, so a failure to register is visible immediately rather than as permanent silence. Re-saving retries.

Info — Telegram bots are BYOK, and so is the userbot

There is no platform-level Telegram credential. The bot channel uses your bot token. The separate Telegram user channel (MTProto) is also bring-your-own: there is no platform TELEGRAM_API_ID or TELEGRAM_API_HASH — the api_id / api_hash pair lives per-workspace on integration_installs.

What works

  • 1:1 DMs to the bot.

  • Group messages, subject to BotFather's privacy setting.

  • Edited messages and callback-query taps.

Discord

Warning — Discord does not deliver over HTTP

Discord is the one channel that does not use the ingest route. Messages arrive over a WebSocket held open by a separate service, apps/discord-gateway. If that service is not running, a Discord channel is configured, shows no error, and receives nothing.

Setup

  1. Discord Developer Portal → New ApplicationBot.

  2. Enable the MESSAGE CONTENT privileged intent on the application. Without it Discord delivers every message with an empty content, and the bot appears to receive nothing useful.

  3. Add the bot to your server with the OAuth2 URL Generator: scope bot, with Read Messages and Send Messages.

  4. Channels → New → Discord — or click Connect to authorise through the built-in Discord OAuth flow:

Parameters

Name

Type

Description

guildId (required)

text

The server (guild) ID, not the application ID. Turn on developer mode in Discord, right-click the server, Copy Server ID.

botToken (required)

password

From your bot application in the developer portal.

publicKey (required)

password

Ed25519 key used to verify interaction-endpoint signatures.

What works

The gateway subscribes to GUILD_MESSAGES, DIRECT_MESSAGES and MESSAGE_CONTENT, and files every non-bot message that has content. Conversations are keyed on the Discord channel_id, so a thread is its own conversation. Outbound goes to POST /channels/{channelId}/messages on Discord's v10 API.

Info — Slash commands are not routed

The adapter can verify an interaction signature, but only MESSAGE_CREATE is turned into a conversation. Slash commands and component interactions are dropped.

SMS

BYOK carrier — Twilio, Telnyx or SignalWire. The SMS channel carries its own credentials; it does not share them with a Voice channel, and the two store them in different shapes.

Parameters

Name

Type

Description

provider (required)

enum

twilio | telnyx | signalwire. Defaults to twilio when unset or unrecognised.

fromNumber (required)

string

E.164 sender. phoneNumber is accepted as a legacy alias for channels created before the rename.

accountSid + authToken

string

Twilio.

apiKey

string

Telnyx.

spaceUrl + projectId + apiToken

string

SignalWire — the API is rooted at your own space, not at api.twilio.com.

Point your carrier's inbound SMS webhook at the shared ingest URL:

https://api.chatlychat.com/v1/channels/webhook/{publicId}

Twilio's signature is verified against the public URL rebuilt from the proxy's forwarding headers, so a deployment behind Traefik or a load balancer verifies correctly. The receiver answers 200 rather than Nest's default 201, because Twilio logs error 12300 on anything else.

MMS carries images and video only. Audio and documents are sent as a link in the message body instead — Twilio's MMS does not accept them.

Warning — A2P 10DLC + TCPA — your problem, not ours

US SMS senders must register their brand + use case with The Campaign Registry for A2P 10DLC. TCPA requires written consent for marketing SMS. Chatly records per-channel consent on contact_channel_consent — and for SMS, like WhatsApp, no row means refused — but complying with the law is your responsibility.

Apple Business Chat

Apple requires a business of record approved via Apple Business Register, plus an integration through a Messaging Service Provider.

Setup

  1. Get approved on Apple Business Register (a real-world process, ~weeks).

  2. Channels → New → Apple Business Chat:

Parameters

Name

Type

Description

businessId (required)

text

From Apple Business Register, under your business profile. Matched against the destinationId on every inbound envelope.

cspAuthToken (required)

password

CSP auth token. Required by the outbound sender — without it every reply is skipped as no_workspace_creds.

webhookSecret

password

Optional additional secret.

Webhook

Apple is the other exception to the shared ingest route. The MSP relay verifies Apple's JWT and forwards a normalised envelope to a dedicated receiver:

POST /v1/webhooks/apple-bc — Public

There is one URL for the whole deployment — no publicId in it. The workspace is resolved from destinationId on the envelope. The receiver authenticates with a Bearer token checked against the deployment-wide APPLE_BC_CSP_AUTH_TOKEN environment variable, so a self-hoster has to set that before any Apple traffic is accepted.

Inbound envelopes carry text, interactive or attachment types; interactive payloads (list pickers, time pickers, Apple Pay, forms) are persisted verbatim rather than rendered as native composer controls.

LINE

The dominant chat app in Japan, Taiwan, and Thailand.

Setup

  1. Create a LINE Official Account + a Messaging API channel in the LINE Developers Console.

  2. Channels → New → LINE:

Parameters

Name

Type

Description

channelId (required)

text

LINE Messaging API channel ID.

channelSecret (required)

password

Verifies the webhook signature.

channelAccessToken (required)

password

Use a long-lived token. Encrypted at rest.

  1. Webhook URL: https://api.chatlychat.com/v1/channels/webhook/{publicId}

Viber

Common in Eastern Europe + Southeast Asia.

Setup

  1. Create a Viber Business Account at partners.viber.com.

  2. Channels → New → Viber:

Parameters

Name

Type

Description

authToken (required)

password

From your Viber Business account dashboard.

botName (required)

text

Shown to customers in the chat header.

avatarUrl

url

Optional. Shown as the bot avatar in Viber.

  1. Webhook: https://api.chatlychat.com/v1/channels/webhook/{publicId}

Cross-channel behaviour

Parameters

Name

Type

Description

Inbound signature verification

always-on

Each provider's own scheme, checked over the raw request bytes before anything is persisted. A bad signature is a 403; an unparseable payload is a 400, never a 500 that invites the provider to retry forever.

Batched deliveries

always-on

A webhook carrying several messages is dispatched sequentially, not in parallel — concurrent creates would race and split one thread in two.

Threading

always-on

Matched on the provider's thread key (external_conversation_id) regardless of conversation status, so a customer replying to a closed thread continues it. With no key, the newest open conversation for that contact on that channel wins.

Outbound routing

per-channel

Email, SMS, Telegram, Discord and Messenger are called directly by the worker. WhatsApp, Instagram, LINE, Viber, Apple, Slack, Teams and TikTok go through the API process, which owns their stateful or centralised auth.

Outbound retries

configurable

BullMQ with exponential backoff, 8 attempts on the delivery queue.

Attachments

pass-through

Carried through by the URL the provider hosted them at. There is no download, no MIME sniffing and no virus scanning anywhere in the inbound path.

Warning — Inbound is not deduplicated

Providers retry webhooks. The provider's message id is stored on messages.metadata.externalMessageId but nothing checks it before inserting, and there is no unique index on it — a redelivered webhook creates a second message in the thread.

One contact across channels

Warning — Cross-channel identity is not automatic

Contact upsert matches on externalId only — the provider's own id for that person. It does not match on email or phone, so the same human writing from Instagram and from email becomes two contacts. Merge them deliberately with POST /v1/contacts/{id}/merge, which is one of the routes an API key can call.

Once merged, the inbox is conversation-first: an agent handles whatever comes in across email, WhatsApp, chat and Instagram, and replying uses that conversation's channel credentials.

Troubleshooting

Warning — A channel is configured and nothing ever arrives

Work through the transport, not the credentials. Discord needs apps/discord-gateway running. Telegram needs the setWebhook call to have succeeded — re-save the channel and read the registration result. Everything else needs the provider pointed at /v1/channels/webhook/{publicId}; an older hand-written path such as /v1/webhooks/{type}/{id} has never been served and 404s.

Warning — 404 on a webhook URL that looks right

The channel is disabled. The ingest route only resolves channels with enabled = true, and answers 404 for a disabled one exactly as it would for a wrong id.

Info — Telegram bot doesn't see group messages

Bots get group messages in two modes: privacy mode on (only sees @mentions + replies) or privacy mode off (sees everything). Toggle via BotFather → /setprivacy. Off is usually what you want for support bots.

Info — Why most platforms won't let you message first

WhatsApp, Messenger, Instagram and LINE all require the customer to message you first. Chatly does not add its own gate for those — the platform refuses the send. TikTok is the exception we do enforce locally: its policy allows no re-engagement of any kind, so the adapter refuses a first message outright and TikTok is excluded from the campaign channel list.

Was this page helpful?