Skip to main content

Errors

Error responses from the Pay-at-Table API use a nested error envelope. The only exception is an invalid token, which returns an OAuth-style body (see below).

Envelope

{
"error": {
"code": 400,
"message": "Validation failed",
"details": {
"amount": ["This value should be greater than 0."]
}
}
}
FieldNotes
error.codeThe HTTP status code, repeated in the body.
error.messageHuman-readable explanation suitable for surfacing in your UI.
error.detailsPer-field validation errors on 400 (map of field name to an array of messages). null on every other error.

Invalid token - 401

A request with an Authorization header whose token is invalid or revoked does not use the envelope above. It returns an OAuth-style body:

{
"error": "access_denied",
"error_description": "The access token provided is invalid."
}

A request with no Authorization header (or a malformed one) returns 403 with the standard envelope, not 401:

{
"error": {
"code": 403,
"message": "Access Denied. You do not have permission to perform this action.",
"details": null
}
}

Status codes

HTTPWhen
400Request body fails validation (missing/invalid field). error.details maps each field to its problems; error.message is "Validation failed".
401Authorization header present but the token is invalid or revoked. OAuth-style body (see above).
403Missing/malformed Authorization header, token lacks partner access, or venue is not in the token's scope.
404Bill endpoint: table unknown for the venue, or no open order on the table. Payment endpoint: order not found in venue. Payment status endpoint: order not found in venue, or no payment with that externalReference on the order. Features endpoint: venue has no active POS connection. The message states which case applies.
409Payment endpoint, two distinct causes distinguishable by message: (a) same externalReference reused on the same order with a different payload - message lists the mismatching fields; (b) a new externalReference submitted while another payment on the same order is still pending - message: Another payment ("<externalReference>") on order "<orderId>" is awaiting POS confirmation. Poll it to a terminal state before submitting a new payment. Resolve (b) by polling the in-flight payment via the payment status endpoint until terminal, then resubmitting.
422Order is closed or voided when a payment is submitted.
502POS forwarding failed (payment endpoint only). See below.
5xxUnexpected server error. message is "Internal Server Error".

502 POS forwarding errors

When the payment endpoint returns 502, Mozrest forwarded the payment to the underlying POS and the POS refused, errored, or was unreachable. The response body is:

{
"error": {
"code": 502,
"message": "The bill is currently open on the POS interface. Please ask the waiter to close any open ticket on this table and retry.",
"details": null
}
}

error.message is controlled by Mozrest (no raw POS body leaks) and is safe to surface to the guest or operator. error.details is currently always null on 502 - there is no machine-readable failure slug in the response today, so branch on the HTTP status and use message for display.

The cases behind a 502, and what to do:

Failure caseMeaningRecommended partner action
Check lockedThe bill is currently open in the POS (a waiter or terminal has it on screen). The POS rejects payment writes while the check is "in use".Surface message to the guest. Retry after the waiter releases the check.
Check already closedThe bill is already closed in the POS. No further payments can be applied.Stop retrying. The bill is paid (or voided) on the POS side.
Check not foundThe bill could not be found in the POS (deleted, moved, or not yet synced).Re-fetch via /bill. If the order disappears, the table is no longer open.
Idempotency conflictA different payment payload was already recorded against the POS with this externalReference.Use a fresh externalReference. Do not retry the same one with a different body.
POS auth / configuration failureMozrest could not authenticate with the POS, Pay-at-Table is not configured for this venue's POS, or the order is missing its POS-side reference.Do not retry - contact Mozrest support.
POS unavailable / unreachableThe POS returned a 5xx or Mozrest could not reach it (network / timeout).Safe to retry shortly with the same externalReference.
POS rejectedThe POS refused for a reason Mozrest does not yet map.Surface message. Contact Mozrest support if it recurs.
Retry safety

Per-POS adapters use server-side idempotency keyed on externalReference (e.g. Simphony's header.idempotencyId = md5(externalReference)), so retrying the same request after a 502 is safe - the POS deduplicates.

Whatever the cause, a 502 means the payment was not recorded in Mozrest and the order is not closed.

A 502 can only occur on immediate-confirmation venues (features.payAtTable.paymentConfirmation = "immediate"), where forwarding happens synchronously inside the POST. On deferred-confirmation venues, POS failures surface asynchronously - see the next section.

Asynchronous failures

On venues where features.payAtTable.paymentConfirmation = "deferred", the payment POST answers 202 Accepted with status: "pending" and the POS confirms afterwards. If the POS then rejects the payment - or never confirms within the 120-second ceiling - the failure is data, not an HTTP error: the payment flips to status: "failed" with a machine-readable failureCode, and the payment status endpoint keeps answering 200 OK with that state in the body. Do not expect a 4xx/5xx for a payment that failed after the 202.

failureCode slugs are stable and safe to branch on. Where applicable they use the same vocabulary as the 502 cases above:

failureCodeMeaningRecommended partner action
pos_confirmation_timeoutThe POS did not confirm the payment within 120 seconds of submission.Refund/void the charge on your side and inform the guest. Report recurring cases to Mozrest.
pos_check_not_foundThe check was closed or moved by staff while the payment was in flight.Re-fetch /bill and restart the flow.
pos_overpaidThe payment would exceed the outstanding balance - e.g. staff took a payment on the till concurrently.Re-fetch /bill and submit a corrected amount with a fresh externalReference.
pos_config_missingPay-at-Table is not correctly configured for this venue's POS.Do not retry - contact Mozrest support.

A failed payment never counts toward the bill's totals.paid and never closes the order. Full lifecycle, polling guidance, and per-state JSON examples: Payment status.