validate_order, quote_order, and submit_order share one canonical order-intent shape; the by-id tools enforce ownership (an agent only touches orders it created).
validate_order
Run Phantom rule validation before quote or submit. REST equivalent:POST /api/agent/restaurants/:restaurantId/orders/validate.
Input — { "restaurant_id": "…", "order": <canonical order intent> }:
restaurant_idat the tool level and insideordermust match, or the call throws.order.agent_idis stamped with the authenticated agent; supplying a different one throws.fulfillment_addressis required for delivery; sendlatitude/longitudewhen the client’s address autocomplete has geometry (courier dispatch needs them).- Per-player naming: a line with
player_first_namemust carryquantity: 1— two players means two item lines.
ordering_disabled, channel_deactivated, location_paused, lead_time_too_short, lead_time_too_long, headcount_too_large, menu_version_stale, player_name_incomplete, player_name_requires_separate_item_line, item_not_found, item_unavailable, item_unavailable_at_time, mapping_needs_review, modifier_group_invalid, modifier_invalid, modifier_unavailable, nested_modifier_quantity_invalid, modifier_not_nested, required_modifier_missing, too_many_modifiers, modifier_quantity_exceeded, too_many_items, order_value_too_large, delivery_unavailable, order_validation_failed.
quote_order
Return pricing for a valid order. REST equivalent:POST /api/agent/restaurants/:restaurantId/orders/quote.
Input: same { restaurant_id, order } shape as validate_order.
Output:
deliveryFeeCents is the courier fee, already folded into totalCents; it is 0/absent on pickup or when no dispatch quote was available. serviceFeeCents is the agent’s consumer fee (a configured share of subtotal).
Idempotency replays are re-shaped to this current schema before being returned.
submit_order
Create the order in Phantom and enter the normal approval and provider-submission lifecycle. REST equivalent:POST /api/agent/restaurants/:restaurantId/orders/submit.
Input: same { restaurant_id, order } shape as validate_order.
Output:
submit_order never bypasses the restaurant’s approval rules — a needs_approval order awaits a human decision.
get_order_status
Phantom’s last known order state, latest provider order identifier, and the payment snapshot. REST equivalent:GET /api/agent/orders/:orderId/status.
Input: { "order_id": "order_123" }
Output:
payment is null when no payment record exists. get_order_status exposes Phantom’s order lifecycle, not raw provider-only state.
get_order_tracking
Full tracking snapshot: kitchen status + timestamped status-event timeline, and for delivery orders the courier leg. Input:{ "order_id": "order_123" }
Output:
delivery: null.
cancel_order
Cancel a pending order the calling agent placed. Only possible before the restaurant accepts it. Cancels the POS ticket and any courier, and best-effort reverses the payment (refunds captured charges with payout clawback, voids held authorizations). Input:{ "order_id": "order_123", "reason": "Customer changed plans" } (reason optional, ≤200 chars)
Output: { "ok": true, "status": "cancelled", "message": "…", "payment": "refunded" }
There is deliberately no restaurant-access check here: an agent must be able to cancel its own pending order even if the restaurant has since disabled ordering or its channel was deactivated.
update_order
Update a live order’s fulfillment details and re-point any courier (partial PATCH). Input:status echoes the order’s current lifecycle status, not an update result.
Menu items are not editable. The restaurant’s POS ticket cannot be amended post-submit — cancel and reorder instead. The editable surface is exactly what the courier’s partial update accepts: time, dropoff address, dropoff notes.