API reference · Orders
Place an order
POST
/v1/ordersPlaces the order into the restaurant's POS. Staff see it in their Online orders inbox and accept or reject it.
- Scope
orders:write - 30 / minute (and 5 per customer phone per 10 minutes)
- Needs
Idempotency-Key
Body
…- Everything from Quote an order, plus:
customer.namestring 1–80required- Customer name (printed on the KOT and bill).
customer.phonestringrequired- 10-digit Indian mobile number (+91 optional).
payment"PAY_AT_COUNTER" | "CASH_ON_DELIVERY"required- Pickup → PAY_AT_COUNTER, delivery → CASH_ON_DELIVERY.
notestring ≤ 300- Note for the restaurant.
expectedTotalinteger (paise)- The quote's
total.amount. If the price changed since, you get PRICE_CHANGED with the new quote — recommended.
Request
curl https://api.billzova.com/v1/orders \
-H "Authorization: Bearer $BILLZOVA_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f0e1d2c-order-1042" \
-d '{"type":"DELIVERY","items":[{"menuItemId":"m-full","quantity":1}],
"delivery":{"address":"Flat 4, Gomti Nagar","pincode":"226010"},
"customer":{"name":"Rahul","phone":"9876543210"},
"payment":"CASH_ON_DELIVERY","expectedTotal":33600}'const order = await fetch('https://api.billzova.com/v1/orders', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BILLZOVA_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(), // reuse the SAME key if you retry
},
body: JSON.stringify({
type: 'DELIVERY',
items: [{ menuItemId: 'm-full', quantity: 1 }],
delivery: { address: 'Flat 4, Gomti Nagar', pincode: '226010' },
customer: { name: 'Rahul', phone: '9876543210' },
payment: 'CASH_ON_DELIVERY',
expectedTotal: quote.total.amount,
}),
}).then((r) => r.json());Response
{
"id": "0b8e…",
"object": "order", "test": false,
"number": "17",
"status": "PENDING",
"type": "DELIVERY",
"customer": { "name": "Rahul", "phone": "9876543210" },
"delivery": { "address": { "address": "Flat 4, Gomti Nagar", "pincode": "226010" }, "person": null },
"lines": [ … ],
"subtotal": { "amount": 32000, "currency": "INR", "display": "₹320" },
"tax": { "total": { "amount": 1600, "currency": "INR", "display": "₹16" } },
"charges": [],
"total": { "amount": 33600, "currency": "INR", "display": "₹336" },
"trackingUrl": "https://billzova.com/track/Vd3…",
"timeline": { "placedAt": "2026-10-24T13:02:11.000Z", "acceptedAt": null, "outForDeliveryAt": null, "completedAt": null }
}Good to know
- Statuses:
PENDING→ACCEPTED→PREPARING→READY→OUT_FOR_DELIVERY→COMPLETED, orREJECTED(by the restaurant, withrejectionReason) /CANCELLED(by the customer, or not accepted in time). - Orders the restaurant does not accept in time (default 15 minutes) are cancelled automatically.
Errors
| Code | HTTP | Meaning |
|---|---|---|
| IDEMPOTENCY_KEY_REQUIRED | 400 | Send an Idempotency-Key header with every create. |
| IDEMPOTENCY_KEY_REUSED | 422 | The same Idempotency-Key was used with a different body. |
| IDEMPOTENCY_IN_PROGRESS | 409 | The first request with this Idempotency-Key is still running. Retry the same request in a second or two. |
| PRICE_CHANGED | 409 | The total changed since the quote — the new quote is in the error. |
| ORDERING_OFF | 403 | Online ordering is switched off. |
| CLOSED | 409 | The restaurant is closed now. opensAt says when it opens. |
| NOT_ACCEPTING | 409 | No staff device is online to take the order. |
| RESTAURANT_UNAVAILABLE | 403 | The restaurant cannot take orders or bookings (subscription or account). |
| PAYMENT_MODE_NOT_ALLOWED | 422 | That payment mode is not allowed for this order type / restaurant. |
| OUT_OF_AREA | 422 | The pincode is outside the delivery area. |
| BELOW_MINIMUM | 422 | Below the minimum order amount (minimum in the error). |
| ITEM_UNAVAILABLE | 422 | A menu item or add-on is sold out / switched off. |
| ADDON_INVALID | 422 | Wrong add-on for the item, a duplicate, or above the group maximum. |
| VALIDATION_FAILED | 422 | The body is invalid — field says where. |
| RATE_LIMITED | 429 | Too many requests — wait for Retry-After seconds. |