Publishing events
Publishing is a server-side call. It authenticates with your Bird API key and carries the app's own key and secret, so the edge knows which app the event belongs to. Clients never publish this way, because it would mean shipping the app secret to the browser. Clients that need to send events to each other use client events, a separate app setting that works only on private and presence channels.
A minimal publish
An event needs a name and at least one channel. The payload is optional, and any JSON value is allowed: an object, an array, or a scalar.
Contoh kode
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 the orders channel receive it. Event names are yours to choose, with one reservation: the bird: and bird_internal: prefixes belong to the protocol, and client- belongs to client events, so a publish using them is rejected.
The full request and response, including every field, is in the publish an event reference.
What a 200 means
Publishing resolves once the edge has accepted the event, not once clients have it. Delivery is asynchronous and there is no per-client receipt. A client whose connection drops during a publish misses that event, and Realtime does not replay it on reconnect.
Design for that. Store anything that must not be lost in your own database, use events to tell clients that something changed, and have the client re-read the current state after it reconnects.
Broadcasting to several channels
One call can name up to 100 channels, and the same event goes to all of them:
Contoh kode
await bird.realtime.publish(appId, {
event: "price-changed",
channels: ["ticker-btc", "ticker-eth", "ticker-sol"],
data: { at: "2026-07-31T09:00:00Z" },
});Each channel is a separate delivery for usage purposes, so this counts as three messages, not one. That arithmetic matters when a channel-per-user design meets a broadcast: fanning one event to 10,000 per-user channels is 10,000 messages.
Batching unrelated events
Broadcasting sends one event to many channels. A batch does the opposite: up to 10 different events, each to its own channel, in one request.
Contoh kode
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 it to collapse several unrelated updates into a single round trip, not to raise a throughput ceiling: the batch is 10 events, and each event still counts individually toward usage. See publish a batch.
Excluding the client that acted
When a client's own action causes the publish, sending the event back to that client makes it apply the same change twice: once locally, once from the event. Pass the acting client's connection id and the edge skips that one connection while delivering to everyone else.
Contoh kode
await bird.realtime.publish(appId, {
event: "message.created",
channels: ["presence-room-1"],
data: { body: "hello" },
exclude_connection_id: "26896.319537",
});The client reads the id from its own connection and sends it with the request that triggered the change. Only that connection is skipped, so the same user's other tabs still receive the event.
Reading channel state as you publish
include returns each target channel's state at the moment of the publish, which saves a second round trip when you want to know whether anyone was listening:
Contoh kode
const result = await bird.realtime.publish(appId, {
event: "order-updated",
channels: ["presence-lobby"],
data: { id: 42 },
include: ["member_count", "connection_count"],
});member_count works on presence channels only, and connection_count requires the app's connection-counting setting. Requesting attributes counts as one extra message toward usage, so ask for them when you will use them.
Caps
| Limit | Value |
|---|---|
| Channels per publish | 100 |
| Events per batch | 10 |
| Event payload | 10 KB serialized |
| Channel name | 164 characters, letters, digits, and _ - = @ , . ; |
| Event name | 200 characters |
Exceeding any of them is a validation error rather than a truncation, so nothing is silently dropped.
Retrying safely
Retrying a publish with the same Idempotency-Key delivers the event once. The TypeScript and Go SDKs generate a key for you and reuse it across their automatic retries, so a transient network failure does not produce a duplicate. If you retry from your own code, send your own key. See Idempotency.
Next steps
- Authorizing channels is what a private- or presence- channel needs before a client can subscribe.
- Realtime overview explains channels, members, and connections, and where usage shows up.
- Excluding event recipients keeps the acting client from receiving its own change.