Skip to main content
Beta is a preview. The Beta (2.0) platform does not have all the features of Stable yet. For example, iMessage on Beta supports only text and images, so tapbacks, polls, message effects, and voice notes are only on Stable for now. Use Stable for production agents, and confirm that Beta supports the features you need before you buy a plan.
@photon-ai/chat-adapter connects Chat SDK bots to the channels connected to a Photon Beta project: iMessage, SMS, WhatsApp, WhatsApp Business, Telegram, and email. It calls the Photon API with a project API key and receives events through signed webhooks or a WebSocket connection. This guide covers the published 0.1.0 adapter and Chat SDK 4.44.0. The source and issue tracker are maintained by Photon.
This replaces the retired @photon-ai/chat-adapter-imessage adapter. It uses createPhotonAdapter() and adapters.photon, not createiMessageAdapter() and adapters.imessage. See Migrating from the iMessage adapter.

Installation

Use Node.js 20 or later in a server-side application:
The examples use Redis for Chat SDK state, subscriptions, deduplication, and the WebSocket resume cursor. Any Chat SDK state adapter works; an in-memory adapter loses this state on restart and does not share it between serverless invocations.

Configuration

  1. Set up a Beta project and API key. Use a project API key with project:read and project:write for receiving messages and sending replies.
  2. Connect the channels you want to use in the Beta dashboard. Start with the iMessage or email guide.
  3. Set these variables in your server’s environment or secret manager. For local development, use a gitignored .env.local file:
.env.local
Run Redis at REDIS_URL, or replace it with your hosted Redis connection URL. Never put keys, signing secrets, or Redis credentials in browser code or commit them to source control. Options passed to createPhotonAdapter() override environment variables. The optional userName option controls group mention matching; it defaults to the Chat instance’s userName. REDIS_URL belongs to createRedisState(), not the Photon adapter.

Add the adapter

Register the adapter as photon. Direct messages reach onDirectMessage. In groups, this example subscribes when someone mentions @mybot, then replies to subsequent messages in that Space.
lib/bot.ts
Test an echo bot from your own phone or account, not another automated line in the same project. Photon can report that other line as a human sender, so two echo bots can keep replying to each other.

Receiving messages

Choose a webhook for a public HTTPS backend, or WebSocket delivery for a process without a public URL. Both deliver message.received events to the same Chat SDK handlers.

Webhooks

Create a webhook destination pointing at your bot’s HTTPS route and subscribe to message.received. Save its signing secret as PHOTON_WEBHOOK_SECRET in the server environment. For example, in Next.js, with the @/ alias pointing at your application root:
app/api/webhooks/photon/route.ts
Pass the original Request; do not parse or reserialize its body first. bot.webhooks.photon initializes the bot and verifies the Standard Webhooks headers: webhook-id, webhook-timestamp, and webhook-signature. Invalid or expired signatures return 401; a missing signing secret returns 500. Events other than message.received are acknowledged without invoking handlers. On serverless hosts, pass the host’s background-task hook as waitUntil so handlers can finish after the response. The 200 response acknowledges the event, not successful completion of your handler or delivery of its reply.

WebSocket gateway

The gateway uses Photon’s Socket.IO event stream. It needs the project ID and API key, but no webhook destination or signing secret. Initialize the bot before starting the listener:
gateway.ts
For this TypeScript runner, use Node.js 24 in a project with "type": "module":
The listener runs in the background for three minutes by default. It reconnects after transient disconnects and stores its event sequence cursor in the Chat SDK state adapter, so a later connection can resume. For serverless deployments, prefer the webhook example above.

Threads and direct messages

A thread represents a Photon Space and the Agent that received the message: photon:<spaceId>:<agentUserId>:<spaceKind>. Replies use that Agent, including in a fresh webhook invocation. Direct Spaces are DMs; group Spaces use the mention and subscription handlers. To start a conversation, set PHOTON_AGENT_USER_ID to a connected Agent User and pass an existing Photon User ID, not a phone number, to the adapter’s openDM:
Call the adapter explicitly: Chat SDK 4.44.0’s bot.openDM() does not recognize Photon User IDs. The adapter finds or creates the direct Space between the Agent and that User. Use an Agent and recipient on the same platform; the platform’s messaging rules still apply.

Feature support

Support depends on the connected platform. An unsupported operation raises Chat SDK’s NotImplementedError; typing is a no-op on platforms without it. Reactions, edits, and deletions arrive as content inside message.received; they do not require separate webhook event subscriptions.

Migrating from the iMessage adapter

This is a new adapter and API, not a drop-in package rename. Keep the legacy guide for an existing Spectrum integration. Create a Beta project, connect its channels, replace the credentials and webhook destination, and review feature support before switching traffic. Old thread IDs, subscriptions, and gateway cursors are not portable; use a separate state store or namespace for the new bot.