Inbound
Events a bridge sends to Hijinks.
Report a command, button press or typed message
Hijinks checks a request in a fixed order and answers the first failure:
| Check | Status |
|---|---|
| Body is JSON and at most 64 KB | 400 / 413 |
| At most 500 requests per second from the sending IP address, signed or not | 429 |
| Workspace exists, is a custom-platform workspace and is connected | 404 |
Hijinks-Signature matches the raw body | 401 |
| Signed timestamp within 5 minutes of Hijinks' clock | 409 |
| At most 250 requests per second for this workspace | 429 |
Body matches InboundEvent (the field at fault is named) | 400 |
Anything that passes is answered 202 {"ok": true} before it is acted
on. What the event causes — a question, an updated message, a DM —
arrives as outbound events, never in this response. A message that
answers nothing in play is accepted and dropped, so a bridge may
forward every message in a channel without filtering.
Rate limits. Every button press and typed answer is one request,
so the workspace's 250 a second covers a whole game answering at
once — 200 players, the largest per-game cap of any plan that has
one — with room for polls. Only signed requests count against the
workspace's limit; every request counts against its IP address's
500, which is checked before anything else so unsigned traffic is
refused cheaply. Bridges for several workspaces sharing one egress
address share that address's limit. A 429 carries Retry-After
(seconds): wait that long and send the request again.
Retries and idempotency. Hijinks acts on a request once. Give
each request your own id (any string up to 128 characters, unique
per request — a UUID will do): a request repeating an id seen in
the last 24 hours is answered 202 and ignored, however it is
signed. A request without an id is ignored only when it is the
very same signed request again (same timestamp, same bytes). So:
- Retry a timeout, a dropped connection, a
5xxor a429with the same body andid, re-signed with the current time. - Do not retry any other
4xx: the request itself is wrong.
Without an id, a retry re-signed with a new timestamp is a new
request — and a repeated typed guess in a word game costs a turn.
Send Content-Type: application/json; the signature is checked over
the body bytes as received.
path Parameters
workspaceIdThe workspace id shown in the dashboard next to the inbound URL.
The Hijinks workspace, as shown in the dashboard.
Headers
Hijinks-Signature^t=\d+(,v1=[0-9a-fA-… · requiredt=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>.
Several v1= entries are allowed; any one matching is enough.
Report a command, button press or typed message › Request Body
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · type="command" · requires: channel, user, text | |
| type = object · type="action" · requires: channel, user, messageId +1 more | |
| type = object · type="message" · requires: channel, user, text |
typeWhere the event happened — a bare id, or an id with a display name.
The member who acted. id is your chat's id for them, opaque to
Hijinks and stable — scores and DMs follow it. name is shown in
results and leaderboards; send it whenever you have it.
textWhat followed the command, e.g. start, start science, leaderboard. Empty is help.
idOptional. Your id for this request, unique per request; send the
same one when you retry it. A request repeating an id seen in the
last 24 hours is answered 202 and ignored.
Report a command, button press or typed message › Responses
Accepted. Effects arrive as outbound events.
ok