Skip to content
FloorPlanCraftSign in
Explore the planner
Browse the docs

Backfill and exit times

Re-send a past range of a service day after an error, and send when each party leaves so the live view can estimate the floor while your app is offline.

Updated · View as Markdown

Two additions in contract v1.7, for every app type. A backfill re-sends the history of a time range, so entries an error left out still reach the stored day and its replay. An exit time on a check-in says when that party leaves, so the live view can estimate the floor while your app is silent.

Backfill

POST https://floorplancraft.com/api/live/backfill, signed exactly as a push (see Signing requests) but with this path, so a push's signature never passes here. It shares the push's refusals: signature failures, 402, 403, 404, 413, 429 and 503.

{
  "restaurant": "Example Play Centre",
  "serviceDay": { "start": "2026-11-06T00:00:00+05:00", "end": "2026-11-07T00:00:00+05:00" },
  "from": "2026-11-06T09:00:00+05:00",
  "to": "2026-11-06T15:30:00+05:00",
  "states": [
    { "at": "2026-11-06T09:00:00+05:00", "tables": [ { "label": "Soft play", "room": "Play hall", "capacity": 40, "state": "seated", "covers": 12, "openMinutes": null, "server": null } ], "stations": [] },
    { "at": "2026-11-06T09:07:12+05:00", "tables": [ { "label": "Soft play", "room": "Play hall", "capacity": 40, "state": "seated", "covers": 15, "openMinutes": null, "server": null } ], "stations": [] }
  ],
  "events": [
    { "id": "checkin:T-58213", "at": "2026-11-06T09:03:41+05:00", "type": "seated", "label": "Soft play", "detail": "3 covers", "exitAt": "2026-11-06T10:03:41+05:00" }
  ]
}
FieldRule
serviceDayAs in a push: start before end, at most 36 hours. Its date in the venue's time zone is the day being replaced.
from, toThe range to replace, inside the service day: start <= from < to <= end. A whole day is from = start, to = end. to must be at least 10 minutes in the past, and from within the last 30 days.
states1 to 2,000 floors in increasing at, each inside the range, the first at from exactly. Each floor is checked as a push's floor is: tables, stations and the optional longSeatedMinutes.
events0 to 2,000, each id once, each inside the range. exitAt as on a push. A label that names no table or station of the request's floors is blanked, not refused.
  • The body may be up to 2 MB. Each connection may send 6 backfills a minute, with bursts of up to 10; backfills and pushes have separate allowances.
  • Send only the floors at changes: a floor is the whole state from its at until the next one.
  • Everything stored for the range, live pushes included, is replaced by the request. Sending the same request twice gives the same result.
  • A backfill is not a sign of life: it does not change the app's Last seen or its sequence.
  • A day your app never pushed, within the last 30 days, is created and appears in the live view's Service day menu.
{ "accepted": true, "serviceDay": "2026-11-06", "states": { "stored": 41, "replaced": 37 }, "events": { "stored": 12, "replaced": 0 }, "unmatchedLabels": [] }
AnswerMeaning
202 as aboveStored. A replay of that day can take up to a minute to show it.
422 { "error": "invalid_backfill", "issues": [...] }A rule was broken; up to 20 issues. Nothing was stored.
422 { "error": "backfill_too_large", "limit": "states", "max": 2000, "needed": 2104 }The day would pass one of its limits on stored floors, bytes or events (5,000 a day). Send fewer floors, or a day of more than 2,000 events as several ranges. Nothing was stored.

When to send one

  • Every night, the previous service day: it corrects anything an error lost without anyone noticing.
  • After a known outage or a correction in your system, the range it affected.

Exit times

A check-in (seated or reservation_seated) may carry exitAt, in pushes and in backfills: when the party leaves, such as the end of the ticket's paid time. If they leave early, send the same event again, with the same id, and the real time.

  • While your app is heard from (a push or heartbeat in the last 90 seconds), the live view shows the floors you send.
  • Once it has been silent for 90 seconds, and the day has at least one check-in with exitAt, the live view estimates each zone: your last count, less the people of earlier check-ins whose exitAt has passed since. It never goes below 0; a zone being reset and a zone without a count are left as they were.
  • The people in a check-in are its detail's number ("3 covers" or "3 guests"), else 1.
  • The viewer then reads “Estimated hh:mm from exit times” where it usually says “Refreshes every 10 s”. Replays of past days are never estimated.
  • When your app is back, the heartbeat that ends the silence answers "needFullState": true: send a feed push with the day's events.