Appearance
Orders
The Orders API handles order calculation, creation, and tracking.
Calculate Order
Calculate order totals including tax before submitting.
POST /v1/ecommerce/orders/calculateAuthentication: OAuth Token
Scope: kitchenclick:orders.calculate
Rate Limit: 30/min per client
Request Body
json
{
"location_id": "loc_00000k1L2m3N4o5",
"order_type": "pickup",
"items": [
{
"item_id": "itm_00000a1B2c3D4e5",
"quantity": 2,
"special_instructions": "No onions on one",
"modifiers": [
{ "modifier_id": "mod_cheddar", "quantity": 1 },
{ "modifier_id": "mod_bacon", "quantity": 1 }
]
}
],
"tip_amount": 5.00,
"save_quote": true
}Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
location_id | string | Yes¹ | Target location ID |
order_type | string | Yes¹ | One of the accepted order types |
items | array | Yes¹ | Order items |
items[].item_id | string | Yes | Menu item ID |
items[].quantity | integer | Yes | Quantity (≥ 1) |
items[].special_instructions | string | No | Item-level note (≤ 255) |
items[].modifiers | array | No | Selected modifiers |
items[].modifiers[].modifier_id | string | Yes | Modifier ID |
items[].modifiers[].quantity | integer | No | Modifier quantity |
items[].modifiers[].children | array | No | Nested modifiers — { modifier_id, quantity } |
customer | object | No | { name, phone, email } |
fulfillment_method | string | Cond. | pickup or delivery; required when order_type is catering |
scheduled_at | string | No | ISO 8601 future time (store-local) |
delivery_info | object | Cond. | Required for delivery — { address, address_line2, city, state, zip, instructions } |
tip_amount | number | No | Flat tip amount |
tip_percentage | number | No | Tip as a percent of subtotal (0–100) |
delivery_fee | number | No | Delivery fee, e.g. the chosen quote fee from Delivery |
special_instructions | string | No | Order-level note (≤ 500) |
save_quote | boolean | No | When true, returns a reusable quote_token_id |
quote_token_id | string | No | Re-price an existing saved quote instead of a fresh calculation |
quote_validity_minutes | integer | No | Quote lifetime, 5–60 (default 15) |
¹ location_id, order_type, and items are required for a fresh calculation. When quote_token_id is supplied they are optional (only the fields you send are changed on the quote).
Response
json
{
"status": "success",
"data": {
"items": [
{
"item_id": "itm_00000a1B2c3D4e5",
"name": "Classic Burger",
"quantity": 2,
"unit_price": 14.99,
"subtotal": 29.98,
"tax": 1.87,
"deposits": 0,
"modifiers": [
{ "modifier_id": "mod_bacon", "name": "Bacon", "price": 2.00, "quantity": 1 }
],
"is_market_priced": false,
"price_status": "set"
}
],
"totals": {
"subtotal": 29.98,
"tax_amount": 1.87,
"deposits_amount": 0,
"fees_amount": 0,
"delivery_fee": 0,
"tip_amount": 5.00,
"total": 36.85
},
"breakdown": {
"tax": [
{ "id": "tax_rate_1", "name": "Sales Tax", "pos_tax_code": "1", "rate": 0.0625, "taxable_amount": 29.98, "amount": 1.87 }
],
"deposits": [],
"fees": []
},
"quote": {
"quote_token_id": "kqt_00000a1B2c3D4e5",
"expires_at": "2026-06-17T14:30:00Z",
"validity_minutes": 15,
"updated": false
}
}
}Response Notes
| Field | Notes |
|---|---|
totals | All amounts are decimal dollars. total = subtotal + tax + deposits + fees + delivery_fee + tip. |
items[].is_market_priced | true for market-priced items whose price is set in-kitchen; these contribute 0 until priced (price_status: "pending"). |
breakdown | Itemized tax, deposits, and fees arrays behind the totals. |
quote | Present only when save_quote is true (or when updating a quote). Pass quote.quote_token_id to Create Stripe Payment Intent and the order-create endpoints. |
catering | An additional catering object (deposit_percentage, deposit_amount, balance_after_deposit, allow_deposit) is included when order_type is catering. |
Create Order
Submit a new order for processing.
POST /v1/ecommerce/ordersWhich order-creation endpoint should I use?
POST /v1/ecommerce/orders/stripe— the standard online path: create an order after a Stripe card payment has been confirmed client-side (pass the confirmedpayment_intent_id). Use this for card checkout. See Payments.POST /v1/ecommerce/orders(this endpoint) — create an order without an attached online card payment, e.g. pay-in-store.- Payment presentment (Payments) is for in-person terminals/kiosks, not browser checkout.
For the full sequence, see the End-to-End Integration Flow.
Authentication: OAuth Token
Scope: kitchenclick:orders.create
Rate Limit: 30/min per client
Request Body
json
{
"location_id": "loc_00000k1L2m3N4o5",
"order_type": "pickup",
"customer": {
"name": "John Doe",
"phone": "(555) 123-4567",
"email": "john.doe@example.com",
"notify_on_ready": true
},
"scheduled_at": null,
"special_instructions": "Extra napkins please",
"items": [
{
"item_id": "itm_00000a1B2c3D4e5",
"quantity": 2,
"special_instructions": "No onions on one",
"modifiers": [
{ "modifier_id": "mod_cheddar", "quantity": 1 }
]
}
],
"payment_method": "cash",
"tip_amount": 5.00
}Create from a saved quote
Instead of resending all order details, you can submit just { "quote_token_id": "kqt_…", "customer": { … } } using a quote_token_id returned by Calculate Order.
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
location_id | string | Yes | Target location ID |
order_type | string | Yes | One of the accepted order types |
customer | object | No | Customer info |
customer.name | string | No | Customer name |
customer.phone | string | No | Contact phone |
customer.email | string | No | Email for receipt |
customer.notify_on_ready | boolean | No | Send a ready notification |
concept_id | string | No | Concept ID (required for catering orders) |
scheduled_at | string | No | ISO 8601 future time for scheduled orders |
special_instructions | string | No | Order-level note (≤ 500) |
items | array | Yes | Order items (same shape as Calculate Order) |
items[].item_id | string | Yes | Menu item ID |
items[].quantity | integer | Yes | Quantity (≥ 1) |
items[].special_instructions | string | No | Item-level note (≤ 255) |
items[].modifiers[].modifier_id | string | Yes | Modifier ID |
delivery_info | object | Cond. | Required for delivery orders (see below) |
payment_method | string | No | credit_card, cash, or digital_wallet |
tip_amount | number | No | Tip amount |
Alternatively, send quote_token_id (+ customer) to create the order from a saved quote.
Delivery Info
For delivery orders, include a delivery_info object:
json
{
"delivery_info": {
"address": "456 Oak Avenue",
"address_line2": "Apt 2B",
"city": "Austin",
"state": "TX",
"zip": "78702",
"instructions": "Gate code: 1234. Leave at door."
}
}Response
json
{
"status": "success",
"message": "Order placed successfully",
"data": {
"order_id": "ord_00000x1Y2z3A4b5",
"order_number": "1247",
"status": "confirmed",
"order_type": "takeout",
"channel": "ecommerce",
"placed_at": "2026-06-17T14:30:00Z",
"estimated_ready_time": "2026-06-17T14:45:00Z",
"scheduled_at": null,
"totals": {
"subtotal": 29.98,
"tax": 2.22,
"delivery_fee": 0,
"tip": 5.00,
"total": 37.20
},
"tracking_url": "https://api.kitchenclick.retailsuccessplatform.com/api/v1/ecommerce/orders/ord_00000x1Y2z3A4b5/track"
}
}| Field | Type | Description |
|---|---|---|
order_id | string | Order ID (prefix ord_) — use for tracking |
order_number | string | Human-readable order number |
status | string | confirmed (ASAP) or scheduled (future order, staged for firing) |
order_type | string | Canonical stored type (e.g. takeout, dine_in, delivery) |
channel | string | ecommerce, or kiosk when the X-Kiosk-ID header is supplied |
totals | object | Decimal-dollar amounts: subtotal, tax, delivery_fee, tip, total |
tracking_url | string | Absolute URL to the public tracking endpoint |
Customer Order History
Retrieve past orders for a customer by email address. Useful for showing order history or enabling quick reorder.
GET /v1/ecommerce/customers/ordersAuthentication: OAuth Token
Scope: kitchenclick:orders.calculate
Rate Limit: 200/min per client
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Customer email address |
location_id | string | No | Filter by location hashkey |
per_page | integer | No | Results per page (1-50, default: 20) |
Response
json
{
"status": "success",
"data": [
{
"order_id": "ord_00000x1Y2z3A4b5",
"order_number": "#1247",
"status": "completed",
"order_type": "pickup",
"date": "2024-01-15T14:30:00Z",
"total": 34.20,
"item_summary": "Classic Burger, Side Salad, Iced Tea",
"items_count": 3
},
{
"order_id": "ord_00000c6D7e8F9g0",
"order_number": "#1198",
"status": "completed",
"order_type": "delivery",
"date": "2024-01-10T18:15:00Z",
"total": 52.75,
"item_summary": "BBQ Chicken Pizza, Caesar Salad, Garlic Bread +2 more",
"items_count": 5
}
],
"meta": {
"total": 42,
"per_page": 20,
"current_page": 1,
"last_page": 3
}
}Response Fields
| Field | Type | Description |
|---|---|---|
order_id | string | Order hashkey |
order_number | string | Human-readable order number |
status | string | Order status (cancelled orders are excluded) |
order_type | string | pickup, delivery, dine-in, etc. |
date | string | ISO 8601 timestamp when order was placed |
total | decimal | Order total amount |
item_summary | string | First 3 item names, then "+X more" if applicable |
items_count | integer | Total number of items in the order |
meta | object | Pagination metadata |
Track Order
Get current order status. This endpoint is public - no authentication required.
GET /v1/ecommerce/orders/{order}/trackAuthentication: None (Public)
Rate Limit: 100/min per IP
Path Parameters
| Parameter | Type | Description |
|---|---|---|
order | string | Order hashkey |
Response
json
{
"status": "success",
"data": {
"order_number": "1247",
"status": "preparing",
"order_type": "takeout",
"placed_at": "2024-01-15T14:30:00Z",
"estimated_ready_time": "2024-01-15T14:45:00Z",
"status_history": [
{
"status": "pending",
"timestamp": "2024-01-15T14:30:00Z"
},
{
"status": "confirmed",
"timestamp": "2024-01-15T14:30:15Z"
},
{
"status": "preparing",
"timestamp": "2024-01-15T14:32:00Z"
}
],
"items": [
{
"name": "Classic Burger",
"quantity": 2,
"status": "preparing"
}
]
}
}Order Statuses
| Status | Description |
|---|---|
pending | Order received, awaiting confirmation |
confirmed | Order confirmed, queued for kitchen |
preparing | Kitchen is preparing the order |
ready | Order is ready for pickup/delivery |
out_for_delivery | Driver has picked up (delivery only) |
completed | Order fulfilled |
cancelled | Order was cancelled |
Order Types
order_type accepts the values below. Inputs are normalized to a canonical stored value, so the ecommerce aliases (e.g. pickup, dinein) are accepted and map to the canonical form.
| Input value | Canonical | Description |
|---|---|---|
pickup, takeout | takeout | Customer picks up |
delivery | delivery | Delivered to customer address |
dinein, dine-in, dine_in | dine_in | Dine in at location |
drivethru, drive-thru, drive_through, drive_thru | drive_thru | Drive-thru pickup |
curbside | curbside | Curbside pickup |
catering | catering | Catering order (deposit/invoice flow) |
special_order | special_order | Special order |
Scheduled Orders
To place an order for a future time, set scheduled_at (and, for delivery/catering, the relevant fulfillment fields):
json
{
"scheduled_at": "2026-06-18T18:00:00Z",
"order_type": "pickup"
}scheduled_atmust be in the future.- Allowed lead time, increments, and how far ahead orders may be placed are configured per location/concept — fetch them from the scheduling-config and time-slots endpoints and present only valid slots.
- Scheduled orders are created with status
scheduledand fired to the kitchen at the appropriate time.
Error Responses
Item Unavailable
json
{
"status": "error",
"message": "One or more items are unavailable",
"errors": {
"items": [
{
"item_id": "itm_00000a1B2c3D4e5",
"error": "Item is currently 86'd (out of stock)"
}
]
}
}Invalid Modifiers
json
{
"status": "error",
"message": "Invalid modifier selection",
"errors": {
"items.0.modifiers": [
"Option group 'Choose Your Cheese' requires exactly 1 selection"
]
}
}Location Closed
json
{
"status": "error",
"message": "Location is currently closed",
"errors": {
"location": ["Location is not accepting orders at this time"]
}
}Example: Complete Order Flow
javascript
async function submitOrder(locationId, cart, customer, paymentMethod) {
const token = await tokenManager.getToken();
// 1. Calculate totals first
const calcResponse = await fetch('/api/v1/ecommerce/orders/calculate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
location_id: locationId,
order_type: 'pickup',
items: cart.items.map(item => ({
item_id: item.id,
quantity: item.quantity,
modifiers: item.selectedModifiers.map(m => ({
modifier_id: m.id,
quantity: 1,
})),
})),
}),
});
const calculation = await calcResponse.json();
if (calculation.status !== 'success') {
throw new Error(calculation.message);
}
// 2. Show totals to customer, get confirmation
const confirmed = await showOrderSummary(calculation.data);
if (!confirmed) return null;
// 3. Submit the order
const orderResponse = await fetch('/api/v1/ecommerce/orders', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
location_id: locationId,
customer: {
name: customer.name,
phone: customer.phone,
email: customer.email,
},
order_type: 'pickup',
items: cart.items.map(item => ({
item_id: item.id,
quantity: item.quantity,
special_instructions: item.notes,
modifiers: item.selectedModifiers.map(m => ({
modifier_id: m.id,
quantity: 1,
})),
})),
payment_method: paymentMethod,
tip_amount: cart.tip,
}),
});
const order = await orderResponse.json();
if (order.status !== 'success') {
throw new Error(order.message);
}
return order.data;
}
// 4. Poll for status updates
async function pollOrderStatus(orderHashkey, onUpdate) {
const poll = async () => {
const response = await fetch(
`/api/v1/ecommerce/orders/${orderHashkey}/track`
);
const { data } = await response.json();
onUpdate(data);
if (!['completed', 'cancelled'].includes(data.status)) {
setTimeout(poll, 10000); // Poll every 10 seconds
}
};
poll();
}Changelog
| Date | Change |
|---|---|
| 2026-06-17 | Corrected Calculate/Create request and response shapes to match the API (location_id/item_id/modifier_id field names, delivery_info, the quote_token_id flow, real totals/breakdown shape); fixed the order-type values; removed the unsupported promo_code field. |
| 2026-03-14 | Added e-commerce API endpoints. |
| 2026-01-15 | Initial publication. |