Publishing over HTTP

Your backend talks to Pikoman with plain HTTP requests. There is no server SDK to install: if your language can make a POST, it can publish.

Base URL and authentication

All requests go to https://api.pikoman.se and use HTTP basic auth, with the app id as the username and the app secret as the password.

terminal
curl https://api.pikoman.se/orders/stats -u your-app-id:your-app-secret

Wrong credentials get a 401 with {"error": "Wrong credentials"}. A request the server cannot read gets a 400.

Publish an event

text
POST /{channel}/{event}

The request body is delivered as the event's payload to every client subscribed to the channel. Send JSON and the JavaScript client hands your handler a parsed object.

curl
curl -X POST https://api.pikoman.se/orders/shipped \
  -u your-app-id:your-app-secret \
  -d '{"id": 1042, "status": "shipped"}'
Node
const credentials = Buffer.from(`${appId}:${appSecret}`).toString("base64");

const response = await fetch("https://api.pikoman.se/orders/shipped", {
  method: "POST",
  headers: { authorization: `Basic ${credentials}` },
  body: JSON.stringify({ id: 1042, status: "shipped" }),
});
const { clients } = await response.json();
Rust (reqwest)
let delivered: serde_json::Value = reqwest::Client::new()
    .post("https://api.pikoman.se/orders/shipped")
    .basic_auth(app_id, Some(app_secret))
    .json(&serde_json::json!({ "id": 1042, "status": "shipped" }))
    .send()
    .await?
    .json()
    .await?;

The response reports how many connected clients the event was delivered to:

JSON
{ "clients": 12 }

Zero is a normal answer: it means nobody was listening at that moment. Events are not stored, so a client that connects later will not receive it.

Publish many events at once

text
POST /mass_events

The body is a JSON array. Each entry sends one payload to one or more channels, which is the cheap way to notify a list of users. Leave out event to send the payload without an event name.

terminal
curl -X POST https://api.pikoman.se/mass_events \
  -u your-app-id:your-app-secret \
  -d '[
    { "channels": ["user-7", "user-9"], "event": "invite", "data": { "team": "Design" } },
    { "channels": ["dashboard"], "event": "tick", "data": { "online": 31 } }
  ]'
JSON
{ "count": 3, "message": "success" }

count is the number of channel deliveries that were queued, here two plus one.

Look inside a channel

Request Response Use it for
GET /{channel}/stats {"clients": 12} How many connections are subscribed.
POST /{channel}/clients {"clients": {"42": "{\"name\":\"Ada\"}"}} Connection ids and, for presence channels, each member's signed data as a JSON string.

Disconnect a client

text
DELETE /connection/{connectionId}

Closes one connection, for example when a user logs out or is banned. The connection id is the one the client reports with pikoman.getClientId() and the one your presence endpoint receives.

JSON
{ "kicked": true }

The client will try to reconnect, so also make your presence endpoint refuse that user. Without a fresh signature they cannot get back into a presence channel.

Channel and event names

  • Names are part of the URL path and of a colon-separated frame, so avoid / and :.
  • Public channels have no access control: anyone with your app id who knows the name can subscribe. For per-user channels, use a name that cannot be guessed, or use a presence channel.
  • Only the presence- prefix is special.

Previous: presence channels Next: wire protocol

We are rebuilding the dashboard

Self-service sign-up is closed while we do. Until the new dashboard is ready we set up apps by hand: write to us with a line about what you are building, and we will send you an app id and a secret.

Write to hello@pikoman.se