Skip to main content

Pay-at-Table

Optional capability

Pay-at-Table is not required for a baseline POS integration with Mozrest. POS systems that implement the two endpoints on this page automatically unlock Mozrest's Pay-at-Table partner products (e.g. Blitz) for every venue connected through them — partners settle bills directly from the guest's seat. Implementations that do not expose these endpoints still ship a fully working order-flow integration; their venues simply stay out of the Pay-at-Table partner scope.

How it fits

Mozrest sits between Pay-at-Table partners and your POS:

Pay-at-Table partner  ──>  Mozrest  ──>  Your POS
(e.g. Blitz) Mozrest endpoints on this page
Pay-at-Table API

The partner discovers their venues and the live bill through Mozrest's Pay-at-Table partner API; Mozrest calls the endpoints below to fetch the bill from your POS and apply the payment back to it. The partner never talks to your POS directly.

Two endpoints make up the contract:

  1. Get Bill — return the current bill for the open order at a table.
  2. Apply Payment — record a partial or full payment against an open order, including tip. A full payment that brings the balance to zero closes the order automatically (no separate close call).

Get Bill

Return the current bill for the open order at a table. Mozrest calls this whenever a partner asks "what does this table owe right now?".

GET /venue/{venueId}/tables/{tableId}/bill
Authorization: Bearer {api_key}

Response

{
"orderId": "98765",
"status": "open",
"tables": ["T12"],
"partySize": 2,
"totals": {
"subtotal": 130.00,
"tax": 12.00,
"tip": 0.00,
"discount": 0.00,
"total": 142.00,
"paid": 50.00,
"balanceDue": 92.00
},
"checks": [
{
"checkNumber": "232323233",
"status": "open",
"totalAmount": 130.00,
"tax": 12.00,
"tip": 0.00,
"discount": 0.00,
"paymentMethod": null,
"items": [
{ "id": 1, "name": "Steak", "price": 40.00, "quantity": 2 },
{ "id": 2, "name": "Wine", "price": 50.00, "quantity": 1 }
]
}
]
}
FieldTypeDescription
orderIdStringPOS-side order id of the open order on this table.
statusStringOrder status — open while a bill exists.
tablesArrayPOS table ids the order is seated on.
partySizeIntegerNumber of guests.
totals.subtotalNumberSum of item amounts across checks, before tax / tip / discount.
totals.taxNumberTotal tax on the bill.
totals.tipNumberTip rung onto the bill at the POS (gratuity already on the check, not collected via Pay-at-Table).
totals.discountNumberTotal discount applied.
totals.totalNumbersubtotal + tax + tip − discount.
totals.paidNumberAggregate amount of all Pay-at-Table payments already applied to this order. Tip collected via Pay-at-Table is recorded on the payment but is not counted in paid.
totals.balanceDueNumbertotal − paid — what the partner is allowed to charge next.
checksArrayPer-check breakdown. Same shape as List Orders.

No open bill

404 Not Found
{ "error": { "code": 404, "message": "No open order on table T12" } }

Return 404 when there is no open order on the table. Mozrest surfaces this to the partner as "nothing to pay".


Apply Payment

Record a partial or full Pay-at-Table payment against an open order. The amount, tip and currency reflect what the partner just collected from the guest; the POS applies it as a tender on the order.

POST /venue/{venueId}/orders/{orderId}/payments
Authorization: Bearer {api_key}
Content-Type: application/json

Payload

FieldTypeRequiredDescription
externalReferenceStringYesIdempotency key chosen by the partner, unique per order. See Idempotency.
typeStringYesfull or partial. A full payment that brings balanceDue to zero closes the order — see Auto-close on full payment.
amountNumberYesAmount paid in currency, excluding tip. Must be > 0 and <= balanceDue.
tipNumberNoGratuity collected on top of amount. Defaults to 0. Stored against the payment; does not reduce balanceDue.
currencyStringYesISO 4217 code (e.g. EUR, GBP, USD).
paymentMethodStringNoFree-text label describing how the guest paid. Recommended vocabulary: card, cash, voucher, gift_card, other. POSes that map onto a fixed tender list should choose the closest match.
referenceStringNoHuman-readable label for the POS UI / receipt (e.g. Pay-at-Table — Blitz). Optional display hint.

Example

{
"externalReference": "blitz-tx-a7c93e",
"type": "full",
"amount": 92.00,
"tip": 10.00,
"currency": "EUR",
"paymentMethod": "card",
"reference": "Pay-at-Table — Blitz"
}

Response

{
"paymentId": "POS-PAY-7782",
"status": "accepted",
"order": {
"orderId": "98765",
"status": "closed",
"totals": {
"paid": 142.00,
"balanceDue": 0.00
}
}
}
FieldTypeDescription
paymentIdStringPOS-side identifier for the recorded tender. Stored by Mozrest for reconciliation.
statusStringAlways accepted on 2xx.
order.orderIdStringEchoed for trace correlation.
order.statusStringopen if balance remains, closed if this payment cleared the order.
order.totals.paidNumberCumulative amount paid against the order, including this call.
order.totals.balanceDueNumberRemaining balance after this payment.

Auto-close on full payment

When a payment with type: "full" brings balanceDue to zero, the POS must close the order in the same transaction:

  • Set the order status to closed.
  • Set every open check on the order to closed.
  • Record the tender so the POS UI reflects the order as settled.

Mozrest does not send a separate close call for Pay-at-Table — accepting the payment is the close signal. This matches how Oracle Simphony, Sapaad and other tender-driven POSes already behave.

A payment with type: "partial" keeps the order open regardless of the resulting balance. Sending partial with an amount that would zero the balance is a business-rule error (422).


Idempotency

Apply Payment is the only write call on this page. Replay protection is keyed on externalReference per order:

  • Same externalReference and identical payload → return 200 OK with the original response body and header X-Idempotent-Replay: true. Do not record a second tender.
  • Same externalReference but a different payload → return 409 Conflict.

This lets Mozrest retry safely on network failure: replay the exact same body, get the original outcome.


Errors

CodeWhenNotes
200Payment accepted (including idempotent replay)Returns the post-payment state of the order.
400Malformed payloadMissing required field, wrong type.
401Bad / missing tokenStandard auth error.
404Unknown order, or order already closedSame response whether the order never existed or has been closed — Mozrest surfaces both as "nothing to pay".
409Idempotency conflictSame externalReference, different body.
422Business-rule violationamount > balanceDue, amount <= 0, unknown / mismatched currency, or type: "partial" that would zero the balance. Include error.details describing the offending field.

Error response format

Use the same shape as the rest of the POS API (API Basics):

{
"error": {
"code": 422,
"message": "Amount exceeds balance due",
"details": {
"amount": "Must be <= 42.50"
}
}
}

Discovery

POSes do not advertise Pay-at-Table support themselves. Mozrest registers the capability per-POS during onboarding (after the endpoints on this page are accredited end-to-end) and surfaces it to partners per venue through the Pay-at-Table partner API — partners check that response before exposing the flow to the guest.