restaurant-default (v1)
The default JobSchema for restaurant orders. Supports two order types — single (one person's order) and group (multi-person order with embedded children).
Metadata
| Field | Value |
|---|---|
name | restaurant-default |
vertical | restaurant |
version | 1 |
source | apiV20 |
Single vs. group orders
The orderType field on orderData selects between two structurally-different shapes. Pick the one that matches how the order arrived from your delivery partner / POS.
When to use each
single— one customer, one bag. The classic delivery or pickup ticket: a single person ordered, possibly with multipleline_items. One ticket prints.group— one host/coordinator with N individual sub-orders attached. Common for corporate lunches, office orders, group catering, and any flow where each person picks their own items but everything is paid for together. Thecustomerat the root oforderDatais the host (e.g. the company or the person organizing); the per-person details live on eachchildren[]entry.
Where line items live
single | group | |
|---|---|---|
Root line_items | Required — every item on the order | Not used (omitted) |
Root customer | The customer placing the order | The host / organizer (often a company) |
Each children[] entry | n/a | Has its own customer, line_items, and per-person totals |
A group order with three sub-orders is one logical Job — one POST, one Job record, one printed receipt (or N receipts when cut_between_children is set; see below).
Totals semantics
single—totalsis the whole order. Required:subtotal,tax,total,quantity.group— roottotalsis the parent summary across all children. Required:subtotal,quantity(only).taxandtotalare optional at the root because the host typically settles up later. Eachchildren[]entry also has atotalsblock with its ownsubtotalandquantityfor that one person.
Required-field differences at a glance
| Order type | Required top-level orderData fields |
|---|---|
single | orderType, id, customer, restaurant, line_items, totals, fulfillment, payment |
group | orderType, id, customer, restaurant, totals, fulfillment, payment, children |
Both shapes additionally require delivery_service + delivery_address + delivery_instructions when fulfillment.method === "delivery". Pickup and dine-in orders omit those.
webhook_url + webhook_method are required on every job regardless of orderType — they live at the envelope of the POST body (alongside printerId), not inside orderData.
Print-time differences
The same template renders both shapes — the layout adapts:
single— one continuous receipt: header, customer block, line items, totals, footer.group— header + parent totals at the top, then each child rendered as its own labeled section (name, items, per-person subtotal). The default is one continuous receipt; settingcut_between_children: trueat the root oforderDatainstructs the printer to emit aPARTIAL_CUTbetween every child sub-order, so each person's items come off as their own ticket.cut_between_childrenis silently ignored on single orders.
Lifecycle differences
- A group order is one Job regardless of child count. State transitions, webhooks, scheduled-print timing, copies, and cancellation all apply at the parent level.
- The
personNameattribute on the Job record is the host's name for groups and the customer's name for singles.
Shape
orderData: object
├── orderType: "single" | "group" # required
├── id: string # required (external order identifier, minLength 1)
├── customer: { name, phone?, company? } # required
├── restaurant: { name?, phone?, address? } # required
├── delivery_service: { name?, support_phone?, support_instructions? }
│ # required when fulfillment.method="delivery"
├── line_items: [LineItem, ...] # required for single
├── totals: {
│ subtotal, tax?, tip?, delivery_fee?,
│ discount?, total?, quantity
│ } # required
├── delivery_address: {
│ street, city, state, zip_code,
│ country?, apartment?, floor?,
│ entrance?, on_arrival?, subdivision?
│ } # required when fulfillment.method="delivery"
├── delivery_instructions: string # required when fulfillment.method="delivery"
├── fulfillment: {
│ method: "pickup" | "delivery" | "dine-in",
│ promised_time?, is_future_order?, pickup_type?
│ }
├── payment: { method?, is_prepaid? }
├── special_instructions: string
├── confirmation_code: string
├── cut_between_children: boolean # group orders only (default false)
└── children: [Child, ...] # required for group
LineItem
{
quantity: integer (≥ 0), # required
name: string, # required
price: number, # required
subtotal: number, # required
category?: string,
comment?: string,
options?: [{ name, quantity, price, comment? }]
}
Child (group orders only)
Each child is a self-contained sub-order for one person.
{
customer: { name, phone? }, # required
line_items: [LineItem, ...], # required
totals: {
subtotal: number, # required
quantity: integer # required
}
}
Required fields by order type
Base required fields (all orders):
| Order type | Required top-level orderData fields |
|---|---|
single | orderType, id, customer, restaurant, line_items, totals, fulfillment, payment |
group | orderType, id, customer, restaurant, totals, fulfillment, payment, children |
Note: webhook_url and webhook_method are also required on every job creation, but live at the root of the POST body (alongside printerId), not inside orderData. See the Create job page.
Additional fields required when fulfillment.method is delivery (both single and group):
delivery_servicedelivery_addressdelivery_instructions
Pickup (fulfillment.method: "pickup") and dine-in (fulfillment.method: "dine-in") orders may omit all three.
For single orders, totals must include subtotal, tax, total, and quantity. For group orders (and each embedded child), totals requires only subtotal and quantity.
Date-time fields (e.g. fulfillment.promised_time) must be ISO 8601 timestamps that include a timezone (2026-04-15T18:15:00Z or 2026-04-15T13:15:00-05:00).
Per-child cuts (group orders)
cut_between_children is optional. When set to true on a group order, each child is printed as its own ticket — useful when the individual orders are being handed out separately. Ignored on single orders.
Printed output
The template associated with restaurant-default (v1) produces a thermal-receipt layout from orderData. The same template renders both single and group orders. The previews below show the template applied to the example payloads in the next section.
Single order

Rendered from the single order example below.
Group order

Rendered from the group order example below.
Example — single order
{
"orderType": "single",
"id": "38086725",
"restaurant": {
"name": "MD Pizza Factory",
"phone": "800-709-7191",
"address": "4706 N Midkiff Rd, Midland, TX 79705"
},
"delivery_service": {
"name": "delivery.com",
"support_phone": "800-709-7191"
},
"customer": {
"name": "John Smith",
"phone": "432-894-7532"
},
"line_items": [
{
"quantity": 1,
"name": "Pepperoni Pizza",
"category": "pizza",
"price": 18.00,
"subtotal": 18.00,
"options": [
{ "name": "Extra Cheese", "quantity": 1, "price": 2.00 }
]
},
{
"quantity": 2,
"name": "Garlic Knots",
"category": "appetizer",
"price": 3.50,
"subtotal": 7.00,
"comment": "Extra garlic butter on the side"
}
],
"totals": {
"subtotal": 27.00,
"tax": 2.23,
"tip": 5.00,
"delivery_fee": 3.99,
"discount": 0,
"total": 38.22,
"quantity": 3
},
"delivery_address": {
"street": "123 Main St",
"city": "Springfield",
"state": "PA",
"zip_code": "19000",
"apartment": "4B",
"entrance": "Ring the doorbell twice"
},
"delivery_instructions": "Leave at door, no contact",
"fulfillment": {
"method": "delivery",
"promised_time": "2026-04-15T18:15:00Z",
"is_future_order": false
},
"payment": {
"method": "Pre-Paid",
"is_prepaid": true
}
}
Example — group order
{
"orderType": "group",
"id": "38086901",
"restaurant": {
"name": "MD Pizza Factory",
"phone": "800-709-7191",
"address": "4706 N Midkiff Rd, Midland, TX 79705"
},
"delivery_service": {
"name": "delivery.com",
"support_phone": "800-709-7191"
},
"customer": {
"name": "Acme Corp",
"phone": "432-555-0199",
"company": "Acme Corp"
},
"totals": {
"subtotal": 62.00,
"tax": 5.12,
"tip": 10.00,
"delivery_fee": 3.99,
"discount": 0,
"total": 81.11,
"quantity": 6
},
"delivery_address": {
"street": "500 Corporate Way",
"city": "Springfield",
"state": "PA",
"zip_code": "19000",
"floor": "12",
"on_arrival": "Check in with reception on 12th floor"
},
"delivery_instructions": "Deliver to front desk, ask for Jane",
"fulfillment": {
"method": "delivery",
"promised_time": "2026-04-15T12:30:00Z",
"is_future_order": true
},
"payment": {
"method": "Pre-Paid",
"is_prepaid": true
},
"children": [
{
"customer": {
"name": "Jane Doe",
"phone": "432-555-0111"
},
"line_items": [
{
"quantity": 1,
"name": "Margherita Pizza",
"category": "pizza",
"price": 16.00,
"subtotal": 16.00,
"options": [
{ "name": "Gluten-Free Crust", "quantity": 1, "price": 3.00 }
]
},
{
"quantity": 1,
"name": "Caesar Salad",
"category": "salad",
"price": 9.00,
"subtotal": 9.00,
"comment": "Dressing on the side"
}
],
"totals": {
"subtotal": 28.00,
"quantity": 2
}
},
{
"customer": {
"name": "Bob Lee",
"phone": "432-555-0122"
},
"line_items": [
{
"quantity": 1,
"name": "Pepperoni Pizza",
"category": "pizza",
"price": 18.00,
"subtotal": 18.00,
"options": [
{ "name": "Extra Cheese", "quantity": 1, "price": 2.00 }
]
},
{
"quantity": 2,
"name": "Garlic Knots",
"category": "appetizer",
"price": 3.50,
"subtotal": 7.00
}
],
"totals": {
"subtotal": 27.00,
"quantity": 3
}
},
{
"customer": {
"name": "Priya Patel",
"phone": "432-555-0133"
},
"line_items": [
{
"quantity": 1,
"name": "Veggie Calzone",
"category": "calzone",
"price": 12.00,
"subtotal": 12.00,
"comment": "No olives please"
}
],
"totals": {
"subtotal": 12.00,
"quantity": 1
}
}
]
}