Flapjack API
Everything a partner app, a shop system or a player device needs: read the board, push content, upload images, pair a screen. Same surface the Flapjack apps use.
Authentication
Board endpoints authenticate with that board's ingest key, shown once when you create or rotate it in the board editor's API tab. Send it as a bearer token. Keys are stored hashed, so a lost key must be rotated rather than recovered.
curl -X POST https://flapjackboard.com/api/public/flaps/lobby/message \
-H "Authorization: Bearer flap_xxx" \
-H "Content-Type: application/json" \
-d '{"message":"WELCOME BACK","ttl_ms":60000}'Limits: 60 requests a minute per board per endpoint (20 a minute for media uploads), and five wrong keys in a row locks that caller out of the board for 15 minutes. Both return 429 with a Retry-After header.
Board endpoints
Base URL https://flapjackboard.com/api/public. All endpoints are CORS-enabled and answer OPTIONS.
GET
/flaps/:slug/stateEverything needed to render the board: grid, scenes, zones, the live message and recent pushes.
{ "board": { "slug": "lobby", "renderer": "split-flap", "grid": { "cols": 22, "rows": 6, "aspect": "16:9" } }, "scenes": [...], "zones": [...], "liveMessage": { "body": "WELCOME BACK", "ttl_ms": 60000 } }POST
/flaps/:slug/messageTake the board over with a message. Omit ttl_ms to use the board's default hold time.
{ "message": "GATE C4 NOW BOARDING", "ttl_ms": 60000, "priority": 5 }{ "ok": true, "id": "…", "created_at": "…" }GET / PUT
/flaps/:slug/rowsRead or replace the rows in a data-table area — rates, menus, scores, departures. PUT replaces the whole set.
{ "rows": [["ESPRESSO", "3.25"], ["FLAT WHITE", "4.50"]] }{ "ok": true, "zone_id": "…", "rows": 2 }GET / POST
/flaps/:slug/mediaList or upload board images (PNG, JPEG, WebP, GIF, SVG — 6 MB max, 20 uploads a minute).
{ "filename": "special.png", "content_type": "image/png", "data_base64": "iVBORw0…" }{ "ok": true, "path": "<owner>/<board>/…png", "url": "<signed 1h url>" }GET / PATCH
/flaps/:slug/bezelRead or change the frame style, bezel weight and colour of the board.
{ "frameStyle": "walnut", "bezelWeight": "thin" }
Device pairing
Pairing needs no key: a screen registers itself, shows the code, and the owner claims it from their dashboard or an assistant. Keep polling state so the screen picks up its board the moment it is claimed.
POST
/devices/registerCalled by a player app on boot. Returns a six-character pairing code to show on screen; pass the same device_id back on every launch.
{ "device_id": "<uuid from last boot, or omit>" }{ "device_id": "…", "pair_code": "K7QD2M", "claimed": false, "board": null }GET
/devices/:id/stateHeartbeat and claim polling. Returns unpaired (keep showing the code), unassigned, paired (board + live message) or gone.
{ "status": "paired", "label": "Lobby TV", "board": { … }, "latest": { … } }
Webhooks
Add a webhook to a scene and Flapjack POSTs JSON to your endpoint when that scene takes the board. Every delivery carries the event name and an HMAC-SHA256 signature of the exact request body, keyed with the endpoint's secret.
X-Flapjack-Event: scene.changed X-Flapjack-Signature: sha256=<hex hmac of the raw body>
Verify before trusting a delivery, comparing in constant time:
const expected = crypto.createHmac("sha256", secret)
.update(rawBody) // the raw string, not a re-serialised object
.digest("hex");
const sent = header.replace(/^sha256=/, "");
const ok = sent.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sent), Buffer.from(expected));Deliveries time out after 8 seconds and are not retried; the board never waits on your endpoint.
Assistants (MCP)
Prefer to work in Claude, ChatGPT or Cursor? Flapjack ships an MCP server at https://flapjackboard.com/mcp with 40 tools covering boards, scenes, zones, schedules, screens, table rows, media and AI design. It signs you in with your Flapjack account, so an assistant only ever sees your own boards.