- Read the floor plan — published rooms and tables, each with a
stable UUID. Store that UUID on your side (EatNow keeps it in
pos_table_id); it is the only table reference the API accepts. - Write reservations — create and update reservations keyed by
your own ids, each carrying its guest (name, contact, a guest-facing
allergiesnote and a staff-only, two-wayinternalNote). A party you seat yourself with nobody to name sendspartyName: null— the till shows its own “Walk-in”, so never invent a placeholder. Setting a reservation toseatedwith tables is an instruction: the till opens the order on the floor plan. See Reservation lifecycle. - Consume webhooks — signed events for everything that happens on the floor: parties seated, spend sent to the kitchen, checks paid, tables freed.
- Feed the guest profile back —
check.paidtells you what each party spent; you keep the CRM, aggregate it, and return those aggregates on the reservation so staff see a 360° guest profile on the till. NowOS never recomputes them — one writer per field. See Guest profile & CRM.
Authentication
Every request carries a location-scoped Bearer key:Errors
Every error body has one shape:code only — messages are free text. Codes: unauthorized,
unknown_reservation, duplicate_reservation, unknown_table_id,
table_occupied, floorplan_not_published, draft_not_empty,
validation_failed. occupiedBy is present on table_occupied only.
A stale update is not an error: PUT acknowledges it with
200 { "outcome": "stale" } and changes nothing, so you can retry any
write blindly.
Idempotency and ordering
- Reservations are keyed by your
externalId; re-sending the same body is a no-op. - Every write carries your
updatedAt. NowOS applies last-write-wins on it: a delivery that arrives late can never regress newer state. - Webhook envelopes carry an
id(your idempotency key) and a per-location monotonicsequence. Delivery order is not guaranteed — drop what you have already applied.