Documentation
Sign inGet started

Publishing events

Publish from your server using your Bird API key and the Realtime app's key and secret. Never ship the app secret in client code. To let subscribed clients exchange short-lived signals, use client events on private or presence channels.

A minimal publish

An event requires a name and at least one channel. Its optional payload can contain any JSON object, array, or scalar.
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({
  apiKey: process.env.BIRD_API_KEY,
  realtime: {
    key: process.env.BIRD_REALTIME_KEY,
    secret: process.env.BIRD_REALTIME_SECRET,
  },
});

await bird.realtime.publish("rap_01krdgeqcxet5s7t44vh8rt9mg", {
  event: "order-updated",
  channels: ["orders"],
  data: { id: 42, status: "shipped" },
});
Clients bound to order-updated on orders receive the event. The API rejects server-published names that start with the protocol prefixes bird: or bird_internal:. Client-originated event names must start with client-.
The full request and response, including every field, is in the publish an event reference.

What a 200 means

The publish completes after the Realtime edge accepts the event. Delivery is asynchronous and has no per-client receipt. A client that disconnects during delivery can miss the event, and Realtime does not replay it after reconnecting.
Store durable state in your database. Use events to announce changes, then have clients reload current state after reconnecting.

Broadcasting to several channels

One call can send the same event to up to 100 channels. A private-encrypted- channel must be the only channel in its publish because each encrypted channel uses a different key. The API rejects an encrypted fan-out with E23000. See Encrypted channels.
await bird.realtime.publish(appId, {
  event: "price-changed",
  channels: ["ticker-btc", "ticker-eth", "ticker-sol"],
  data: { at: "2026-07-31T09:00:00Z" },
});
Each target channel counts as a separate message for usage. This example counts as three messages. A publish to 10,000 per-user channels therefore counts as 10,000 messages.

Batching unrelated events

A broadcast sends one event to many channels. A batch sends up to 10 different events, each to one channel, in one request.
await bird.realtime.publishBatch(appId, {
  events: [
    { event: "order-updated", channels: ["orders-42"], data: { status: "shipped" } },
    { event: "stock-changed", channels: ["inventory-99"], data: { left: 3 } },
  ],
});
Use a batch to combine unrelated updates into one request. Each event still counts separately toward usage, and a batch accepts at most 10 events. See Publish a batch.

Excluding the client that acted

If a client already applied its action locally, pass its connection ID to prevent the resulting publish from applying the same change again. The edge skips only that connection.
await bird.realtime.publish(appId, {
  event: "message.created",
  channels: ["presence-room-1"],
  data: { body: "hello" },
  exclude_connection_id: "26896.319537",
});
Read the ID from the client's current connection and include it in the request that triggers the change. Other tabs use separate connections and still receive the event.

Reading channel state as you publish

Use include to return each target channel's state at publish time and avoid a separate channel-state request:
const result = await bird.realtime.publish(appId, {
  event: "order-updated",
  channels: ["presence-lobby"],
  data: { id: 42 },
  include: ["member_count", "connection_count"],
});
member_count works only on presence channels. connection_count requires connection counting on the app. Requesting these attributes counts as one extra message toward usage.

Caps

LimitValue
Channels per publish100
Events per batch10
Event payload10 KB serialized
Channel name164 characters, letters, digits, and _ - = @ , . ;
Event name200 characters
Exceeding any cap returns a validation error. The API does not truncate the request.

Retrying safely

Retry a publish with the same Idempotency-Key to avoid duplicate delivery. The TypeScript and Go SDKs generate a key and reuse it for automatic retries. If your application retries a request, supply and reuse its own key. See Idempotency.

Next steps