HTTP API

Your servers publish events and read channel information over HTTP. Every Pusher server library already speaks this API, so you rarely need to call it directly. This page is for when you do.

Base URL, with your own app id:

https://YOUR_HOST/apps/YOUR_APP_ID

Signing requests

Every request carries these query parameters:

ParameterValue
auth_keyyour app key
auth_timestampthe current Unix time in seconds
auth_version1.0
body_md5the MD5 of the request body, hex (POST requests only)
auth_signaturethe signature, below

The signature is an HMAC-SHA256, in hex, keyed with your app secret, of this string:

METHOD
PATH
QUERY

METHOD is GET or POST, PATH is the request path (for example /apps/123/events), and QUERY is all the query parameters except auth_signature, sorted by name and joined as name=value with &. The three parts are joined with a newline.

Without a library, in Node:

js

import { createHash, createHmac } from "node:crypto";

const appId = "YOUR_APP_ID";
const key = "YOUR_APP_KEY";
const secret = process.env.PUSHER_APP_SECRET;

const body = JSON.stringify({
  name: "my-event",
  channels: ["my-channel"],
  data: JSON.stringify({ hello: "world" }), // data is a string
});

const path = `/apps/${appId}/events`;
const query = [
  `auth_key=${key}`,
  `auth_timestamp=${Math.floor(Date.now() / 1000)}`,
  "auth_version=1.0",
  `body_md5=${createHash("md5").update(body).digest("hex")}`,
].join("&");
const signature = createHmac("sha256", secret)
  .update(`POST\n${path}\n${query}`)
  .digest("hex");

const response = await fetch(
  `https://YOUR_HOST${path}?${query}&auth_signature=${signature}`,
  { method: "POST", headers: { "Content-Type": "application/json" }, body },
);
console.log(await response.json()); // { ok: true }

Endpoints

Method and pathPurpose
POST /eventsPublish one event to one or more channels
POST /batch_eventsPublish up to 10 events at once
GET /channelsList occupied channels
GET /channels/CHANNELInformation about one channel
GET /channels/CHANNEL/usersMembers of a presence channel
POST /users/USER_ID/terminate_connectionsClose a signed-in user's connections

All paths are under /apps/YOUR_APP_ID.

Publish an event

POST /events with a JSON body:

json

{
  "name": "my-event",
  "channels": ["my-channel", "other-channel"],
  "data": "{\"hello\":\"world\"}",
  "socket_id": "123.456"
}
  • data is a string. Send JSON by serializing it first.
  • Use channels (up to 100) or the single-channel channel.
  • socket_id is optional: that client will not receive the event, which is how you avoid echoing a change back to the browser that made it.

The response is {"ok":true}.

Publish a batch

POST /batch_events:

json

{
  "batch": [
    { "channel": "my-channel", "name": "e1", "data": "x" },
    { "channel": "other-channel", "name": "e2", "data": "y" }
  ]
}

A batch holds at most 10 events.

Channel information

GET /channels lists occupied channels. Filter with filter_by_prefix, for example ?filter_by_prefix=presence-:

json

{ "channels": { "room-1": { "subscription_count": 1, "occupied": true } } }

GET /channels/room-1 returns the same fields for one channel. GET /channels/presence-room-1/users returns { "users": [{ "id": "42" }] }.

Errors

json

{ "error": "The secret authentication failed", "code": 401 }
codeMeaning
400The body is malformed or incomplete, or a batch has more than 10 events
401The signature does not match: wrong secret, or the request was changed after signing
404The app id does not exist
413The event data is larger than your plan allows (see Limits and quotas)
429You exceeded your publish or read rate, or the app is paused

Rate limits

Publishing and reading are limited per app, per second, by your plan. A publish costs one point per channel, so an event to 20 channels costs 20, and a batch costs the sum of its events' channels. Each read request costs one. The limits are in Limits and quotas.