Taking orders

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

CallReturns
GET /pos/outlets/{outlet_id}The outlet, its settings and accepted payment methods
GET /pos/outlets/{outlet_id}/itemsIds of the catalog items this outlet sells
GET /pos/itemsThe property's catalog, with prices, to resolve those ids
GET /pos/outlets/{outlet_id}/menusHow the outlet groups items into menus
GET /pos/outlets/{outlet_id}/floor-planSections and tables, for restaurant outlets
GET /pos/settings/propertyCurrency 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_id seats the order. The table counts as occupied
    for as long as an open order references it.
  • Order types: dine_in, takeaway or room_service.
  • Guests: attach a reservation with reservation_id so the order can later be
    charged to the room.
  • Naming: alias names 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_id are 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:

ChangeCall
Discount one linePOST /pos/orders/{order_id}/items/{item_id}/discount
Charge a different pricePUT /pos/orders/{order_id}/items/{item_id}/price
Discount the whole orderPOST /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/transfer moves one or more open orders to
    another staff member. Either all of them move or none do.
  • Separate checks: POST /pos/orders/{order_id}/split divides 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 as split, and each new order points back
    to it in parent_order_id. Discounts, taxes and fees are divided so the checks
    add up exactly to the original. POST /pos/orders/{order_id}/unsplit reverses
    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}/cancel works on an open or sent
    order. A paid order is refunded instead.

Order statuses

StatusMeaning
openBeing built; nothing sent to the kitchen yet
sentAt least one line fired to the kitchen
paidSettled; posted, or being posted, to Cloudbeds
cancelledCancelled before payment
splitDivided into new orders; see their parent_order_id