preview_order
Previews an order before creation: validates the shop / address / items, applies coupons, and returns the final price breakdown along with thepreview_id and confirmation_token used to place the order.
Order flow:
search_shops → shop_id + cart_id (carries delivery coordinates) → get_shop_menu to pick items → quote_cart to price the cart and get quote_id → select_address to get address_id → preview_order → preview_id + confirmation_token → create_order. A preview must be based on an existing cart_id.Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
consent_grant_id | string | Yes | — | User consent grant ID (cg_ prefix, from verify_user_bind), identifying the consenting user |
shop_id | string | Yes | — | Shop ID (from search_shops) |
cart_id | string | Yes | — | Cart context ID (from search_shops; carries shop & delivery coordinates, so no lat/lng is needed here) |
quote_id | string | null | No | null | Quote ID (from quote_cart); validates the quote context when provided |
address_id | string | Yes | — | Gateway address ID (string); use the address_id returned by select_address as-is |
items | array | Yes | — | Item list (see below) |
items[].item_id | string | Yes | — | Item ID (from get_shop_menu) |
items[].sku_id | string | No | null | SKU ID |
items[].quantity | integer | Yes | — | Quantity, ≥ 1 |
items[].ingredient_option_ids | string[] | No | [] | Ingredient / option IDs (from the menu item’s options; for a non-default SKU use that SKU’s sku_options[].ingredient_options) |
items[].ingredient_quantities | array | No | [] | Portion counts for specific options, e.g. “Espresso shots x3”, shaped [{option_id, quantity}]; only options whose max_quantity exceeds 1 accept it, and exceeding it fails the order. Listing an option here counts as selecting it, so it need not repeat in ingredient_option_ids; omit and each option uses its own default_quantity (the merchant-recommended count) |
items[].remark | string | No | "" | Per-item note |
coupon_ids | string[] | null | No | null | Coupon selection, three states below |
order_remark | string | No | "" | Order note (for the rider) |
lang | string | No | — | Language for this response. One of zh / en / ja / ko / ru / ms / es; defaults to the language set at binding time (Chinese if unset) |
include_chinese | boolean | No | false | When true, the response also includes the Chinese original (<key>_zh) — see Bilingual responses |
coupon_ids three states:
- Omit the parameter → the gateway auto-selects the best coupon
- Pass
[](empty array) → explicitly use no coupon - Pass
["<coupon_id>", ...]→ use the specified coupons (IDs come from a previous preview’savailable_coupons[].coupon_id)
Returns
All amount fields are in cents (integer), not yuan. e.g.
payable_price: 1500 means ¥15.00.| Field | Type | Description |
|---|---|---|
preview_id | string | Preview ID (prv_), passed to create_order; valid for ~10 minutes |
confirmation_token | string | Confirmation token (cf_), passed with preview_id to create_order |
shop.name | string | Shop name |
shop.logo_url | string | null | Shop logo URL, same source as shop.logo_url from get_shop_menu; null if absent |
shop.lat | number | null | Shop latitude, same source and value as shop.lat from get_shop_menu; same coordinate system as the request lat / lng (AMap GCJ-02); null when the menu step captured no coordinates |
shop.lng | number | null | Shop longitude, otherwise same as shop.lat |
address.display_name | string | Address display name |
address.address_detail | string | Door number / details |
address.city | string | City name (e.g. “武汉”). Older addresses may return an empty string, meaning unknown — not a different city. |
items[].item_id | string | Item ID |
items[].name | string | Item name |
items[].quantity | integer | Quantity |
items[].price | integer | Item price (cents) |
items[].min_purchase | integer | null | Minimum purchase echo; same as items[].min_purchase in quote_cart |
items[].available_quantity | integer | null | Remaining stock echo; same as items[].available_quantity in quote_cart |
items[].image_url | string | null | Item image URL; null if none |
items[].specs | array | Selected specs for this item, [{name, value}] (e.g. {"name":"Size","value":"Large"}); [] if none |
items[].selected_ingredients | array | Selected ingredients/options, [{group_name, name, price_delta, quantity}]; group_name may be null, price_delta is the surcharge for one portion (cents), quantity is the effective portion count (defaults to that option’s default_quantity). The line’s surcharge is NOT price_delta × quantity — see price_steps on get_item_options for the tiered price; [] if none |
price.goods_price | integer | Goods subtotal (cents) |
price.delivery_fee | integer | Delivery fee (cents) |
price.packing_fee | integer | Packing fee (cents) |
price.original_price | integer | Pre-discount total (cents) = payable + discount; satisfies original_price − discount = payable_price |
price.discount | integer | Discount amount (cents) |
price.payable_price | integer | Payable amount (cents) |
delivery.estimated_time_text | string | null | Estimated delivery text |
delivery.delivery_type | string | null | Delivery type (currently null) |
payment.requires_payment | boolean | Whether payment is required |
payment.available_methods | string[] | Available payment methods |
warnings | array | Preview warnings (e.g. item changes) |
available_coupons | array | Available coupons; coupon_id can be passed back via coupon_ids |
available_coupons[].amount | integer | Coupon value (cents) |
available_coupons[].threshold | integer | Usage threshold (cents) |
available_coupons[].available | boolean | Whether usable |
available_coupons[].unavailable_reason | string | null | Reason if unusable |
selected_coupons | array | Coupons applied this time (with coupon_id / name / amount) |
shop_activities | object | Shop-level activities (store discount / first-visit discount / spend-and-return red packet), auto-applied by the upstream server; not in available_coupons and outside the coupon-selection flow. When absent, total_discount is 0 and activities is [] |
shop_activities.total_discount | number | Total this-order instant discount from shop activities (in yuan, not cents); sums only type=discount activities |
shop_activities.activities[].name | string | Activity name, e.g. “店铺满70减3”, “首次光顾立减” |
shop_activities.activities[].type | string | discount = this-order instant discount (applied to this order, counted in total_discount); return = spend-and-return red packet (usable on the NEXT order, not this one) |
shop_activities.activities[].amount | number | null | This-order discount amount (in yuan, not cents); the discount value when type=discount, null when type=return |
shop_activities.activities[].desc | string | Display text, e.g. ”-¥3”, “实付0元返2元店铺专享红包” |
shop_activities.activities[].tag | string | null | Activity badge text, e.g. “减” / “新” / “返”; null if none |
shop_activities.total_discount / activities[].amount are in yuan (float, e.g. 3.0) — the only exception to this response’s “all amounts in cents” rule. A type=discount activity is normally already reflected in price.payable_price; total_discount is display-only, do not subtract it from the payable amount again.shop_activities shape (a shop with activities):
{
"total_discount": 4.0,
"activities": [
{"name": "店铺满70减3", "type": "discount", "amount": 3.0, "desc": "-¥3", "tag": "减"},
{"name": "满返红包", "type": "return", "amount": null, "desc": "实付0元返2元店铺专享红包", "tag": "返"}
]
}
Error Codes
| code | Description |
|---|---|
CONSENT_GRANT_REQUIRED | Missing consent grant (no consent_grant_id) |
CONSENT_GRANT_INVALID | Consent grant is invalid |
CONSENT_GRANT_EXPIRED | Consent grant has expired; re-authorization required |
CAP_NOT_BOUND | The delivery capability is not enabled for this agent |
CONSENT_GRANT_WRONG_CAP | Consent grant belongs to a different capability / provider |
PUBLIC_REFERENCE_INVALID | cart_id / quote_id invalid or expired, shop_id and cart_id mismatch, or address_id invalid |
MISSING_REQUIRED_SELECTION | The cart hasn’t satisfied a store-level required item group (e.g. a malatang shop’s “Required Soup”). Add an item from required_groups[].candidate_item_ids (in the get_shop_menu response) and retry; message names the missing group |
BELOW_MIN_PURCHASE | An item’s quantity is below its minimum purchase (see items[].min_purchase in the menu / get_item_options). Raise that item’s quantity per the message details and retry |
ELEME_ERROR | Upstream preview API error; retry later |
Example Call
{
"name": "preview_order",
"arguments": {
"consent_grant_id": "cg_your_consent_grant",
"shop_id": "<from search_shops>",
"cart_id": "<from search_shops>",
"address_id": "<from select_address>",
"items": [
{"item_id": "670685166551", "sku_id": "5014584502270", "quantity": 1}
]
}
}

