> ## Documentation Index
> Fetch the complete documentation index at: https://docs.photon.codes/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Use Stable documentation by default. Honor an explicit Beta request or a URL under /docs/beta/. If the requested version conflicts with the installed CLI package or API origin, clarify the target before writing integration code.
> Pages under /docs/beta/ document Beta; other product pages document Stable. Keep the CLI package, commands, API origin, and credentials within the selected version. State the documentation version in your answer.
> For MCP search, always pass version: Stable or version: Beta. Unfiltered search mixes both versions. For filesystem reads, keep Beta queries under /beta/ and exclude /beta/ from Stable queries; discover paths before reading them.
> The public docs base is https://photon.codes/docs. Convert MCP page paths to public URLs under that base, preserving /beta/ when present. Read https://photon.codes/docs/skill.md for version selection and https://photon.codes/docs/llms.txt for the version indexes.

# WebSocket

> Receive project events with Socket.IO and resume from your last processed cursor.

Keep a connection open to receive project events without hosting a public
HTTPS receiver. This is useful for local development and long-running backend
workers. Use [Webhook](https://docs.photon.codes/docs/beta/message-delivery/webhook.md) when Photon should push
events to your HTTP endpoint instead.

Photon uses **Socket.IO**, not a raw WebSocket protocol. Use `socket.io-client`
in Node.js or another compatible client. A native `WebSocket` client cannot
subscribe to this protocol.

## Connect to your project

You need a [project and API credential](https://docs.photon.codes/docs/beta/get-started/project.md) with
`project:read` access to that project. Each connection subscribes to one project.
You do not need to create a webhook destination first.

```bash npm theme={null}
npm install socket.io-client
```

```bash pnpm theme={null}
pnpm add socket.io-client
```

```bash yarn theme={null}
yarn add socket.io-client
```

```bash bun theme={null}
bun add socket.io-client
```

Set `PHOTON_PROJECT_ID` and `PHOTON_API_KEY` in your server's environment.
Create the connection without starting it, so you can register listeners first:

```ts theme={null}
import { io } from "socket.io-client";

const socket = io("https://api.photon.codes", {
  path: `/v1/projects/${process.env.PHOTON_PROJECT_ID}/events/ws`,
  addTrailingSlash: false,
  transports: ["websocket"],
  extraHeaders: { Authorization: `Bearer ${process.env.PHOTON_API_KEY}` },
  autoConnect: false,
});
```

Set the project route in `path`, not in the URL passed to `io()`.
Use Socket.IO's default namespace. Photon does not support polling.

> [!WARNING]
>
> Keep your credential on the server. A browser cannot supply this authorization
> header on a websocket-only connection. Direct connections from customer
> browser applications cannot use this endpoint.

## Subscribe and receive events

Before calling `socket.connect()`, register handlers for `connect`, `delivery`,
`delivery_error`, and `connect_error`.

A **cursor** marks your progress through the event stream. Use it to resume
after a disconnection.

1. On every `connect`, emit `subscribe` with `{ startSeq }` and an acknowledgement
   callback. Use `0` for new events. To resume, use the cursor of the last event
   you successfully processed. You can also set `apiVersion` to choose a
   selectable payload version.
2. Check the acknowledgement's `ok` field. A successful subscription returns the
   accepted API version, connection ID, cursor, and limits before deliveries
   begin. Send only one successful subscription per connection.
3. Handle `delivery(event, metadata)`. The event is the same parsed public JSON
   object as a webhook for that event and API version. The metadata contains
   `seq`, the cursor, and `replyExpected`.

Use the [Node.js example](https://docs.photon.codes/docs/beta/websocket/example.md) for a queue that processes one event at a time
and reconnect handling. The [session guide](https://docs.photon.codes/docs/beta/websocket/session.md) and
[event guide](https://docs.photon.codes/docs/beta/websocket/events.md) describe the command and delivery shapes.

## Resume without skipping work

Process one event at a time. Save `metadata.seq` to durable storage only after
processing succeeds.
If your last processed cursor is `42`, reconnect with `startSeq: 42`, not `43`.
Cursors can have gaps. Use the value Photon gives you; do not calculate the
next value. Store a separate cursor for each project and each independent
application that processes its events.

Socket.IO reconnects automatically after temporary connection failures. For
authentication errors or an explicit server disconnect, fix the cause before
you call `socket.connect()` again. Your application
must subscribe again with its saved cursor. Do not reset the cursor to `0` on
every connection. That starts with new events and skips the disconnected period.
If a handler fails, stop the stream before you process later events. Resume
from the last cursor you successfully saved.

The server does not wait for your event handler to finish. A reconnection can
deliver the same event again, so prevent duplicate work in your handler.
Photon can replay only events it still retains. Replay is not an unlimited
archive and does not guarantee exactly-once processing. See
[Cursors and replay](https://docs.photon.codes/docs/beta/websocket/cursors.md) and
[Errors and reconnection](https://docs.photon.codes/docs/beta/websocket/errors.md) for recovery details.

## Reply when the event requests it

When `metadata.replyExpected` is true, the connection can submit a synchronous
HTTP response through the Socket.IO `reply` command. This requires `project:write`.
Send the reply before the event's deadline expires. It is not a chat message.
Send chat replies through the messaging API.

See [Reply to a webhook event](https://docs.photon.codes/docs/beta/websocket/replies.md) for the reply format and
the [frame reference](https://docs.photon.codes/docs/beta/websocket/frames.md) for the complete protocol.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.