pusher.trigger(). This page explains what the button actually does,
how to read the response card, and how to turn the form into a signed
REST request that your own server can send.
The screen needs three things before it will publish: a signed-in
session, an org, and a selected app. Without a session it prompts you to
sign in at the portal; without an app it sends you to Apps & keys.
What the console publish does differently from a signed REST call
The console does not sign a REST request. It calls the control-plane procedurerealtime.publish (an org-scoped procedure) with
{ orgId, appId, channel, event, data }. The control-plane API then
RPUSHes the publish body onto the engine’s generic BFF-to-engine ring
(clutchcall:realtime:ring) — the same bus the presence and
assist bridges ride.
Two consequences follow, and they are the reason console results can
differ from your server’s results:
- No per-deployment HTTP configuration is involved. The publisher is always reachable from the console, because it writes to the ring rather than to an engine HTTP endpoint.
- The control-plane API is an authorized publisher.
private-*andpresence-*channels are legitimate targets from this screen, and the form never blocks those prefixes. Channel authorization that a browser subscriber would have to pass does not apply to the publish side here.
Reading the three response states
The API response card renders one of three outcomes, driven by theok and wired fields of the procedure result.
Before you press Send event, the card shows an empty state: “No
response yet.”
A fourth outcome is not part of the card at all — see
Telling a transport failure from a rejected publish.
Queued delivery and what it guarantees
queued is a success state, not a failure. The ok: true means the
control-plane API wrote your publish body onto the BFF-to-engine ring.
The wired: false means it could not observe an engine heartbeat at that
moment. The engine picks the entry up when it reconnects and drains the
ring.
What the state tells you:
- The body was accepted. You do not need to retry the form to get the event onto the ring; retrying enqueues a second copy.
- Delivery is deferred, not cancelled.
- It does not confirm delivery. Fan-out to channel subscribers happens engine-side after the ring is drained. Nothing in this response reflects whether any subscriber received the event.
- It does not carry a hold time or a delivery deadline. The response has no expiry field, and the console does not display one. Treat “delivers when the engine reconnects” as the whole of the contract.
- It is not a replay mechanism. The ring is a handoff to the engine, not subscriber-facing history. Whether a client that connects in the interim sees the event depends entirely on when the engine drains the ring relative to that client’s subscription — the console cannot tell you which came first.
Telling a transport failure from a rejected publish
The screen surfaces three distinct classes of failure in three distinct places. They mean different things:
The distinction that matters: a mutation error means “we never got an
answer,” while
ok: false means “we got an answer and it was no.” Only
the second one has an HTTP status and a response body to read.
Channel and event name validation
The form validates shape before it sends anything. Errors appear underneath the offending input once you have pressed Send event at least once. Channel- Required.
- Maximum 164 characters.
- Must match
[A-Za-z0-9_\-=@,.;]+— letters, digits, and_ - = @ , . ;only.
pusher-js client refuses to subscribe to a name outside that set, so
publishing to one is publishing into the void. The control-plane API
enforces the same rule, so bypassing the form does not help.
Channel prefixes are deliberately not restricted. private-orders
(the default) and presence-* names are accepted because the
control-plane API publishes as an authorized publisher.
Event name
- Required.
- Maximum 200 characters.
valid JSON or invalid live as you
type, and Send event is disabled while the payload is invalid. The
parsed object — not the raw text — is what goes to the procedure.
Turning the form into a signed REST request
The Equivalent cURL card mirrors your current form values as a request against the engine’s external Pusher-compatible REST plane. This is the shape your own server SDK sends; it is not the path the console itself takes.- The endpoint is
POST /apps/{app_id}/eventson the engine host, with the app id from the pill at the top of the screen. datais a JSON-encoded string, not a nested object. The console re-serializes whatever you typed in the Data textarea into a string for this snippet. Sending an object instead of a string is the most common cause of a rejected publish.channelsis an array, even for a single channel.- Authentication is query-string HMAC, not a bearer header:
auth_key,auth_timestamp,auth_version=1.0,body_md5, andauth_signature. The signature is HMAC-SHA256 of the sign-string with your app secret, andbody_md5is the MD5 of the exact request body you send — recompute both if you edit the payload.
Related
- Authentication — API keys and short-lived tokens
- Telemetry — where publish-side counters land

