Scheduled Orders
Scheduled orders allow customers to place orders ahead of time for future fulfillment — including ordering while the store is closed for a pickup time later that day.
There are two ways to handle them: your platform holds the order and sends it to us when preparation should begin, or you send us the order right away and we hold it. This page covers both, what we validate and when, and which events you receive.
Order Fields for Scheduled Orders
When working with scheduled orders, these fields in the NewOrder object are particularly important:
status— set toscheduledto have Stream hold the order until preparation time. This is the field that queues the order.is_future_order— set totruewhen the order is not to be prepared ASAP. This flags the order as a future order for the merchant and their POS; on its own it does not delay the order.estimated_ready_at_ms— the time the order should be ready for pickup/delivery, in epoch milliseconds. If omitted or invalid, it defaults to 30 minutes from the time of the order.
status: scheduled is what holds the order. Sending is_future_order: true and estimated_ready_at_ms without status: scheduled does not queue the order — we validate and inject it into the merchant's POS immediately. If the store is closed or an item is unavailable at the moment you send the order, it fails right away with a location.order.fail event and a restaurant_not_accepting_orders failure reason, even though the requested pickup time is hours away.
If you are accepting orders while the store is closed (ordering ahead for the next open window), you must send status: scheduled.
3 Approaches to Scheduled Orders
1. DSP Managed Timing
Your platform handles all the timing logic internally and only sends us the order when it should begin preparation.
How it works:
- Customer places a scheduled order on your platform.
- Your platform calculates prep time and holds the order internally.
- When it's time to start preparation, your platform sends the order via webhook.note
When sending the order webhook,
is_future_orderwould befalse. - We immediately confirm the order and begin preparation.
Because the order reaches us only when it should be prepared, the store must be open and the items available at that moment — the same conditions as an ASAP order.
2. Stream Managed Timing
You send us the complete order as soon as the customer places it, and we hold it until preparation time.
How it works:
- Customer places a scheduled order on your platform.
- Your platform sends us the complete order with
status: scheduled,is_future_order: trueandestimated_ready_at_ms. - We hold the order and internally manage the delay until the appropriate preparation time.
- At that time we validate the order and submit it to the merchant's POS, then notify you of the outcome.
This is the approach to use for after-hours order ahead — the store does not need to be open when you send us the order.
3. Immediate Injection with a Future Fulfillment Time
You send us the order as soon as the customer places it and we submit it to the merchant's POS right away, marked as a future order.
How it works:
- Customer places a scheduled order on your platform.
- Your platform sends us the complete order with
is_future_order: trueandestimated_ready_at_ms, and withoutstatus: scheduled. - We validate the order and submit it to the POS immediately, carrying the requested fulfillment time.
- The POS holds the order until its promised time, where the POS supports doing so.
Because there is no hold on our side, the store must be open and the items available at the moment you send the order. Only use this approach for orders placed during the merchant's open hours — for anything else, use approach 2.
When the Order Reaches the POS
For a Stream-managed scheduled order, the order is not sent to the merchant's POS the moment we receive it — and the merchant's receipt does not print until it is. When we submit it is a merchant setting on their location, not something the order payload controls. Merchants choose from:
- Fire at prep time (default) — we submit the order ahead of
estimated_ready_at_msby the location's current prep time, so it reaches the kitchen when preparation should start. Prep time is dynamic: it reflects the merchant's prep-time rules and whether the location is in busy mode, so the exact submission time is not fixed when you send the order. - Fire 24 hours in advance — we submit the order a day ahead of the requested time, for merchants who want advance visibility of tomorrow's orders.
- Fire immediately — we submit the order to the POS as soon as we receive it, for merchants who prefer their POS to hold the order.
Merchants configure this per location in the Stream dashboard — see Setting Scheduled and Future Order Preferences. Some POS systems also require setup on their side before scheduled orders can be received.
Whenever we submit the order, we pass the requested fulfillment time through to the POS where the POS supports it, so the order is identified as a future order with its promised time rather than as an order to make now.
Because this varies by merchant and by POS, do not assume a fixed relationship between when you send us a scheduled order and when the merchant receives it. Drive your customer-facing messaging off estimated_ready_at_ms and the events you receive, not off an assumed submission time.
Events for Scheduled Orders
Held orders do not generate an event when we receive them. The first event you receive for a Stream-managed scheduled order is the outcome of POS submission, which may be hours after you sent us the order:
| When | Event | Meaning |
|---|---|---|
| You send the order | (no event) | The order is accepted into the queue and held. |
| At POS submission time | location.order.accept | The order passed validation and was injected into the merchant's POS. |
| At POS submission time | location.order.fail | The order could not be injected. See the failure_reason. |
| After acceptance | location.order.notify_status_change | Normal status progression (e.g. ready for pickup). |
| Any time before fulfillment | location.order.cancel | The order was canceled. A held order can be canceled before it reaches the POS. |
If your platform needs to confirm to the customer that the order was received, treat the successful HTTP response to your new_order request as that acknowledgement — not location.order.accept, which may not arrive until much later.
Validation Happens at Submission Time, Not When You Send the Order
For a held order, we validate against the state of the store and menu at the moment we submit to the POS — not the state when the customer placed the order. That means a scheduled order that was perfectly valid when placed can still fail later if conditions have changed:
- an item or modifier has been marked unavailable (86'd) in the POS,
- an item has been removed from or changed in the merchant's menu,
- the store is closed, paused, or not accepting orders at submission time.
These failures reach you as a location.order.fail event with the same failure reasons as an ASAP order — items_unavailable, pos_missing_items, restaurant_not_accepting_orders, and so on.
Build for this: your platform should be able to handle a failure on an order the customer placed hours earlier, and notify the customer or refund accordingly. This is the main operational difference between ASAP and scheduled orders.
Adjusting Scheduled Orders
While a scheduled order is held by Stream (before it is sent to the merchant's POS for preparation), you can update it by sending an order_adjustment event with the full adjusted order. The held order is replaced with the adjusted details, and the adjusted order is what gets submitted to the POS at preparation time.
- The scheduled preparation time is retained unless the adjustment changes
estimated_ready_at_ms. - Re-state
status: scheduled,is_future_order: trueandestimated_ready_at_mson the adjusted order — if omitted, the order is treated as an ASAP order and is prepared immediately. - If the adjustment arrives after the order has already been sent to the POS, it is not applied automatically; the merchant is notified so they can update the order on their POS.
The same boundary applies to cancellations: a held order can be canceled cleanly before submission, while a cancellation after submission is handled with the merchant as it would be for any accepted order.