Jump to an endpoint
- GET/
locations/ {locationId} - GET/
locations/ {locationId}/ menu - GET/
locations/ {locationId}/ menu/ items/ {itemId} - GET/
locations/ {locationId}/ schedule - POST/
locations/ {locationId}/ delivery/ quote - POST/
orders/ quote - POST/
orders - GET/
orders/ {orderId} - POST/
orders/ {orderId}/ arrival - POST/
locations/ {locationId}/ promotions/ validate - POST/
locations/ {locationId}/ gift-cards/ balance - GET/
customers/ me/ loyalty - POST/
customers/ token - GET/
customers/ me/ orders - GET/
customers/ me/ payment-methods - POSTorder.updated
Overview
One API to show a Real Time Ordering restaurant's menu, price a cart, place an order and follow it to the kitchen. It is built for self-order kiosks, branded apps and ordering partners.
Availability. Endpoints marked Live are running in production today for RTO kiosks, which authenticate with a device token. Partner API keys are the next release; until then, partner access is arranged directly with Real Time Ordering. Endpoints marked Planned are the agreed contract and may still change in detail.
Conventions
- Money is always an integer number of cents (
1299= $12.99). - Rates are decimal strings (
"0.0825"= 8.25%). - Timestamps are ISO-8601 with an offset (
2026-09-21T18:30:00-07:00); time zones are IANA names. - IDs are opaque strings.
locationIdis the restaurant's short name in its ordering URL. - Every order write needs an
Idempotency-Keyheader. Retrying with the same key returns the first result, so a retry can never place a second order. - The server sets the price. Show your own math if you like, but only the totals from
POST /orders/quoteandPOST /orderscount. A payment that does not equal the server total is refused before anything reaches the kitchen. - Errors share one envelope with a stable machine
code.
Placing an order
POST /orders/quote (validate and price) → take payment for exactly that total → POST /orders → follow GET /orders/{orderId} or the order.updated webhook. If the kitchen refuses an order after a card payment, the server voids the payment itself and says so in the response.
Endpoints at a glance
| Endpoint | What it does | Status |
|---|---|---|
GET /locations/{locationId} | Location profile, order types, fees, tipping and payment options | Live |
GET /locations/{locationId}/menu | Full orderable menu for a location and order type | Planned |
GET /locations/{locationId}/menu/items/{itemId} | One item with its full modifier tree (for lazy-loading large menus) | Planned |
GET /locations/{locationId}/schedule | Open hours and orderable time slots per order type | Live |
POST /locations/{locationId}/delivery/quote | Is this address deliverable, and at what fee, minimum and ETA? | Planned |
POST /orders/quote | Validate and price a cart exactly as POST /orders would, without placing it | Live |
POST /orders | Place an order | Live |
GET /orders/{orderId} | Order status and receipt | Live |
POST /orders/{orderId}/arrival | Curbside "I'm here" | Planned |
POST /locations/{locationId}/promotions/validate | Check a coupon code against a cart without placing an order | Planned |
POST /locations/{locationId}/gift-cards/balance | Gift card balance lookup | Planned |
GET /customers/me/loyalty | Points balance, punch cards and redeemable rewards at a location | Planned |
POST /customers/token | Exchange customer credentials (or an SMS one-time code) for a customer bearer token | Planned |
GET /customers/me/orders | Order history (reorder source) | Planned |
GET /customers/me/payment-methods | Saved cards (tokens only; brand + last4) | Planned |
POST order.updated | Sent to the client's registered URL whenever an order's status changes | Planned |
/locations/{locationId}LiveLocation profile, order types, fees, tipping and payment options
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
locationId required | path | string | Restaurant orderUrl |
Responses
{
"locationId": "nancyjosburgers",
"name": "2pc Snack",
"phone": "(503) 555-0142",
"address": {
"line1": "2651 E Chapman Ave",
"line2": "line2",
"city": "Fullerton",
"state": "CA",
"postalCode": "92831",
"country": "US",
"lat": 33.87,
"lng": 33.87,
"instructions": "instructions"
},
"timeZone": "America/Los_Angeles",
"imageUrl": "imageUrl",
"logoUrl": "logoUrl",
"brandColor": "brandColor",
"acceptingOrders": true,
"openNow": true,
"taxRate": "0.0825",
"currency": "USD",
"orderTypes": [
{
"type": "pickup",
"enabled": true,
"asapAllowed": true,
"futureOrdersAllowed": true,
"maxDaysAhead": 1,
"prepTimeMinutes": 15,
"minimumOrder": 0,
"maximumOrder": 0,
"deliveryProvider": "merchant",
"vehicleInfoRequired": true,
"instructions": "instructions",
"paymentMethods": [
"card"
]
}
],
"tipping": {
"enabled": true,
"suggestions": [
{
"percent": "\u2026",
"isDefault": "\u2026"
}
]
},
"fees": [
{
"type": "service",
"label": "Service fee",
"flat": 1,
"percent": "percent",
"taxable": true
}
],
"guestCheckout": {
"allowed": true,
"emailRequired": true,
"phoneRequired": true
},
"cardTokenization": {
"provider": "shift4I4go",
"publicConfig": {}
},
"features": {
"specialInstructions": true,
"coupons": true,
"giftCards": true,
"loyalty": true,
"languages": [
"en"
]
}
}/locations/{locationId}/scheduleLiveOpen hours and orderable time slots per order type
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
locationId required | path | string | Restaurant orderUrl |
orderType required | query | pickup | curbside | delivery | dineIn | |
days | query | integer |
Responses
{
"locationId": "nancyjosburgers",
"orderType": "pickup",
"timeZone": "America/Los_Angeles",
"now": "2026-09-21T18:30:00-07:00",
"asapAvailable": true,
"asapEstimate": "2026-09-21T18:30:00-07:00",
"nextOpen": "2026-09-21T18:30:00-07:00",
"days": [
{
"date": "2026-09-21",
"closed": true,
"closedReason": "closed",
"hours": [
{
"open": "\u2026",
"close": "\u2026"
}
],
"slots": [
{
"time": "\u2026",
"available": "\u2026"
}
]
}
]
}/locations/{locationId}/delivery/quotePlannedIs this address deliverable, and at what fee, minimum and ETA?
Stateless: checks an address without touching any cart or order.
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
locationId required | path | string | Restaurant orderUrl |
Request body
{
"address": {
"line1": "2651 E Chapman Ave",
"line2": "line2",
"city": "Fullerton",
"state": "CA",
"postalCode": "92831",
"country": "US",
"lat": 33.87,
"lng": 33.87,
"instructions": "instructions"
},
"subtotal": 2340,
"requestedTime": "2026-09-21T18:30:00-07:00"
}
Responses
{
"deliverable": true,
"reason": "outsideZone",
"fee": 399,
"minimumOrder": 0,
"estimatedDeliveryTime": "2026-09-21T18:30:00-07:00",
"provider": "provider",
"zoneId": "zoneId"
}error.details.issues lists every problem./orders/quoteLiveValidate and price a cart exactly as POST /orders would, without placing it
Runs the full order pipeline in dry-run: item/modifier resolution, 86 check, hours/slot check, min order, delivery zone, discounts, tax, fees, tip and (for POS-priced stores) the POS price check. Returns every problem at once in issues[] (HTTP 200) so a client can fix the cart in one round trip. The returned quoteId may be passed to POST /orders within expiresAt; if the server total has changed by then, the order is rejected with PRICE_CHANGED and the new totals.
Request body
{
"locationId": "nancyjosburgers",
"lines": [
{
"lineId": "0",
"itemId": "282413",
"sizeId": "White",
"quantity": 2,
"modifiers": [
{
"groupId": "\u2026",
"modifierId": "\u2026"
}
],
"specialInstructions": "extra napkins",
"forName": "forName"
}
],
"orderType": "pickup",
"requestedTime": "2026-09-21T18:30:00-07:00",
"deliveryAddress": {
"line1": "2651 E Chapman Ave",
"line2": "line2",
"city": "Fullerton",
"state": "CA",
"postalCode": "92831",
"country": "US",
"lat": 33.87,
"lng": 33.87,
"instructions": "instructions"
},
"vehicle": {
"make": "make",
"model": "model",
"color": "color",
"plate": "plate"
},
"tableNumber": "tableNumber",
"tip": {
"amount": 2716,
"percent": 18
},
"promoCode": "promoCode",
"notes": "notes",
"customer": {
"firstName": "Sam",
"lastName": "Rivera",
"email": "[email protected]",
"phone": "(503) 555-0142",
"marketingOptIn": true
},
"payment": {
"method": "cardToken",
"cardToken": {
"token": "tok_example",
"postalCode": "92831"
},
"wallet": {
"type": "applePay",
"token": "tok_example"
},
"cardPresent": {
"paymentId": "paymentId"
},
"softPos": {
"recordNo": "recordNo",
"authCode": "04711A",
"refNo": "refNo",
"approvedAmount": "approvedAmount",
"cardType": "cardType",
"acctNoMasked": "acctNoMasked"
},
"savedCardId": "savedCardId",
"giftCards": [
{
"cardNumber": "\u2026",
"pin": "\u2026"
}
],
"loyaltyRewardIds": [
"loyaltyRewardIds"
]
},
"source": {
"channel": "kiosk",
"deviceId": "deviceId",
"partnerOrderId": "partnerOrderId"
}
}
Responses
issues — a quote can price and still be unorderable){
"quoteId": "q_7f3a",
"expiresAt": "2026-09-21T18:30:00-07:00",
"orderable": true,
"issues": [
{
"code": "ITEM_UNAVAILABLE",
"message": "2pc Snack is sold out.",
"lineId": "0",
"itemId": "282413",
"modifierGroupId": "modifierGroupId",
"nextAvailableTime": "2026-09-21T18:30:00-07:00"
}
],
"lines": [
{
"lineId": "0",
"itemId": "282413",
"name": "2pc Snack",
"sizeName": "sizeName",
"quantity": 2,
"unitPrice": 995,
"total": 2716,
"modifiers": [
{
"modifierId": "\u2026",
"name": "\u2026"
}
],
"specialInstructions": "extra napkins"
}
],
"totals": {
"subtotal": 2340,
"discount": 0,
"fees": [
{
"type": "\u2026",
"label": "\u2026"
}
],
"deliveryFee": 0,
"tax": 176,
"tip": 200,
"total": 2716,
"giftCardApplied": 0,
"amountDue": 2716
},
"estimatedReadyTime": "2026-09-21T18:30:00-07:00",
"upsells": [
{
"itemId": "282413",
"name": "2pc Snack",
"price": 995
}
]
}/ordersLivePlace an order
Re-validates and re-prices server-side. Payment is then taken/verified for exactly the server total, the order is persisted, and it is sent to the POS.
Payment is verified, never trusted. cardPresent must reference a /payments/v1 record that is approved, belongs to this location, is unused, and whose amount equals the order total. cardToken / wallet are charged by the server. A client can never mark an order paid by itself.
If POS submission fails after payment, the server voids/refunds and returns 502 POS_REJECTED with payment.status — the client does not need to void.
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
Idempotency-Key required | header | string · uuid |
Request body
{
"locationId": "nancyjosburgers",
"lines": [
{
"lineId": "0",
"itemId": "282413",
"sizeId": "White",
"quantity": 2,
"modifiers": [
{}
],
"specialInstructions": "extra napkins",
"forName": "forName"
}
],
"orderType": "pickup",
"requestedTime": "2026-09-21T18:30:00-07:00",
"deliveryAddress": {
"line1": "2651 E Chapman Ave",
"line2": "line2",
"city": "Fullerton",
"state": "CA",
"postalCode": "92831",
"country": "US",
"lat": 33.87,
"lng": 33.87,
"instructions": "instructions"
},
"vehicle": {
"make": "make",
"model": "model",
"color": "color",
"plate": "plate"
},
"tableNumber": "tableNumber",
"tip": {
"amount": 2716,
"percent": 18
},
"promoCode": "promoCode",
"notes": "notes",
"customer": {
"firstName": "Sam",
"lastName": "Rivera",
"email": "[email protected]",
"phone": "(503) 555-0142",
"marketingOptIn": true
},
"payment": {
"method": "cardToken",
"cardToken": {
"token": "tok_example",
"postalCode": "92831"
},
"wallet": {
"type": "applePay",
"token": "tok_example"
},
"cardPresent": {
"paymentId": "paymentId"
},
"softPos": {
"recordNo": "recordNo",
"authCode": "04711A",
"refNo": "refNo",
"approvedAmount": "approvedAmount",
"cardType": "cardType",
"acctNoMasked": "acctNoMasked"
},
"savedCardId": "savedCardId",
"giftCards": [
{
"cardNumber": "\u2026",
"pin": "\u2026"
}
],
"loyaltyRewardIds": [
"loyaltyRewardIds"
]
},
"source": {
"channel": "kiosk",
"deviceId": "deviceId",
"partnerOrderId": "partnerOrderId"
},
"quoteId": "q_7f3a",
"expectedTotal": 2716
}
Responses
{
"orderId": "21707901",
"orderNumber": "1093",
"accessToken": "accessToken",
"locationId": "nancyjosburgers",
"status": "received",
"statusReason": "statusReason",
"orderType": "pickup",
"placedAt": "2026-09-21T18:30:00-07:00",
"requestedTime": "2026-09-21T18:30:00-07:00",
"estimatedReadyTime": "2026-09-21T18:30:00-07:00",
"lines": [
{
"lineId": "0",
"itemId": "282413",
"name": "2pc Snack",
"sizeName": "sizeName",
"quantity": 2,
"unitPrice": 995,
"total": 2716,
"modifiers": [
{
"modifierId": "\u2026",
"name": "\u2026"
}
],
"specialInstructions": "extra napkins"
}
],
"removedLines": [
"removedLines"
],
"totals": {
"subtotal": 2340,
"discount": 0,
"fees": [
{
"type": "\u2026",
"label": "\u2026"
}
],
"deliveryFee": 0,
"tax": 176,
"tip": 200,
"total": 2716,
"giftCardApplied": 0,
"amountDue": 2716
},
"payment": {
"method": "method",
"status": "pending",
"amount": 2716,
"brand": "VISA",
"last4": "1111",
"authCode": "04711A",
"reference": "58"
},
"customer": {
"firstName": "Sam",
"lastName": "Rivera",
"email": "[email protected]",
"phone": "(503) 555-0142",
"marketingOptIn": true
},
"deliveryAddress": {
"line1": "2651 E Chapman Ave",
"line2": "line2",
"city": "Fullerton",
"state": "CA",
"postalCode": "92831",
"country": "US",
"lat": 33.87,
"lng": 33.87,
"instructions": "instructions"
},
"delivery": {
"provider": "provider",
"trackingUrl": "trackingUrl",
"driverName": "driverName"
},
"pos": {
"system": "skytab",
"checkNumber": "checkNumber",
"status": "pending"
},
"trackingUrl": "trackingUrl"
}{
"orderId": "21707901",
"orderNumber": "1093",
"accessToken": "accessToken",
"locationId": "nancyjosburgers",
"status": "received",
"statusReason": "statusReason",
"orderType": "pickup",
"placedAt": "2026-09-21T18:30:00-07:00",
"requestedTime": "2026-09-21T18:30:00-07:00",
"estimatedReadyTime": "2026-09-21T18:30:00-07:00",
"lines": [
{
"lineId": "0",
"itemId": "282413",
"name": "2pc Snack",
"sizeName": "sizeName",
"quantity": 2,
"unitPrice": 995,
"total": 2716,
"modifiers": [
{
"modifierId": "\u2026",
"name": "\u2026"
}
],
"specialInstructions": "extra napkins"
}
],
"removedLines": [
"removedLines"
],
"totals": {
"subtotal": 2340,
"discount": 0,
"fees": [
{
"type": "\u2026",
"label": "\u2026"
}
],
"deliveryFee": 0,
"tax": 176,
"tip": 200,
"total": 2716,
"giftCardApplied": 0,
"amountDue": 2716
},
"payment": {
"method": "method",
"status": "pending",
"amount": 2716,
"brand": "VISA",
"last4": "1111",
"authCode": "04711A",
"reference": "58"
},
"customer": {
"firstName": "Sam",
"lastName": "Rivera",
"email": "[email protected]",
"phone": "(503) 555-0142",
"marketingOptIn": true
},
"deliveryAddress": {
"line1": "2651 E Chapman Ave",
"line2": "line2",
"city": "Fullerton",
"state": "CA",
"postalCode": "92831",
"country": "US",
"lat": 33.87,
"lng": 33.87,
"instructions": "instructions"
},
"delivery": {
"provider": "provider",
"trackingUrl": "trackingUrl",
"driverName": "driverName"
},
"pos": {
"system": "skytab",
"checkNumber": "checkNumber",
"status": "pending"
},
"trackingUrl": "trackingUrl"
}error.details.issues lists every problem./orders/{orderId}LiveOrder status and receipt
Callable with the API key that created the order, or with the order's accessToken (returned at creation; safe to put in a customer-facing tracking link). Order ids are not sequential and are not the POS/restaurant order number.
Auth: apiKey, orderToken
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
orderId required | path | string |
Responses
{
"orderId": "21707901",
"orderNumber": "1093",
"accessToken": "accessToken",
"locationId": "nancyjosburgers",
"status": "received",
"statusReason": "statusReason",
"orderType": "pickup",
"placedAt": "2026-09-21T18:30:00-07:00",
"requestedTime": "2026-09-21T18:30:00-07:00",
"estimatedReadyTime": "2026-09-21T18:30:00-07:00",
"lines": [
{
"lineId": "0",
"itemId": "282413",
"name": "2pc Snack",
"sizeName": "sizeName",
"quantity": 2,
"unitPrice": 995,
"total": 2716,
"modifiers": [
{
"modifierId": "\u2026",
"name": "\u2026"
}
],
"specialInstructions": "extra napkins"
}
],
"removedLines": [
"removedLines"
],
"totals": {
"subtotal": 2340,
"discount": 0,
"fees": [
{
"type": "\u2026",
"label": "\u2026"
}
],
"deliveryFee": 0,
"tax": 176,
"tip": 200,
"total": 2716,
"giftCardApplied": 0,
"amountDue": 2716
},
"payment": {
"method": "method",
"status": "pending",
"amount": 2716,
"brand": "VISA",
"last4": "1111",
"authCode": "04711A",
"reference": "58"
},
"customer": {
"firstName": "Sam",
"lastName": "Rivera",
"email": "[email protected]",
"phone": "(503) 555-0142",
"marketingOptIn": true
},
"deliveryAddress": {
"line1": "2651 E Chapman Ave",
"line2": "line2",
"city": "Fullerton",
"state": "CA",
"postalCode": "92831",
"country": "US",
"lat": 33.87,
"lng": 33.87,
"instructions": "instructions"
},
"delivery": {
"provider": "provider",
"trackingUrl": "trackingUrl",
"driverName": "driverName"
},
"pos": {
"system": "skytab",
"checkNumber": "checkNumber",
"status": "pending"
},
"trackingUrl": "trackingUrl"
}/orders/{orderId}/arrivalPlannedCurbside "I'm here"
Auth: apiKey, orderToken
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
orderId required | path | string |
Request body
{
"vehicle": {
"make": "make",
"model": "model",
"color": "color",
"plate": "plate"
},
"parkingSpot": "parkingSpot"
}
Responses
/locations/{locationId}/promotions/validatePlannedCheck a coupon code against a cart without placing an order
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
locationId required | path | string | Restaurant orderUrl |
Request body
{
"code": "ITEM_UNAVAILABLE",
"cart": {
"locationId": "nancyjosburgers",
"lines": [
{
"lineId": "\u2026",
"itemId": "\u2026"
}
]
},
"email": "[email protected]"
}
Responses
{
"valid": true,
"discount": 0,
"description": "description",
"reason": "reason"
}/locations/{locationId}/gift-cards/balancePlannedGift card balance lookup
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
locationId required | path | string | Restaurant orderUrl |
Request body
{
"cardNumber": "cardNumber",
"pin": "pin"
}
Responses
{
"balance": 2500,
"currency": "USD"
}error.details.issues lists every problem./customers/me/loyaltyPlannedPoints balance, punch cards and redeemable rewards at a location
Auth: customerToken
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
locationId required | query | string |
Responses
{
"enrolled": true,
"points": 1,
"pointsValue": 1,
"punchCards": [
{
"id": "id",
"name": "2pc Snack",
"punches": 1,
"threshold": 1
}
],
"rewards": [
{
"id": "id",
"name": "2pc Snack",
"pointsCost": 1,
"value": 1,
"redeemable": true
}
]
}/customers/tokenPlannedExchange customer credentials (or an SMS one-time code) for a customer bearer token
Scoped to one merchant. Replaces the hash/username cookie login for API clients.
Request body
{
"locationId": "nancyjosburgers",
"email": "[email protected]",
"password": "password"
}
Responses
{
"accessToken": "accessToken",
"expiresAt": "2026-09-21T18:30:00-07:00",
"customer": {
"firstName": "Sam",
"lastName": "Rivera",
"email": "[email protected]",
"phone": "(503) 555-0142",
"marketingOptIn": true
}
}/customers/me/ordersPlannedOrder history (reorder source)
Auth: customerToken
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
locationId | query | string |
Responses
{
"orders": [
{
"orderId": "21707901",
"orderNumber": "1093",
"accessToken": "accessToken",
"locationId": "nancyjosburgers",
"status": "received",
"statusReason": "statusReason",
"orderType": "pickup",
"placedAt": "2026-09-21T18:30:00-07:00",
"requestedTime": "2026-09-21T18:30:00-07:00",
"estimatedReadyTime": "2026-09-21T18:30:00-07:00",
"lines": [
{
"lineId": "\u2026",
"itemId": "\u2026"
}
],
"removedLines": [
"removedLines"
],
"totals": {
"subtotal": "\u2026",
"discount": "\u2026"
},
"payment": {
"method": "\u2026",
"status": "\u2026"
},
"customer": {
"firstName": "\u2026",
"lastName": "\u2026"
},
"deliveryAddress": {
"line1": "\u2026",
"line2": "\u2026"
},
"delivery": {
"provider": "\u2026",
"trackingUrl": "\u2026"
},
"pos": {
"system": "\u2026",
"checkNumber": "\u2026"
},
"trackingUrl": "trackingUrl"
}
]
}/customers/me/payment-methodsPlannedSaved cards (tokens only; brand + last4)
Auth: customerToken
Responses
[
{
"id": "id",
"brand": "VISA",
"last4": "1111",
"expMonth": 1,
"expYear": 1
}
]order.updatedPlannedSent to the client's registered URL whenever an order's status changes
Signed like our Shift4 loyalty inbound: header X-RTO-Signature: t=<unix>,v1=<hex> where v1 = HMAC-SHA256(secret, t + "." + rawBody). Reject if |now - t| > 300s. Retries with exponential backoff for 24h; eventId is stable across retries.
Request body
{
"eventId": "eventId",
"type": "order.updated",
"createdAt": "2026-09-21T18:30:00-07:00",
"order": {
"orderId": "21707901",
"orderNumber": "1093",
"accessToken": "accessToken",
"locationId": "nancyjosburgers",
"status": "received",
"statusReason": "statusReason",
"orderType": "pickup",
"placedAt": "2026-09-21T18:30:00-07:00",
"requestedTime": "2026-09-21T18:30:00-07:00",
"estimatedReadyTime": "2026-09-21T18:30:00-07:00",
"lines": [
{
"lineId": "\u2026",
"itemId": "\u2026"
}
],
"removedLines": [
"removedLines"
],
"totals": {
"subtotal": 2340,
"discount": 0,
"fees": [
{
"type": "\u2026",
"label": "\u2026"
}
],
"deliveryFee": 0,
"tax": 176,
"tip": 200,
"total": 2716,
"giftCardApplied": 0,
"amountDue": 2716
},
"payment": {
"method": "method",
"status": "pending",
"amount": 2716,
"brand": "VISA",
"last4": "1111",
"authCode": "04711A",
"reference": "58"
},
"customer": {
"firstName": "Sam",
"lastName": "Rivera",
"email": "[email protected]",
"phone": "(503) 555-0142",
"marketingOptIn": true
},
"deliveryAddress": {
"line1": "2651 E Chapman Ave",
"line2": "line2",
"city": "Fullerton",
"state": "CA",
"postalCode": "92831",
"country": "US",
"lat": 33.87,
"lng": 33.87,
"instructions": "instructions"
},
"delivery": {
"provider": "provider",
"trackingUrl": "trackingUrl",
"driverName": "driverName"
},
"pos": {
"system": "skytab",
"checkNumber": "checkNumber",
"status": "pending"
},
"trackingUrl": "trackingUrl"
}
}
Responses
Errors
Every error uses the same envelope: {"error": {"code", "message", "details"}}. The message is safe to show a customer; switch on code. When a cart can't be placed, details.issues lists every problem at once, and after a refused card payment details.payment says whether it was voided.
UNAUTHORIZEDFORBIDDENNOT_FOUNDVALIDATION_FAILEDLOCATION_UNAVAILABLELOCATION_CLOSEDORDER_TYPE_UNAVAILABLESLOT_UNAVAILABLEITEM_UNAVAILABLEITEM_NOT_ON_MENUINVALID_MODIFIERSBELOW_MINIMUMABOVE_MAXIMUMOUTSIDE_DELIVERY_ZONEPROMOTION_INVALIDPRICE_CHANGEDIDEMPOTENCY_CONFLICTPAYMENT_DECLINEDPAYMENT_AMOUNT_MISMATCHPAYMENT_NOT_APPROVEDPAYMENT_ALREADY_USEDPAYMENT_METHOD_NOT_ALLOWEDPOS_REJECTEDRATE_LIMITEDINTERNALOpenAPI file
The full OpenAPI 3.1 description of everything on this page, for code generators and API tools. Download openapi.yaml or copy it below.
Show OpenAPI 3.1 YAML
openapi: 3.1.0
info:
title: RTO Ordering API
version: 1.0.0
summary: Menu, pricing, ordering and order status for Real Time Ordering (GimmeGrub) locations.
description: "One API to show a Real Time Ordering restaurant's menu, price a cart, place an order and\n\
follow it to the kitchen. It is built for self-order kiosks, branded apps and ordering partners.\n\
\n**Availability.** Endpoints marked *Live* are running in production today for RTO kiosks, which\n\
authenticate with a device token. Partner API keys are the next release; until then, partner\naccess\
\ is arranged directly with Real Time Ordering. Endpoints marked *Planned* are the agreed\ncontract\
\ and may still change in detail.\n\n## Conventions\n- **Money** is always an integer number of **cents**\
\ (`1299` = $12.99).\n- **Rates** are decimal strings (`\"0.0825\"` = 8.25%).\n- **Timestamps** are\
\ ISO-8601 with an offset (`2026-09-21T18:30:00-07:00`); time zones are IANA names.\n- **IDs** are\
\ opaque strings. `locationId` is the restaurant's short name in its ordering URL.\n- **Every order\
\ write** needs an `Idempotency-Key` header. Retrying with the same key returns the first\n result,\
\ so a retry can never place a second order.\n- **The server sets the price.** Show your own math\
\ if you like, but only the totals from\n `POST /orders/quote` and `POST /orders` count. A payment\
\ that does not equal the server total is refused\n before anything reaches the kitchen.\n- **Errors**\
\ share one envelope with a stable machine `code`.\n\n## Placing an order\n`POST /orders/quote` (validate\
\ and price) → take payment for exactly that total → `POST /orders` →\nfollow `GET /orders/{orderId}`\
\ or the `order.updated` webhook. If the kitchen refuses an order after a card\npayment, the server\
\ voids the payment itself and says so in the response.\n"
contact:
name: Real Time Ordering
url: https://www.realtimeordering.com
servers:
- url: https://www.gimmegrub.com/api/v1
description: Production
security:
- apiKey: []
tags:
- name: Locations
- name: Menu
- name: Scheduling
- name: Delivery
- name: Orders
- name: Promotions
- name: GiftCards
- name: Loyalty
- name: Customers
- name: Devices
- name: Webhooks
paths:
/locations/{locationId}:
get:
tags:
- Locations
operationId: getLocation
summary: Location profile, order types, fees, tipping and payment options
parameters:
- $ref: '#/components/parameters/locationId'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Location'
'404':
$ref: '#/components/responses/NotFound'
x-status: live
/locations/{locationId}/menu:
get:
tags:
- Menu
operationId: getMenu
summary: Full orderable menu for a location and order type
description: 'Returns the active menu with sizes and nested modifier groups. Unavailable (86''d)
items
are **included** with `available: false` so clients can show "sold out" and reject stale
carts deterministically. Supports `ETag` / `If-None-Match`.
'
parameters:
- $ref: '#/components/parameters/locationId'
- name: orderType
in: query
schema:
$ref: '#/components/schemas/OrderType'
- name: at
in: query
description: Evaluate menu/category availability at this time (future orders). Defaults to now.
schema:
type: string
format: date-time
- name: If-None-Match
in: header
schema:
type: string
responses:
'200':
description: OK
headers:
ETag:
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Menu'
'304':
description: Not modified
'404':
$ref: '#/components/responses/NotFound'
x-status: planned
/locations/{locationId}/menu/items/{itemId}:
get:
tags:
- Menu
operationId: getMenuItem
summary: One item with its full modifier tree (for lazy-loading large menus)
parameters:
- $ref: '#/components/parameters/locationId'
- name: itemId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/MenuItem'
'404':
$ref: '#/components/responses/NotFound'
x-status: planned
/locations/{locationId}/schedule:
get:
tags:
- Scheduling
operationId: getSchedule
summary: Open hours and orderable time slots per order type
parameters:
- $ref: '#/components/parameters/locationId'
- name: orderType
in: query
required: true
schema:
$ref: '#/components/schemas/OrderType'
- name: days
in: query
schema:
type: integer
minimum: 1
maximum: 31
default: 7
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Schedule'
x-status: live
/locations/{locationId}/delivery/quote:
post:
tags:
- Delivery
operationId: quoteDelivery
summary: Is this address deliverable, and at what fee, minimum and ETA?
description: 'Stateless: checks an address without touching any cart or order.'
parameters:
- $ref: '#/components/parameters/locationId'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- address
properties:
address:
$ref: '#/components/schemas/Address'
subtotal:
type: integer
description: cents; affects min-order and %-based fees
requestedTime:
type: string
format: date-time
description: omit for ASAP
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/DeliveryQuote'
'422':
$ref: '#/components/responses/Unprocessable'
x-status: planned
/locations/{locationId}/promotions/validate:
post:
tags:
- Promotions
operationId: validatePromotion
summary: Check a coupon code against a cart without placing an order
parameters:
- $ref: '#/components/parameters/locationId'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- code
- cart
properties:
code:
type: string
cart:
$ref: '#/components/schemas/Cart'
email:
type: string
description: for single-use-per-customer coupons
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
valid:
type: boolean
discount:
type: integer
description: cents
description:
type: string
reason:
type: string
description: present when valid=false (EXPIRED, MIN_NOT_MET, ALREADY_USED, NOT_FOUND)
x-status: planned
/locations/{locationId}/gift-cards/balance:
post:
tags:
- GiftCards
operationId: giftCardBalance
summary: Gift card balance lookup
parameters:
- $ref: '#/components/parameters/locationId'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- cardNumber
properties:
cardNumber:
type: string
pin:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
balance:
type: integer
description: cents
currency:
type: string
example: USD
'422':
$ref: '#/components/responses/Unprocessable'
'429':
$ref: '#/components/responses/RateLimited'
x-status: planned
/orders/quote:
post:
tags:
- Orders
operationId: quoteOrder
summary: Validate and price a cart exactly as POST /orders would, without placing it
description: 'Runs the full order pipeline in dry-run: item/modifier resolution, 86 check, hours/slot
check, min order, delivery zone, discounts, tax, fees, tip and (for POS-priced stores) the
POS price check. Returns every problem at once in `issues[]` (HTTP 200) so a client can
fix the cart in one round trip. The returned `quoteId` may be passed to `POST /orders`
within `expiresAt`; if the server total has changed by then, the order is rejected with
`PRICE_CHANGED` and the new totals.
'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OrderRequest'
responses:
'200':
description: Priced (check `issues` — a quote can price and still be unorderable)
content:
application/json:
schema:
$ref: '#/components/schemas/Quote'
'404':
$ref: '#/components/responses/NotFound'
x-status: live
/orders:
post:
tags:
- Orders
operationId: createOrder
summary: Place an order
description: 'Re-validates and re-prices server-side. Payment is then taken/verified for exactly
the
server total, the order is persisted, and it is sent to the POS.
**Payment is verified, never trusted.** `cardPresent` must reference a `/payments/v1`
record that is `approved`, belongs to this location, is unused, and whose amount equals
the order total. `cardToken` / `wallet` are charged by the server. A client can never
mark an order paid by itself.
If POS submission fails after payment, the server voids/refunds and returns
`502 POS_REJECTED` with `payment.status` — the client does not need to void.
'
parameters:
- $ref: '#/components/parameters/idempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/OrderRequest'
- type: object
required:
- customer
- payment
properties:
quoteId:
type: string
expectedTotal:
type: integer
description: Cents. If given and ≠ server total, reject with PRICE_CHANGED before
charging.
responses:
'201':
description: Order accepted
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
'200':
description: Idempotent replay of an order already created with this key
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
'402':
$ref: '#/components/responses/PaymentFailed'
'409':
$ref: '#/components/responses/Conflict'
'422':
$ref: '#/components/responses/Unprocessable'
'502':
$ref: '#/components/responses/PosRejected'
x-status: live
/orders/{orderId}:
get:
tags:
- Orders
operationId: getOrder
summary: Order status and receipt
description: 'Callable with the API key that created the order, or with the order''s `accessToken`
(returned at creation; safe to put in a customer-facing tracking link). Order ids are
not sequential and are not the POS/restaurant order number.
'
security:
- apiKey: []
- orderToken: []
parameters:
- $ref: '#/components/parameters/orderId'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
'404':
$ref: '#/components/responses/NotFound'
x-status: live
/orders/{orderId}/arrival:
post:
tags:
- Orders
operationId: notifyArrival
summary: Curbside "I'm here"
security:
- apiKey: []
- orderToken: []
parameters:
- $ref: '#/components/parameters/orderId'
requestBody:
content:
application/json:
schema:
type: object
properties:
vehicle:
$ref: '#/components/schemas/Vehicle'
parkingSpot:
type: string
responses:
'204':
description: Merchant notified
x-status: planned
/customers/token:
post:
tags:
- Customers
operationId: customerLogin
summary: Exchange customer credentials (or an SMS one-time code) for a customer bearer token
description: Scoped to one merchant. Replaces the `hash`/`username` cookie login for API clients.
requestBody:
required: true
content:
application/json:
schema:
oneOf:
- type: object
required:
- locationId
- email
- password
properties:
locationId:
type: string
email:
type: string
password:
type: string
- type: object
required:
- locationId
- phone
- otp
properties:
locationId:
type: string
phone:
type: string
otp:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
accessToken:
type: string
expiresAt:
type: string
format: date-time
customer:
$ref: '#/components/schemas/Customer'
'401':
$ref: '#/components/responses/Unauthorized'
x-status: planned
/customers/me/orders:
get:
tags:
- Customers
operationId: myOrders
summary: Order history (reorder source)
security:
- customerToken: []
parameters:
- name: locationId
in: query
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
orders:
type: array
items:
$ref: '#/components/schemas/Order'
x-status: planned
/customers/me/payment-methods:
get:
tags:
- Customers
operationId: myPaymentMethods
summary: Saved cards (tokens only; brand + last4)
security:
- customerToken: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: string
brand:
type: string
last4:
type: string
expMonth:
type: integer
expYear:
type: integer
description: 4-digit
x-status: planned
/customers/me/loyalty:
get:
tags:
- Loyalty
operationId: myLoyalty
summary: Points balance, punch cards and redeemable rewards at a location
security:
- customerToken: []
parameters:
- name: locationId
in: query
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/LoyaltyAccount'
x-status: planned
webhooks:
order.updated:
post:
tags:
- Webhooks
summary: Sent to the client's registered URL whenever an order's status changes
description: 'Signed like our Shift4 loyalty inbound: header `X-RTO-Signature: t=<unix>,v1=<hex>`
where
v1 = HMAC-SHA256(secret, t + "." + rawBody). Reject if |now - t| > 300s. Retries with
exponential backoff for 24h; `eventId` is stable across retries.
'
requestBody:
content:
application/json:
schema:
type: object
properties:
eventId:
type: string
type:
type: string
const: order.updated
createdAt:
type: string
format: date-time
order:
$ref: '#/components/schemas/Order'
responses:
2XX:
description: Acknowledged
components:
securitySchemes:
apiKey:
type: http
scheme: bearer
description: '`Authorization: Bearer <key>`. Keys are issued per client (kiosk fleet, app or partner)
and scoped to named locations. RTO kiosks use their enrolled device token here, limited to their
own location.'
orderToken:
type: apiKey
in: query
name: token
description: Per-order read token returned as `Order.accessToken`.
customerToken:
type: http
scheme: bearer
description: From POST /customers/token. Must be sent together with the client's apiKey via `X-RTO-Api-Key`.
parameters:
locationId:
name: locationId
in: path
required: true
description: Restaurant orderUrl
schema:
type: string
orderId:
name: orderId
in: path
required: true
schema:
type: string
idempotencyKey:
name: Idempotency-Key
in: header
required: true
schema:
type: string
format: uuid
responses:
NotFound:
description: Unknown location, item or order
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Missing/invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unprocessable:
description: Cart/order cannot be placed as sent. `error.details.issues` lists every problem.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Conflict:
description: PRICE_CHANGED (details.quote has new totals), IDEMPOTENCY_CONFLICT, or PAYMENT_ALREADY_USED
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
PaymentFailed:
description: PAYMENT_DECLINED / PAYMENT_AMOUNT_MISMATCH / PAYMENT_NOT_APPROVED. Nothing sent to
the POS.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
PosRejected:
description: POS refused the order; payment already voided/refunded (see details.payment).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
RateLimited:
description: Too many requests; honour Retry-After
headers:
Retry-After:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
schemas:
Error:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
enum:
- UNAUTHORIZED
- FORBIDDEN
- NOT_FOUND
- VALIDATION_FAILED
- LOCATION_UNAVAILABLE
- LOCATION_CLOSED
- ORDER_TYPE_UNAVAILABLE
- SLOT_UNAVAILABLE
- ITEM_UNAVAILABLE
- ITEM_NOT_ON_MENU
- INVALID_MODIFIERS
- BELOW_MINIMUM
- ABOVE_MAXIMUM
- OUTSIDE_DELIVERY_ZONE
- PROMOTION_INVALID
- PRICE_CHANGED
- IDEMPOTENCY_CONFLICT
- PAYMENT_DECLINED
- PAYMENT_AMOUNT_MISMATCH
- PAYMENT_NOT_APPROVED
- PAYMENT_ALREADY_USED
- PAYMENT_METHOD_NOT_ALLOWED
- POS_REJECTED
- RATE_LIMITED
- INTERNAL
message:
type: string
description: Human readable; safe to show a customer
details:
type: object
properties:
issues:
type: array
items:
$ref: '#/components/schemas/Issue'
quote:
$ref: '#/components/schemas/Quote'
payment:
$ref: '#/components/schemas/PaymentResult'
requestId:
type: string
Issue:
type: object
required:
- code
- message
properties:
code:
type: string
description: One of Error.code values
message:
type: string
lineId:
type: string
description: Cart line the issue refers to
itemId:
type: string
modifierGroupId:
type: string
nextAvailableTime:
type: string
format: date-time
OrderType:
type: string
enum:
- pickup
- curbside
- delivery
- dineIn
description: 'pickup = carry-out; curbside = pickup + vehicle; delivery = own fleet or DaaS (see
Location.orderTypes[].deliveryProvider); dineIn = table service / kiosk eat-in.
Catering is a pickup/delivery order with a future `requestedTime` (Location.catering rules).
'
Location:
type: object
properties:
locationId:
type: string
name:
type: string
phone:
type: string
address:
$ref: '#/components/schemas/Address'
timeZone:
type: string
example: America/Los_Angeles
imageUrl:
type: string
logoUrl:
type: string
brandColor:
type: string
acceptingOrders:
type: boolean
description: false when paused/unavailable (admin pause-for-today)
openNow:
type: boolean
taxRate:
type: string
example: '0.0825'
currency:
type: string
example: USD
orderTypes:
type: array
items:
type: object
properties:
type:
$ref: '#/components/schemas/OrderType'
enabled:
type: boolean
asapAllowed:
type: boolean
futureOrdersAllowed:
type: boolean
maxDaysAhead:
type: integer
prepTimeMinutes:
type: integer
minimumOrder:
type: integer
description: cents
maximumOrder:
type: integer
description: cents; 0 = none
deliveryProvider:
type: string
enum:
- merchant
- doordash
- uber
- firstDelivery
description: delivery only
vehicleInfoRequired:
type: boolean
instructions:
type: string
paymentMethods:
type: array
items:
type: string
enum:
- card
- applePay
- googlePay
- giftCard
- payAtStore
tipping:
type: object
properties:
enabled:
type: boolean
suggestions:
type: array
items:
type: object
properties:
percent:
type: integer
isDefault:
type: boolean
fees:
type: array
description: Service / convenience / CC fees that may appear on the quote
items:
type: object
properties:
type:
type: string
enum:
- service
- convenience
- creditCard
- bag
- deposit
label:
type: string
flat:
type: integer
description: cents
percent:
type: string
taxable:
type: boolean
guestCheckout:
type: object
properties:
allowed:
type: boolean
emailRequired:
type: boolean
phoneRequired:
type: boolean
cardTokenization:
type: object
description: How a client obtains a `cardToken` for this location
properties:
provider:
type: string
enum:
- shift4I4go
- stripe
- datacap
publicConfig:
type: object
additionalProperties: true
features:
type: object
properties:
specialInstructions:
type: boolean
coupons:
type: boolean
giftCards:
type: boolean
loyalty:
type: boolean
languages:
type: array
items:
type: string
example:
- en
- es
Menu:
type: object
properties:
menuId:
type: string
name:
type: string
currency:
type: string
updatedAt:
type: string
format: date-time
categories:
type: array
items:
$ref: '#/components/schemas/MenuCategory'
MenuCategory:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
imageUrl:
type: string
sortOrder:
type: integer
availability:
$ref: '#/components/schemas/Availability'
items:
type: array
items:
$ref: '#/components/schemas/MenuItem'
MenuItem:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
imageUrl:
type: string
price:
type: integer
description: cents; base price when there are no sizes
sizes:
type: array
description: Mutually exclusive priced variants (exactly one must be chosen when present)
items:
type: object
properties:
id:
type: string
name:
type: string
price:
type: integer
available:
type: boolean
isDefault:
type: boolean
modifierGroups:
type: array
items:
$ref: '#/components/schemas/ModifierGroup'
available:
type: boolean
description: false = 86'd / sold out
availability:
$ref: '#/components/schemas/Availability'
taxRate:
type: string
description: overrides location taxRate when present
tags:
type: array
items:
type: string
example:
- alcohol
- spicy
- vegetarian
minimumAge:
type: integer
maxQuantity:
type: integer
specialInstructionsAllowed:
type: boolean
posId:
type: string
description: POS PLU / item GUID, informational
ModifierGroup:
type: object
properties:
id:
type: string
name:
type: string
minSelections:
type: integer
maxSelections:
type: integer
description: 0 = unlimited
maxPerModifier:
type: integer
description: max quantity of a single modifier (e.g. extra cheese x2)
style:
type: string
enum:
- standard
- pizzaTopping
description: pizzaTopping allows placement left/right/whole
modifiers:
type: array
items:
$ref: '#/components/schemas/Modifier'
Modifier:
type: object
properties:
id:
type: string
name:
type: string
price:
type: integer
description: cents
sizePrices:
type: object
additionalProperties:
type: integer
description: sizeId → price when price depends on the chosen size
halfPrice:
type: integer
description: cents when placed on one half (pizzaTopping)
isDefault:
type: boolean
description: pre-selected / included
available:
type: boolean
modifierGroups:
type: array
description: nested groups (e.g. "choose dressing" under a side)
items:
$ref: '#/components/schemas/ModifierGroup'
Availability:
type: object
description: When absent, available whenever the location is open.
properties:
windows:
type: array
items:
type: object
properties:
days:
type: array
items:
type: string
enum:
- mon
- tue
- wed
- thu
- fri
- sat
- sun
start:
type: string
example: '11:00'
end:
type: string
example: '15:00'
orderTypes:
type: array
items:
$ref: '#/components/schemas/OrderType'
Schedule:
type: object
properties:
locationId:
type: string
orderType:
$ref: '#/components/schemas/OrderType'
timeZone:
type: string
now:
type: string
format: date-time
asapAvailable:
type: boolean
asapEstimate:
type: string
format: date-time
nextOpen:
type: string
format: date-time
days:
type: array
items:
type: object
properties:
date:
type: string
format: date
closed:
type: boolean
closedReason:
type: string
enum:
- closed
- holiday
- paused
hours:
type: array
items:
type: object
properties:
open:
type: string
format: date-time
close:
type: string
format: date-time
slots:
type: array
items:
type: object
properties:
time:
type: string
format: date-time
available:
type: boolean
reason:
type: string
enum:
- full
- pastCutoff
- leadTime
Address:
type: object
properties:
line1:
type: string
line2:
type: string
city:
type: string
state:
type: string
postalCode:
type: string
country:
type: string
default: US
lat:
type: number
lng:
type: number
instructions:
type: string
description: gate code, apartment notes
Vehicle:
type: object
properties:
make:
type: string
model:
type: string
color:
type: string
plate:
type: string
DeliveryQuote:
type: object
properties:
deliverable:
type: boolean
reason:
type: string
enum:
- outsideZone
- belowMinimum
- providerUnavailable
- closed
fee:
type: integer
description: cents
minimumOrder:
type: integer
estimatedDeliveryTime:
type: string
format: date-time
provider:
type: string
zoneId:
type: string
Cart:
type: object
required:
- locationId
- lines
properties:
locationId:
type: string
lines:
type: array
minItems: 1
items:
$ref: '#/components/schemas/CartLine'
CartLine:
type: object
required:
- itemId
- quantity
properties:
lineId:
type: string
description: client-chosen; echoed in issues and receipt
itemId:
type: string
sizeId:
type: string
quantity:
type: integer
minimum: 1
modifiers:
type: array
items:
$ref: '#/components/schemas/CartModifier'
specialInstructions:
type: string
maxLength: 140
forName:
type: string
description: label for whom the item is (party orders)
CartModifier:
type: object
required:
- modifierId
properties:
groupId:
type: string
modifierId:
type: string
quantity:
type: integer
minimum: 1
default: 1
placement:
type: string
enum:
- whole
- left
- right
default: whole
modifiers:
type: array
items:
$ref: '#/components/schemas/CartModifier'
OrderRequest:
allOf:
- $ref: '#/components/schemas/Cart'
- type: object
required:
- orderType
properties:
orderType:
$ref: '#/components/schemas/OrderType'
requestedTime:
type: string
format: date-time
description: Omit for ASAP. Must be an available slot from /schedule. ASAP on a closed store
is rejected (LOCATION_CLOSED) — never silently rolled to the next day.
deliveryAddress:
$ref: '#/components/schemas/Address'
vehicle:
$ref: '#/components/schemas/Vehicle'
tableNumber:
type: string
tip:
type: object
properties:
amount:
type: integer
description: cents
percent:
type: integer
description: alternative to amount; server computes
promoCode:
type: string
notes:
type: string
maxLength: 250
description: order-level instructions
customer:
$ref: '#/components/schemas/Customer'
payment:
$ref: '#/components/schemas/PaymentRequest'
source:
type: object
properties:
channel:
type: string
enum:
- kiosk
- app
- web
- partner
deviceId:
type: string
partnerOrderId:
type: string
Customer:
type: object
properties:
firstName:
type: string
lastName:
type: string
email:
type: string
format: email
phone:
type: string
description: E.164 or 10 digits; server normalizes (formatted phones must never fail a paid
order)
marketingOptIn:
type: boolean
PaymentRequest:
type: object
required:
- method
properties:
method:
type: string
enum:
- cardToken
- wallet
- cardPresent
- softPos
- savedCard
- giftCard
- payAtStore
cardToken:
type: object
description: Card-not-present token from Location.cardTokenization (e.g. Shift4 i4Go TrueToken).
Server charges it.
properties:
token:
type: string
postalCode:
type: string
wallet:
type: object
properties:
type:
type: string
enum:
- applePay
- googlePay
token:
type: string
cardPresent:
type: object
description: A kiosk pinpad payment already approved via /payments/v1/start. Server verifies
location, amount and single use.
properties:
paymentId:
type: string
softPos:
type: object
description: On-device Datacap (dsiEMVAndroid) result. Only accepted from a device enrolled
for SoftPOS; approvedAmount must equal the server total.
properties:
recordNo:
type: string
authCode:
type: string
refNo:
type: string
approvedAmount:
type: string
description: dollars, e.g. 27.16
cardType:
type: string
acctNoMasked:
type: string
savedCardId:
type: string
giftCards:
type: array
description: Applied first; remaining balance goes to the primary method
items:
type: object
properties:
cardNumber:
type: string
pin:
type: string
amount:
type: integer
description: cents; omit to use max available
loyaltyRewardIds:
type: array
items:
type: string
Quote:
type: object
properties:
quoteId:
type: string
expiresAt:
type: string
format: date-time
orderable:
type: boolean
description: false when issues[] is non-empty
issues:
type: array
items:
$ref: '#/components/schemas/Issue'
lines:
type: array
items:
$ref: '#/components/schemas/PricedLine'
totals:
$ref: '#/components/schemas/Totals'
estimatedReadyTime:
type: string
format: date-time
upsells:
type: array
items:
type: object
properties:
itemId:
type: string
name:
type: string
price:
type: integer
PricedLine:
type: object
properties:
lineId:
type: string
itemId:
type: string
name:
type: string
sizeName:
type: string
quantity:
type: integer
unitPrice:
type: integer
description: cents incl. modifiers
total:
type: integer
modifiers:
type: array
items:
type: object
properties:
modifierId:
type: string
name:
type: string
placement:
type: string
price:
type: integer
specialInstructions:
type: string
Totals:
type: object
description: total = subtotal - discount + fees + deliveryFee + tax + tip. All cents.
properties:
subtotal:
type: integer
discount:
type: integer
fees:
type: array
items:
type: object
properties:
type:
type: string
label:
type: string
amount:
type: integer
deliveryFee:
type: integer
tax:
type: integer
tip:
type: integer
total:
type: integer
giftCardApplied:
type: integer
amountDue:
type: integer
description: total - giftCardApplied - loyalty; what the primary method is charged
PaymentResult:
type: object
properties:
method:
type: string
status:
type: string
enum:
- pending
- approved
- declined
- voided
- refunded
- dueAtStore
amount:
type: integer
brand:
type: string
last4:
type: string
authCode:
type: string
reference:
type: string
description: processor reference (for support/refunds)
Order:
type: object
properties:
orderId:
type: string
description: opaque, non-sequential
orderNumber:
type: string
description: human/restaurant-facing number shown on tickets
accessToken:
type: string
description: returned on create only; lets GET /orders/{id}?token= be used from a customer tracking
link
locationId:
type: string
status:
type: string
enum:
- received
- scheduled
- sentToPos
- confirmed
- ready
- outForDelivery
- completed
- cancelled
- failed
statusReason:
type: string
orderType:
$ref: '#/components/schemas/OrderType'
placedAt:
type: string
format: date-time
requestedTime:
type: string
format: date-time
estimatedReadyTime:
type: string
format: date-time
lines:
type: array
items:
$ref: '#/components/schemas/PricedLine'
removedLines:
type: array
description: Always empty for API orders — sold-out items reject the order (ITEM_UNAVAILABLE)
rather than being silently dropped after payment.
items:
type: string
totals:
$ref: '#/components/schemas/Totals'
payment:
$ref: '#/components/schemas/PaymentResult'
customer:
$ref: '#/components/schemas/Customer'
deliveryAddress:
$ref: '#/components/schemas/Address'
delivery:
type: object
properties:
provider:
type: string
trackingUrl:
type: string
driverName:
type: string
pos:
type: object
properties:
system:
type: string
example: skytab
checkNumber:
type: string
status:
type: string
enum:
- pending
- sent
- acknowledged
- rejected
trackingUrl:
type: string
LoyaltyAccount:
type: object
properties:
enrolled:
type: boolean
points:
type: integer
pointsValue:
type: integer
description: cents
punchCards:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
punches:
type: integer
threshold:
type: integer
rewards:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
pointsCost:
type: integer
value:
type: integer
redeemable:
type: boolean
Questions or partner access: [email protected].