Guides
Website ordering, end to end
Menu → cart → quote → order → status → tracking, the way Billzova websites do it.
Show open / closed
On page load call
GET /v1/restaurant. Ifordering.acceptingNowis false, showstatus.label(e.g. “Closed · opens 11:00 AM”) and hide checkout.Render the menu
GET /v1/menu(cache it; refresh withIf-None-Match). For items with sizes let the customer pick a variant; respect each add-on group'smax. Hide or grey outavailable: false.Quote the cart
On the checkout page
POST /v1/orders/quoteand show its lines, GST and total — never your own maths.Place the order
POST /v1/orderswith the customer's name and phone,payment, anIdempotency-Key, andexpectedTotalset to the quote'stotal.amount. OnPRICE_CHANGED, show the new quote from the error.Show status
Show the order page and poll
GET /v1/orders/{id}every 10–20 seconds untilCOMPLETED,REJECTEDorCANCELLED. Or send the customer thetrackingUrl.
What each status means
| Status | Meaning | Show the customer |
|---|---|---|
PENDING | Waiting for the restaurant | “Sent to the restaurant…” |
ACCEPTED | Accepted | “Accepted — ready in about N min” |
PREPARING / READY | In the kitchen / ready | “Being prepared” / “Ready for pickup” |
OUT_FOR_DELIVERY | On the way | Delivery person's name + call button |
COMPLETED | Done | “Enjoy your meal” |
REJECTED | Restaurant declined | rejectionReason |
CANCELLED | Cancelled (customer, or not accepted in time) | rejectionReason |
Keep the key on your server
export async function POST(req) {
const order = await req.json();
const res = await fetch('https://api.billzova.com/v1/orders', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BILLZOVA_KEY}`, // server-only env var
'Content-Type': 'application/json',
'Idempotency-Key': order.checkoutId,
},
body: JSON.stringify(order.payload),
});
return new Response(await res.text(), { status: res.status, headers: { 'Content-Type': 'application/json' } });
}