This page follows one dinner check from the menu to the kitchen. Payment is
covered in Payments and folios.
Every request below sends Authorization and x-property-id. The writes also
send the server's X-Staff-Token (see Authentication).
1. Load what the outlet sells
| Call | Returns |
|---|---|
GET /pos/outlets/{outlet_id} | The outlet, its settings and accepted payment methods |
GET /pos/outlets/{outlet_id}/items | Ids of the catalog items this outlet sells |
GET /pos/items | The property's catalog, with prices, to resolve those ids |
GET /pos/outlets/{outlet_id}/menus | How the outlet groups items into menus |
GET /pos/outlets/{outlet_id}/floor-plan | Sections and tables, for restaurant outlets |
GET /pos/settings/property | Currency and timezone, to display money and to know when scheduled offers apply |
2. Show a running total
While the server builds the cart, price it without saving anything:
POST /pos/orders/quote
{
"outlet_id": "5f1c2a90-7d3e-4b8a-a1c4-2e9f6d0b7a13",
"guest_count": 2,
"items": [
{ "key": "row-1", "item_id": "1043", "quantity": 2, "unit_price": "4.50" },
{ "key": "row-2", "item_id": "2211", "quantity": 1, "unit_price": "18.00" }
]
}key is your own identifier for the cart row; it is echoed back on each priced
line so you can match results to rows. A quote uses the same tax, fee, discount and rounding rules as a real order, so
the total it returns is the total the order will have. If taxes cannot be
computed at that moment, it returns 503 rather than an estimate.
3. Open the order
POST /pos/orders/
{
"outlet_id": "5f1c2a90-7d3e-4b8a-a1c4-2e9f6d0b7a13",
"order_type": "dine_in",
"table_id": "a8e4c1d2-3f5b-4a6c-9d7e-1b2c3d4e5f60",
"guest_count": 2,
"items": [
{ "item_id": "1043", "quantity": 2, "base_unit_price": "4.50", "note": "No ice" },
{ "item_id": "2211", "quantity": 1, "base_unit_price": "18.00" }
]
}Each line's item_id is a Cloudbeds catalog id, checked against the catalog.
base_unit_price is the list price the item sold at, before modifiers and
offers. It is kept as sent, so a later catalog price change never rewrites an
existing order.
Don't send a price with an offer already taken off. The server applies offers
itself, so a pre-discounted price gets the offer taken off twice. To make sure
the order matches what the guest was shown, send claimed_offer_amount on a line
(or claimed_offer_total on the order). If the server's offers come out
different, it refuses the order instead of silently repricing it. Taxes, fees
and totals are always computed server-side.
The response is the order: its id, the short display_number to show staff and
guests, a status of open, and each line's id, taxes and line_total, plus
the order's subtotal, tax_total, total and payable_total.
- Seating: passing
table_idseats the order. The table counts as occupied
for as long as an open order references it. - Order types:
dine_in,takeawayorroom_service. - Guests: attach a reservation with
reservation_idso the order can later be
charged to the room. - Naming:
aliasnames a check, such as "Ana's tab". It is free text, not an
identifier. - Offline clients: set
offline_id. If the request is replayed, the order
that was already created is returned instead of a duplicate.
4. Change it
PUT /pos/orders/{order_id} updates an open order. Send the whole item list:
- lines that carry
order_item_idare kept and updated; - lines without one are added;
- lines you leave out are removed.
Fields you omit are left alone, and an explicit null clears a field.
Other per-line changes:
| Change | Call |
|---|---|
| Discount one line | POST /pos/orders/{order_id}/items/{item_id}/discount |
| Charge a different price | PUT /pos/orders/{order_id}/items/{item_id}/price |
| Discount the whole order | POST /pos/orders/{order_id}/discount |
A discount above the outlet's cap needs an approval.
A custom price never does: it is a price, not a discount.
5. Fire to the kitchen
POST /pos/orders/{order_id}/send
{ "item_ids": ["0c9a3f8e-5b1d-4e8a-9f0b-6a2d7c4e1b55"] }The order becomes sent, and so do the lines it fired, which now have
is_sent: true. Omit item_ids to fire every active line, or send only some
lines to course the meal.
A sent line cannot simply be removed. Void it with
POST /pos/orders/{order_id}/void-item/{item_id}, which always needs an
approval with action void_sent_item.
6. Hand over, split or cancel
- Change of server:
POST /pos/orders/transfermoves one or more open orders to
another staff member. Either all of them move or none do. - Separate checks:
POST /pos/orders/{order_id}/splitdivides the items into
new orders. You can split a line's units too, for example one of two waters on
each check. The original order ends assplit, and each new order points back
to it inparent_order_id. Discounts, taxes and fees are divided so the checks
add up exactly to the original.POST /pos/orders/{order_id}/unsplitreverses
the split while every new check is still untouched. - Same items, several payers: don't split. Take several payments on the one
order instead (see Payments and folios). - Cancel:
POST /pos/orders/{order_id}/cancelworks on anopenorsent
order. A paid order is refunded instead.
Order statuses
| Status | Meaning |
|---|---|
open | Being built; nothing sent to the kitchen yet |
sent | At least one line fired to the kitchen |
paid | Settled; posted, or being posted, to Cloudbeds |
cancelled | Cancelled before payment |
split | Divided into new orders; see their parent_order_id |

