Skip to main content

Order placement

An order placement integration bridges Future Ordering and an external Point of Sale (POS) system. When a guest completes checkout, the integration receives an event, retrieves the order data, sends it to the POS, and reports the outcome back to Future Ordering.

This article covers the full placement flow: subscribing to the trigger event, starting a placement session, reporting success or failure, and using mapping details to correlate Future Ordering entities with records in your POS.

For a conceptual overview of how orders progress through their lifecycle, see Order lifecycle.

Prerequisites

Handle an order ready to be placed in POS

When a guest finalizes their basket and completes checkout, Future Ordering closes the order and emits an order.ready_to_be_placed_in_pos event. Your integration reacts to this event, retrieves the full order, sends it to the POS, and reports back whether placement succeeded or failed.

Start a place-order session

Before sending the order to the POS, start a place-order session by calling:

POST /orders/{order-id}/place-order-session/start

Request body:

PropertyTypeRequiredDescription
placeOrderSessionIdstring (UUID)YesA UUID generated by your integration to identify this session.

The API returns the full order object, including all items, discounts, payments, mapping details and the time the guest requested the order to be ready. Use this data to construct the request to your POS.

Report a successful placement

When the POS confirms the order was placed, call:

POST /orders/{order-id}/pos/placed

Request body:

PropertyTypeRequiredDescription
orderNamestringYesA guest-facing display name for the order, such as a check number. Does not need to be unique. Example: "1234"
datePlacedstring (ISO 8601)YesThe datetime when the order was placed in the POS.
estimatedReadyTimestring (ISO 8601)YesThe estimated datetime when the food will be ready.
cancelableUntilstring (ISO 8601)NoThe datetime after which the guest can no longer cancel the order, if applicable.
orderRefsDictobjectNoA map of opaque unique references to tie to the order, such as the order's ID in the POS system. Keys and values are both strings. Example: { "my-pos": "abc123" }
receiptstringNoA full-text fiscal receipt string. Made available through the receipt service and included in the order confirmation email.
extensionsobjectNoOptional additional order-related data as a free-form key-value map.
note

orderRefsDict values must be unique across all orders for your tenant. If you attempt to set a reference that is already associated with another order, the API returns 409 Conflict.

Report a failed placement

When the POS cannot place the order, call:

POST /orders/{order-id}/pos/failed

Request body:

PropertyTypeRequiredDescription
codestringYesAn opaque error code identifying the failure reason. Example: "order.pos.item-out-of-stock"
messagestringYesA human-readable description of the error.
dataobjectNoOptional additional context for the error as a free-form object.

Whether placement succeeds or fails, the order transitions to finalized after Future Ordering processes the callback. See Order lifecycle for more information.

note

While codes are opaque strings, consider using a structured format such as {domain}.{subdomain}.{reason} to make codes easier to manage. Example: "order.pos.item-out-of-stock".

Placement session timeout

Each placement session has a timeout of 3 minutes. If your integration does not call /pos/placed or /pos/failed before the timeout elapses, Future Ordering marks the order as failed and transitions it to finalized.

A timeout-triggered failure is distinct from calling /pos/failed. If your integration receives an order.ready_to_be_placed_in_pos event but the order is already finalized, calling the endpoint /pos/placed or /pos/failed returns 405 Method Not Allowed — the order is no longer in a valid state for placement.

Mapping details

When your integration imports master data entities of stores and menu items, it can include a mappingDetails object with custom key-value pairs. This object is stored as-is and later included in the order data when an order is ready to be placed. This allows your integration to correlate Future Ordering entities with records in your POS when processing an order placement.

tip

mappingDetails is your contract between the master data integration and the order placement integration.

Discounts also contain mappingDetails that can be used to determine which POS discounts to apply, see Loyalty integrations for more information on how to setup discounts with mappingDetails. For charge items like delivery fees or service charges, mappingDetails are generated from configuration.

When you retrieve the full order object, mappingDetails is present on each entity that carries it:

  • Items (order.items[].mappingDetails) for menu items and charge items
  • Discounts (order.discounts[].mappingDetails) for applied discounts
  • Store (order.storeDetails.mappingDetails) for the store the order belongs to

For example, you might store a POS product ID in mappingDetails on each menu item so that your integration can look up the correct POS product when constructing the placement request:

{
"id": "e646d0c0-...",
"type": "menuItem",
"title": "150g Burger",
"quantity": 2,
"mappingDetails": {
"posProductId": "BURGER-150G"
}
}

The fields present in mappingDetails are defined when the entity is imported. See Importing menus and Importing stores for how to set these values.

tip

If you need per-item discount amounts when constructing the POS request, use the discounts[].amounts array. Each entry includes the discounted item ID, the specific unit ID, and the discount value. See Basket and items for a full explanation of the discount structure.