Events
The API reference holds every field and an example of each event; this page is the working overview.
Events Hijinks sends
POST to your bridge URL with Content-Type: application/json and three headers:
Hijinks-Signature, Hijinks-Event-Id and Hijinks-Workspace. Answer any 2xx within 5 seconds.
| type | When | Fields | Retries |
|---|---|---|---|
message.create | Post a message in a channel | channel, message | +1 s, +4 s, then dropped |
message.update | Replace a message Hijinks created (each question, answer counts, reveal, final board) | channel, message (same message.id) | a question, reveal or final board: +1 s, +4 s, then dropped; anything else never — the next update supersedes it |
message.ephemeral | A reply only the member who acted should see | channel, user, message | +1 s, +4 s, then dropped |
dm.create | A private message to a member (async rounds, Know Your Team, reminders) | user, message | +1 s, +4 s, then dropped |
ping | "Send test event" in the dashboard | — | never |
Every event also carries id, type, workspace, sequence, createdAt and expiresAt
(when it goes stale; see Retries and ordering). A question looks like
this: an update of the message the game started with.
Code
Rendering a message
- text is chat-flavoured Markdown, ready to print:
*italic*,**bold**, code, links, quotes. A bare\nis a line break, as in most chat tools. If your chat renders strict CommonMark, turn on hard line breaks (markdown-it'sbreaks: true, for example), or lines will run together. - buttons are rows, top to bottom. A button is either
{ label, action }— sendactionback when it is pressed — or{ label, url }, a link to open (the Pictionary drawing room, for one). - image is a picture or GIF URL to show with the message, or null.
- awaitsReply means Hijinks would like the member's next typed message to answer this one; offer a reply box if your chat has one. In a DM no reply is needed: the member's next message there answers it.
- kind names the message (
question,time_up,game_end,leaderboard,wordle_boardand 27 more) so a bridge can special-case a few and print the rest. data carries the view model behind it, for bridges that draw their own UI. - A
message.updatefor a message first sent as a DM arrives withchannel: "dm:<user id>". Send button presses and typed messages from a member's DM back the same way, asactionandmessageevents withchannel: "dm:<their own user.id>": replies then go to the DM, and a typed message there answers the Know Your Team question (or any other prompt) waiting in it. Any other channel id starting withdm:is refused.
Events your bridge sends
POST https://api.hijinks.team/hooks/<workspace id>, signed the same way. user is
{ "id", "name" } (ids up to 128 characters; send the name whenever you have it, it is what
leaderboards print). channel is an id, or { "id", "name" }. Unknown fields are refused, so a
typo fails loudly. Every event may also carry your own id for the request (up to 128
characters, unique per request): send it, and retries become safe.
| type | Meaning | Fields |
|---|---|---|
command | A member ran /hijinks <text> | channel, user, text |
action | A member pressed a button | channel, user, messageId, action |
message | A member typed something (word games, rebus, charades, replies) | channel, user, text, replyTo? |
A typed message that answers nothing in play is accepted and dropped, so a bridge can forward
every message in a channel without filtering. All visible output arrives as outbound events, never
in the HTTP response.
| Status | Meaning |
|---|---|
202 | Accepted: {"ok":true}. What it causes arrives as outbound events. |
400 | Malformed JSON, or the body does not match the schema; field names the culprit. |
401 | Missing or wrong Hijinks-Signature. |
404 | Unknown, non-webhook or disconnected workspace. |
409 | Signature valid, but the timestamp is more than 5 minutes off (replay or clock drift). |
413 | Body larger than 64 KB. |
429 | More than 500 requests a second from your IP address (checked first, signed or not), or more than 250 signed requests a second for this workspace. Wait Retry-After seconds and send it again. |
Rate limits and retries
Each button press and typed answer is one request, so the limit is set for a whole game answering in the same second: 250 signed requests a second per workspace covers 200 players, the largest per-game cap of any plan that has one, with room for polls. Bridges for several workspaces behind one egress address share that address's 500 a second.
Hijinks acts on a request once. A request repeating an id sent in the last 24 hours is answered
202 and ignored; without an id, only an exact replay (same signature, same bytes) is. So:
- Retry a timeout, a dropped connection, a
5xxor a429(afterRetry-After), with the same body and the sameid, re-signed with the current time. - Don't retry any other
4xx: the request itself is wrong, andfieldsays where.
Without an id, a retry re-signed with a new timestamp counts as a new request: a word-game guess
sent twice costs two turns.
Retries and ordering
- Every delivery has a 5-second deadline. Creates, DMs, ephemeral replies and the updates that start a phase of a game (a question, a reveal, the final board) are retried after 1 and 4 seconds, then dropped — a question that arrives 20 seconds late is worse than none. Other updates (answer counts, tallies) and pings are never retried: the next update supersedes them.
- A retry carries the same event id. Dedupe on
Hijinks-Event-Id, and answer2xxbefore doing slow work. sequenceincreases per workspace, so events that arrive out of order can be put back in order: skip an update older than one you have applied.expiresAtsays when an event stops being worth showing: 60 seconds for ephemeral replies and pings, 10 minutes for a live game's messages and command answers,null(never) for self-paced rounds, word games, icebreakers and digests. Drop an event past it, unapplied.- The game runs on its own clock and never stalls a round for a bridge that is down. A push bridge that is down misses what is sent meanwhile. A polling bridge finds it all waiting for 24 hours, and drops what expired on the way (Catching up).
- Your bridge URL must be public HTTPS. Hijinks does not follow redirects and will not deliver to private or loopback addresses.