Skip to content

Push notifications

When the user is offline (the app is closed), an Intercom webhook tells the backend an operator replied — and the backend sends a push so the user comes back. When the app is open, polling already delivers everything, so no push is sent.

There are two channels, both optional and both no-op until configured:

ChannelPlatformTransport
FCMiOS + Android (React Native)Firebase Cloud Messaging
TelegramTelegram Mini App (TMA)Telegram Bot API

How it flows

Operator replies in Intercom
   └─▶ Intercom webhook  →  POST /webhooks/intercom
          └─▶ verify signature → 200 → (async) look up the user's devices + prefs
                 ├─ device.platform = "mobile" → FCM.send(token, …)
                 └─ device.platform = "tma"    → Telegram.sendMessage(chatId, …)

The SDK registers the device for you: when you pass fcmToken (mobile) or telegramChatId (TMA) to <AWChat />, it calls POST /api/devices/register automatically. On logout, teardown() (web) / unmount (RN) unregisters it.

You never call the device API yourself — you only need to (1) configure the server, and (2) obtain the token/chat-id and pass it as a prop.


A) FCM — mobile (iOS + Android)

1. Server: add the Firebase service account

  1. In the Firebase console, open (or create) the project for your app.

  2. ⚙︎ Project settings → Service accounts → Generate new private key. This downloads a JSON file (keep it secret — it grants send rights).

  3. Put that JSON on the server (or mount it as a secret) and point the env var at its path:

    bash
    FCM_SERVICE_ACCOUNT=/etc/aw-chat/firebase-sa.json

That's all the server needs. If the var is unset or the file is missing, FCM calls are skipped (logged, never crash).

2. App: get the device's FCM token

In the React Native app, use Firebase Messaging (e.g. @react-native-firebase/messaging): request notification permission, then read the token.

ts
import messaging from "@react-native-firebase/messaging";

await messaging().requestPermission();        // iOS prompt; Android auto on <13
const fcmToken = await messaging().getToken(); // the device token

iOS also needs an APNs key uploaded in Firebase (Project settings → Cloud Messaging → Apple app configuration). Android works once google-services.json is in the app. This is standard Firebase setup, outside the SDK.

3. App: pass it to <AWChat />

tsx
<AWChat
  userId={user.id}
  sessionToken={token}
  serverUrl={SERVER}
  telemetry={{ appVersion: "6.1.4", hardwareId: "iPhone15,2", osVersion: "iOS 17.4", deviceLang: "ru" }}
  fcmToken={fcmToken}   // ← registers this device for mobile push
/>

The SDK registers it (platform: "mobile"). Refresh it when Firebase rotates the token (messaging().onTokenRefresh) by re-mounting with the new value.

4. Payload the device receives

json
{
  "notification": { "title": "Поддержка", "body": "Новое сообщение от оператора" },
  "data": { "type": "chat", "conversationId": "123456" }
}

data.type is chat | ticket | system; conversationId or ticketId is set; csat: "true" is present when a resolved ticket should trigger the CSAT popup. Map these to initialRoute + targetId when the user taps the notification (see Deep linking).


B) Telegram — Mini App (TMA)

1. Create the bot and Mini App

  1. In Telegram, talk to @BotFather/newbot → choose a name and username. BotFather returns the bot token — this is TELEGRAM_BOT_TOKEN.
  2. Attach your Mini App URL to the bot (/newapp in BotFather, or Bot Settings → Configure Mini App). The bot's username (without @) is TELEGRAM_BOT_USERNAME — it's what builds the deep-link button.

2. Server: set both env vars

bash
TELEGRAM_BOT_TOKEN=7123456:AAF...      # from BotFather
TELEGRAM_BOT_USERNAME=AWBot            # the bot's username, no @

Unset → Telegram pushes are skipped (logged, never crash).

3. App: pass the Telegram user id

Inside the Mini App (running @aw-chat/web), read the Telegram user id from the WebApp SDK and pass it as telegramChatId:

tsx
const tg = window.Telegram.WebApp;

<AWChat
  userId={awUserId}
  sessionToken={token}
  serverUrl={SERVER}
  telemetry={{ appVersion: "6.1.4", hardwareId: "tma", osVersion: "tma", deviceLang: tg.language_code }}
  telegramChatId={String(tg.initDataUnsafe.user.id)}   // ← registers TMA push
  theme={tg.colorScheme}
/>

The SDK registers it (platform: "tma", the chat id is the token).

The user must have pressed Start on the bot at least once. Telegram's Bot API can only message a chat_id that opened a conversation with the bot; otherwise sendMessage returns 403. Opening the Mini App through the bot normally satisfies this.

The push is a normal bot message with an inline button:

Поддержка
Новое сообщение от оператора
[ Открыть чат ]  → https://t.me/<TELEGRAM_BOT_USERNAME>/app?startapp=chat_123456

The startapp payload is <type>_<id> (e.g. chat_123456, ticket_98765). When the Mini App launches, read it and route in:

ts
const param = tg.initDataUnsafe.start_param;   // "chat_123456"
const [type, id] = param ? param.split("_") : [];
// → <AWChat initialRoute={type === "ticket" ? "ticket" : "chat"} targetId={id} skipWelcome />

Notification preferences

Each user can mute a category. The SDK reads/writes them; the dispatcher checks them before sending, so a muted category delivers nothing.

MethodPathBody
GET/api/settings/notifications— (defaults: all on)
PUT/api/settings/notifications{ chatMessages?, ticketUpdates?, systemNotices? }
  • chatMessagestype: "chat" pushes
  • ticketUpdatestype: "ticket" pushes
  • systemNoticestype: "system" pushes

One user, multiple devices

A user can have several registered devices (e.g. a phone + the Mini App). The dispatcher fans out to all of them; one device failing never blocks the others. Each registration upserts by (user, token), so re-passing the same token won't create duplicates.

Troubleshooting

SymptomCheck
No push at allIs the device registered? (passing fcmToken/telegramChatId triggers POST /api/devices/register.) Is the category enabled? Are the server env vars set?
Logs say [fcm] skipped (not configured)FCM_SERVICE_ACCOUNT is unset or the file path is wrong.
Logs say [telegram] skipped (not configured)TELEGRAM_BOT_TOKEN is unset.
Telegram 403The user never pressed Start on the bot — Bot API can't open a chat.
Button missing on Telegram pushTELEGRAM_BOT_USERNAME is unset (no username → no deep link).
iOS gets nothing, Android worksAPNs key not uploaded in Firebase, or missing push entitlement.

Webhooks are the trigger for all of this — if pushes never fire, confirm the Intercom webhook is configured and verifying. See Webhooks.

AW Chat SDK — internal integration docs.