Nexus Gateway
EnglishRomână
OpenAPI

A slow response must not turn into a second order. Keep one durable ID and request body per purchase, and separate a known validation failure from an uncertain outcome.

The retry protocol

Same purchase. Same connection. Same ID. Same body. After a timeout, lost response or 503, the original order may already exist in Retail. A new ID can create a duplicate.
  1. Before first dispatch, atomically save your connection, external_order_id and complete request in a durable outbox.
  2. On 200 or 201, persist intake confirmation. Use GET for current status.
  3. On a network failure or 503, retain the request as unconfirmed and retry it unchanged. Honor Retry-After; the gateway sends 5 seconds on its 503 responses.
  4. Use bounded exponential backoff with jitter. Keep the request after your retry window and surface it for reconciliation; do not silently drop it.
  5. Other unexpected server/proxy errors can also have uncertain outcomes. Preserve the original identity and investigate or retry according to your recovery policy.
saved = persist_once(purchase, connection, external_order_id, full_request)

send saved.request to saved.connection
if response is 200 or 201:
    mark intake confirmed
    handle signed webhook updates
    reconcile with GET after gaps; poll only without webhooks
else if response is 429:
    retry saved.request after Retry-After plus jitter
else if timeout, network failure, or 503:
    keep unconfirmed
    retry saved.request after backoff
else:
    apply the error-specific recovery below

never create another purchase ID just because a response was lost

The gateway durably reserves validated contents before dispatch. Identical retries reuse the original snapshot even after menu changes or closure. Once reserved, an ID cannot be used for a different cart, customer, payment reference or note. There is no configurable idempotency header; external_order_id is the identity.

HTTP responses and body shapes

HTTPMeaningAction
400connection_requiredSelect an enabled connection with discovery and include its ID in the route. No order was created.
404connection_not_foundThe selected connection is unavailable to this tenant key. Refresh discovery; never move an uncertain order to another POS.
401Missing, invalid or wrong-role key.Check credentials and environment. Repeating an invalid key will not help.
404Menu unpublished or order ID unknown to this connection.Check the resource and connection; contact the restaurant to publish a menu.
409Business conflict.Read error and use the table below.
413Body exceeds 4 MiB.Reduce the request size.
422Schema or conditional validation failed.Correct the fields. Do not retry an unchanged invalid request.
429Request rate exceeded.Wait Retry-After seconds with jitter, then retry the original ID and body. See Rate limits below.
503Retail or storage unavailable; submission outcome unconfirmed.Honor Retry-After. Retry the original ID and body.

Read error or detail for the machine-readable code. Authentication and not-found responses normally use detail; pricing conflicts use error. Action eligibility checks can return either shape, so handle both. Validation includes sanitized field paths/types without echoing submitted customer values.

{ "error": "total_mismatch" }
{ "detail": "invalid_credentials" }
{
  "error": "invalid_request",
  "fields": [{ "path": ["body", "total"], "type": "int_type" }]
}
{ "error": "retail_unavailable", "retry_same_order_id": true }

storage_unavailable is also a 503, with {"error":"storage_unavailable"} and the same retry guidance. Do not require retry_same_order_id to be present before preserving your original identity. Reverse proxies may return non-JSON errors; handle HTTP status and transport failures before parsing a JSON body.

Conflict codes

CodeRecovery
menu_not_publishedAsk the restaurant to publish; GET menu uses 404, submission uses 409.
menu_changedRefresh the menu and reconfirm the cart with the customer.
restaurant_closedDisable new checkout. Do not bypass closure with a different connection.
product_unavailableRefresh the menu and remove/replace the unavailable product with customer approval.
unknown_modifierUse group and option IDs from the selected product.
duplicate_modifierSend each group/option pair only once per line.
variant_unavailableSelect an exact published, available variant combination.
modifier_selection_invalidRespect each group’s minimum and maximum selections.
modifier_unavailableChoose an available option after refreshing the menu.
total_mismatchRecalculate variant price, published promotions, checkout coupon, deposits, extras, packaging, tip and delivery fee in integer bani.
order_id_already_usedThis ID was reserved with different contents. Recover the original saved request; investigate before creating a genuinely new purchase.
publication_supersededInternal publisher only: a newer publication has already arrived, or this generation was used with different contents. Retain the latest queued publication.
revision_already_usedPublisher only: changed menu contents require a new revision.

A request rejected during initial validation is not reserved. You may correct that request for the same purchase. If there was an earlier uncertain attempt, first reconcile its original body; do not assume a later conflict erased the earlier order.

Share useful diagnostics

For support, provide the environment, connection ID used in the request URL, external order ID, timestamp, endpoint, HTTP status and error code. Redact keys, authorization headers, customer names, phones, addresses and payment details. Do not log full request bodies or downstream exceptions.

  • scheduled_time_unavailable: Send a valid timestamp with an explicit timezone offset.
  • cancellation_not_allowed: The order is outside the customer cancellation window or no longer in an eligible state. Immediate orders must still await acceptance; accepted scheduled orders must still await preparation and be strictly before their saved preparation start. Read current status and contact the restaurant. A receipt alone does not block an otherwise eligible scheduled cancellation.
  • cancellation_conflict: A different cancellation was committed. Reconcile using the order status.

Delivery updates

delivery_update_not_allowed: wrong fulfillment or lifecycle state; read current status before retrying. delivery_update_conflict: the request ID already belongs to a different body. delivery_update_limit: the order has reached 100 distinct delivery updates. These return 409.

Refund reports

refund_report_not_allowed: the original order was not paid online. refund_report_conflict: reused request ID or processor reference. refund_amount_exceeded: the reported amount exceeds the order total or the remaining refundable amount. refund_report_limit: 100 reports already exist. All return 409; do not perform another refund just to resolve a reporting error.

tips_unavailable (409): the published menu does not enable staff tips. Remove the tip only with customer approval and recalculate before submitting a new purchase.

invalid_checkout_discount: Unknown or repeated product scope, or an amount exceeding eligible product prices. Correct the coupon before submitting a new order.

Request tracing

Gateway responses for handled /v1/ requests include X-Request-ID. Save this header with the connection ID and external order ID when reporting a problem. Each HTTP attempt gets a new request ID, including retries; it is not an idempotency key. Keep the original external order ID and request body when retrying. A network failure or proxy-generated response may have no request ID.

Rate limits

The gateway enforces limits itself, across all workers sharing its local database. Per tenant, website reads (GET/HEAD/OPTIONS) refill at 600 requests/minute with a burst of 100; writes refill at 120/minute with a burst of 30. All points of sale share these budgets. Retail publishing has a separate tenant budget of 120/minute with a burst of 30. Key rotation does not reset tenant budgets.

All /v1/ requests also share an intake budget of 6,000/minute with a burst of 1,000, including invalid credentials and malformed requests. This check runs before reading request bodies. These are continuously replenished token buckets, not calendar-minute quotas. Documentation, health checks and outbound webhook deliveries are excluded. Limits persist across restarts; independent gateway databases do not share counters.

Excess requests return 429, {"error":"rate_limit_exceeded"} and Retry-After in seconds. Wait at least that long, add jitter, then retry the same request with its original order/request ID and body. A rate-limited attempt is not forwarded to Retail. Another caller may consume the next token, so a retry can also receive 429. Use webhooks for updates and avoid aggressive polling. If limiter storage is unavailable, requests fail closed with 503 and Retry-After: 5.

Nexus GatewayWebsite Ordering API · v1.0.0

Type to search the integration guides.