Skip to main content

Order Confirmed

This event will be sent after Stream successfully injects a DSP order into the POS.

API Reference

Customer Fields

Each order carries a customers array holding the customer details for the order. For a single-customer order — the canonical case — the array contains exactly one element.

The singular customer field is deprecated. It is still populated with the first customer for backwards compatibility, but new integrations should read customers instead.

FieldTypeDescription
namestringCustomer display name
phonestringCustomer phone number
masked_phone_codestring (optional)Phone masking access code, only provided when the platform uses phone masking
provider_loyalty_idstring (optional)Customer loyalty program identifier, when provided by the ordering platform

provider_loyalty_id lets loyalty platforms reconcile points and rewards against the ordering platform's own customer identity. It is only present when the ordering platform supplies a loyalty identifier on the order — orders without one simply omit the field.

{
"customers": [
{
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111",
"provider_loyalty_id": "user@example.com"
}
]
}

Item and Modifier IDs

Each item and modifier carries a stream_id — the Stream catalog ID for that object. It matches the stream_id exposed on the DSP menu, so integrators using both the DSP and Events products can reconcile order contents against their stored menu data instead of matching by name. Items or modifiers that share a name are always distinguishable by their stream_id.

The field is omitted in the rare case where an order line could not be matched to a Stream catalog object, so treat it as optional.

Modifiers

Each item carries a modifiers array. A modifier may itself contain a nested modifiers array when the selected option has its own selected modifiers (for example, a "Half & Half" topping that further splits into per-half choices). Nesting can be several levels deep.

The nested modifiers field is only present when a modifier has its own selected modifiers — leaf modifiers omit it entirely. Consumers that do not need nested modifiers can safely ignore the field, so existing integrations are unaffected.

{
"stream_id": "STREAM_ITEM_1",
"name": "Build Your Own Pizza",
"quantity": 1,
"price": 1500,
"modifiers": [
{
"stream_id": "STREAM_MODIFIER_1",
"name": "Large",
"quantity": 1,
"price": 300
},
{
"stream_id": "STREAM_MODIFIER_2",
"name": "Half & Half",
"quantity": 1,
"price": 0,
"modifiers": [
{
"stream_id": "STREAM_MODIFIER_3",
"name": "Left: Pepperoni",
"quantity": 1,
"price": 200,
"modifiers": [
{
"stream_id": "STREAM_MODIFIER_4",
"name": "Extra Pepperoni",
"quantity": 2,
"price": 100
}
]
},
{
"stream_id": "STREAM_MODIFIER_5",
"name": "Right: Mushroom",
"quantity": 1,
"price": 150
}
]
}
]
}

Unpaid Orders

Most orders arrive already paid through the ordering platform. When unpaid is true, payment has not been collected and is due at fulfillment — drive_thru is the common case.

For unpaid orders, cash_amount_due carries the amount to collect at fulfillment, in the lowest denomination (e.g. cents). It may be less than total when the ordering platform funds a promotion that reduces the cash owed without appearing as a separate discount line, so collect cash_amount_due rather than deriving the amount from total.

Both fields are optional and omitted on ordinary prepaid orders.

Delivery Order

{
"type": "order.confirmed",
"location_id": "STREAM_LOCATION_1",
"reference_id": "PROVIDER_LOCATION_1",
"order": {
"id": "STREAM_ORDER_1234",
"source": "uber",
"dsp_order_id": "123456789",
"dsp_order_number": "1234",
"pos_order_id": "POS_ORDER_5678",
"customers": [
{
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111"
}
],
"customer": {
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111"
},
"currency": "usd",
"delivery_fee": 350,
"driver_tip": 100,
"estimated_fulfillment_time": 1706124214619,
"fulfillment_type": "delivery",
"items": [
{
"stream_id": "STREAM_ITEM_1",
"name": "Cheeseburger",
"quantity": 1,
"price": 1000,
"modifiers": [
{
"stream_id": "STREAM_MODIFIER_1",
"name": "Extra Patty",
"quantity": 1,
"price": 500
}
],
"special_instructions": "No bun please"
}
],
"special_instructions": "Extra napkins please",
"subtotal": 1500,
"tax": 150,
"total": 2100
}
}

On self-delivery orders (fulfillment_type: merchant_managed_delivery), the customer's delivery_address and fulfillment_instructions are personal data that ordering platforms only release with the customer's explicit consent.

Without that consent, the order omits delivery_address and fulfillment_instructions entirely — the fields are simply absent, not empty or null. Every other field is unaffected, and the order is still a valid merchant_managed_delivery order.

Because of this, your integration must not assume a self-delivery order carries an address. Treat both fields as optional and handle the missing case explicitly — for example, by falling back to contacting the customer via phone (with the masked_phone_code when phone masking is in use) to arrange delivery.

The two examples below show the same self-delivery order without and with the customer's consent for the address.

{
"type": "order.confirmed",
"location_id": "STREAM_LOCATION_1",
"reference_id": "PROVIDER_LOCATION_1",
"order": {
"id": "STREAM_ORDER_1234",
"source": "uber",
"dsp_order_id": "123456789",
"dsp_order_number": "1234",
"pos_order_id": "POS_ORDER_5678",
"customers": [
{
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111"
}
],
"customer": {
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111"
},
"currency": "usd",
"delivery_fee": 350,
"driver_tip": 100,
"estimated_fulfillment_time": 1706124214619,
"fulfillment_type": "merchant_managed_delivery",
"items": [
{
"stream_id": "STREAM_ITEM_1",
"name": "Cheeseburger",
"quantity": 1,
"price": 1000,
"modifiers": [
{
"stream_id": "STREAM_MODIFIER_1",
"name": "Extra Patty",
"quantity": 1,
"price": 500
}
],
"special_instructions": "No bun please"
}
],
"special_instructions": "Extra napkins please",
"subtotal": 1500,
"tax": 150,
"total": 2100
}
}
{
"type": "order.confirmed",
"location_id": "STREAM_LOCATION_1",
"reference_id": "PROVIDER_LOCATION_1",
"order": {
"id": "STREAM_ORDER_1234",
"source": "uber",
"dsp_order_id": "123456789",
"dsp_order_number": "1234",
"pos_order_id": "POS_ORDER_5678",
"customers": [
{
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111"
}
],
"customer": {
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111"
},
"currency": "usd",
"delivery_address": {
"address_line_1": "123 test lane",
"address_line_2": "apt 11",
"city": "Los Angeles",
"state": "CA",
"postal_code": "90010",
"country": "USA",
"lat": 1000,
"long": 1000
},
"delivery_fee": 350,
"driver_tip": 100,
"estimated_fulfillment_time": 1706124214619,
"fulfillment_type": "merchant_managed_delivery",
"fulfillment_instructions": "Gate code 1234",
"items": [
{
"stream_id": "STREAM_ITEM_1",
"name": "Cheeseburger",
"quantity": 1,
"price": 1000,
"modifiers": [
{
"stream_id": "STREAM_MODIFIER_1",
"name": "Extra Patty",
"quantity": 1,
"price": 500
}
],
"special_instructions": "No bun please"
}
],
"special_instructions": "Extra napkins please",
"subtotal": 1500,
"tax": 150,
"total": 2100
}
}

Drive thru Order

{
"type": "order.confirmed",
"location_id": "STREAM_LOCATION_1",
"reference_id": "PROVIDER_LOCATION_1",
"order": {
"id": "STREAM_ORDER_1234",
"source": "flipdish",
"dsp_order_id": "123456789",
"dsp_order_number": "1234",
"pos_order_id": "POS_ORDER_5678",
"customers": [
{
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111"
}
],
"customer": {
"name": "test c.",
"phone": "+1111111111",
"masked_phone_code": "111"
},
"currency": "usd",
"estimated_fulfillment_time": 1706124214619,
"fulfillment_type": "drive_thru",
"items": [
{
"stream_id": "STREAM_ITEM_1",
"name": "Cheeseburger",
"quantity": 1,
"price": 1000,
"modifiers": [
{
"stream_id": "STREAM_MODIFIER_1",
"name": "Extra Patty",
"quantity": 1,
"price": 500
}
],
"special_instructions": "No bun please"
}
],
"special_instructions": "Extra napkins please",
"subtotal": 1500,
"tax": 150,
"total": 1650,
"unpaid": true,
"cash_amount_due": 1650
}
}