Arc
Backend API

HTTP API

Publishing events and querying channels from your backend, with signed requests.

Your backend talks to Arc over a small signed HTTP API. It is the same scheme the server SDKs for this protocol already implement, so a Python, Node, Go or Ruby SDK works by pointing host, port and ssl at Arc.

MethodPathPurpose
POST/apps/:app_id/eventsPublish one event to up to 100 channels
POST/apps/:app_id/batch_eventsPublish up to 10 events
GET/apps/:app_id/channelsOccupied channels
GET/apps/:app_id/channels/:nameOne channel's occupancy and counts
GET/apps/:app_id/channels/:name/usersPresence member ids
POST/apps/:app_id/users/:user_id/terminate_connectionsClose every connection of a user

Signing a request

Every request carries these query parameters:

ParameterValue
auth_keyThe app key
auth_timestampUnix seconds, within 600 seconds of Arc's clock
auth_version1.0
body_md5Hex MD5 of the request body, when there is one
auth_signatureHex HMAC-SHA256 of the string below, keyed by the app secret

The string to sign is three lines: the uppercase method, the path, and the query parameters except auth_signature, sorted by name and joined with &:

POST
/apps/1/events
auth_key=abc&auth_timestamp=1700000000&auth_version=1.0&body_md5=...

Comparisons are constant time. A stale timestamp or a body whose MD5 does not match is a 401.

Publishing

POST /apps/1/events
{
  "name": "order-created",
  "channels": ["orders", "private-account-42"],
  "data": "{\"id\":7}",
  "socket_id": "1234.5678",
  "info": "subscription_count"
}
  • data is a string. Your SDK serialises the object for you.
  • socket_id excludes the connection that caused the action, so the browser that made the change does not receive an echo of it. Every SDK sends it when you pass it through.
  • info asks for per-channel counts in the response, which costs a lookup, so it is only computed when requested.

Publishing to a channel nobody is listening to succeeds and returns {}. That is not an error: subscribers come and go.

Querying

GET /apps/1/channels?filter_by_prefix=presence-&info=user_count
GET /apps/1/channels/presence-room-1?info=user_count,subscription_count
GET /apps/1/channels/presence-room-1/users

user_count is only meaningful on presence channels; asking for it elsewhere is a 400 rather than a silent zero. subscription_count has to ask every node, so it must be enabled per app and is a 403 when it is not.

Errors

Bodies are plain text, written for the developer reading them:

StatusMeaning
400Malformed request
401Bad signature, stale timestamp, or body_md5 mismatch
403App disabled, or a feature not enabled for this app
404Unknown app
413Payload above the app's limit
429Rate limited

On this page