Skip to content

Checkout & booking

Five UCP checkout tools are registered when the storefront takes instant bookings (the profile advertises dev.ucp.shopping.checkout):

ToolDoes
create_checkoutPrice a stay into a session: checkout.line_items + optional checkout.buyer.
get_checkoutFetch current session state by id.
update_checkoutReplace line_items and/or buyer (per-key PUT semantics); reprices.
complete_checkoutPlace the held booking. Requires meta["idempotency-key"].
cancel_checkoutCancel an open session. Requires meta["idempotency-key"].
json
{
  "meta": { "ucp-agent": { "profile": "…" } },
  "checkout": {
    "line_items": [{ "item": { "id": "stay:42:2026-08-03:2026-08-10:2:0" }, "quantity": 1 }],
    "buyer": { "first_name": "Ada", "last_name": "Lovelace", "email": "[email protected]", "phone_number": "+359888123456" }
  }
}

The session

Responses are the full UCP checkout resource: id (pass it to the other tools), status, currency, line_items, buyer, totals, messages, links (the storefront's policy pages), and — once completed — order and continue_url.

Statuses: incompleteready_for_completecomplete_in_progresscompleted, or canceled (explicit cancel, or 24 h of inactivity). requires_escalation is reserved and unused in v1.

Buyer requirements: non-empty first_name, last_name, and a valid email. phone_number is optional. Until those are present the session stays incomplete with a missing message at $.buyer.

Totals

totals is the itemized price in minor units with signed amounts: subtotal (accommodation), optional negative discount, one fee entry per mandatory fee, one tax entry per added tax (taxes already included in the nightly rate are not added again), and total. The non-total entries always sum exactly to total — render them as given, don't recompute.

Messages

Problems come back as structured messages, not tool errors:

codeTypical causeseverity
out_of_stockDates no longer available (also on completion races)recoverable — try other dates
item_unavailableUnknown/inactive item idrecoverable
capacity_exceededParty larger than max_guests × quantityrequires_buyer_input
missingBuyer fields absent/invalidrequires_buyer_input
min_stay, max_stay, closed_to_arrival, closed_to_departure, stop_sellStay restrictionsrecoverable
invalidMixed dates across lines; mutating a finished sessionrecoverable / unrecoverable

Tool-level errors are reserved for transport problems: unknown checkout id, missing idempotency-key, malformed arguments, or calling a checkout tool on a storefront that doesn't register them.

Completing

complete_checkout re-validates availability under lock, creates the booking, and returns the session with:

json
{
  "status": "completed",
  "order": {
    "id": "BKG-7F3A2C",
    "checkout_id": "9c2e…",
    "permalink_url": "https://stay.example.com/pay/status/eyJpdiI6…"
  },
  "continue_url": "https://stay.example.com/pay/status/eyJpdiI6…",
  "messages": [{ "type": "info", "code": "payment_required", "content": "Booking is held. Payment must be completed at the permalink to confirm the stay." }]
}

Hand the guest the permalink_url. The booking is held but unpaid; the guest pays there through the host's payment providers, and unpaid holds are released automatically (~2 h). Retrying complete_checkout on a completed session returns the same order — bookings are never duplicated. If the inventory was taken between pricing and completion, the session drops back to incomplete with an out_of_stock message and no booking is created.

© Stayblox — Developer Platform