Reservations
Three tools, one scope: reservation:write. A reservation is a 30-minute soft hold on a VIN, created from an open quote. It is not a binding purchase — a human closes the deal after hand-off.
- One active hold per VIN. A second create on a VIN that already has an unexpired active hold fails with
RESERVATION_CONFLICT. - 30-minute TTL.
expires_atis set at insert (now + 30 min). There is no background sweeper — stale active holds are lazy-expired the next time anyone reserves that VIN. - Per-agent daily budget. Default 5 reservations/day (raise on request). Creating charges the budget; the create is the only tool that consumes it.
- Same-day-release refund. Releasing within the same UTC day you created the hold refunds 1 slot to your daily budget.
create_reservation
Convert an open quote into a soft hold. Validates that the quote exists, is open and unexpired, is owned by you, and that the vehicle is still available. On success the quote flips to converted.
| Field | Type | Constraints | |
|---|---|---|---|
| quote_id | string | required | 10–64 chars — from request_quote |
| customer_ref | string | optional | ≤ 200 chars — opaque; your own handle, not PII |
// arguments
{ "quote_id": "qte_8f1c…", "customer_ref": "caredge-sess-91f3" }
// data
{ "reservation_token": "rsv_Qh7m…",
"vin": "4S4BTGUD8R3201234",
"reserved_price": 34187.0,
"created_at": "2026-05-27T18:05:02+00:00",
"expires_at": "2026-05-27T18:35:02+00:00",
"status": "active",
"terms": "30-minute soft hold. Not a binding purchase. A human closes the deal. …" }
Errors: QUOTE_NOT_FOUND, QUOTE_EXPIRED, QUOTE_STATE (already converted/closed), VEHICLE_UNAVAILABLE, RESERVATION_CONFLICT (VIN already held), RESERVATION_LIMIT (daily budget hit), NOT_AUTHORIZED (quote owned by another agent).
release_reservation
Release a hold you own. Idempotent — calling it on an already-released or expired
reservation returns status with already_closed: true instead of an error, so it is
always safe to call twice. Releasing within the same UTC day refunds 1 slot to your daily budget.
| Field | Type | Constraints | |
|---|---|---|---|
| reservation_token | string | required | 10–80 chars |
// arguments
{ "reservation_token": "rsv_Qh7m…" }
// data (first release)
{ "status": "released", "released_at": "2026-05-27T18:12:40+00:00", "vin": "4S4BTGUD8R3201234" }
// data (second, idempotent release)
{ "status": "released", "already_closed": true }
get_reservation_status
Look up the current state of a reservation you created. Same input shape as release.
| Field | Type | Constraints | |
|---|---|---|---|
| reservation_token | string | required | 10–80 chars |
// data
{ "reservation_token": "rsv_Qh7m…",
"vin": "4S4BTGUD8R3201234",
"reserved_price": 34187.0,
"created_at": "2026-05-27T18:05:02+00:00",
"expires_at": "2026-05-27T18:35:02+00:00",
"released_at": null,
"released_by": null,
"status": "active" }
Status values: active, released, expired, converted. released_by is agent for an agent-initiated release. Errors: RESERVATION_NOT_FOUND, NOT_AUTHORIZED (owned by another agent).
Response fields
Shared across create_reservation, release_reservation, and get_reservation_status. See Data formats for the timestamp / Money / opaque-token conventions.
| Field | Type | Description | |
|---|---|---|---|
| reservation_token | string | create / status | Opaque hold handle (10–80 chars). Use it for release_reservation, get_reservation_status, and initiate_deal_handoff. Do not parse. |
| vin | string | always | The held VIN. |
| reserved_price | number | create / status | Price locked at hold creation — the quote's quoted_price. Non-binding. |
| status | enum | always | active | released | expired | converted. |
| created_at | string | create / status | ISO-8601 UTC — when the hold was created. |
| expires_at | string | create / status | ISO-8601 UTC — created_at + 30 min. After this the hold lazy-expires. |
| released_at | string | null | status / release | ISO-8601 UTC when released; null while the hold is still active. |
| released_by | string | null | status | agent for an agent-initiated release; null while active or if it expired untouched. |
| already_closed | boolean | release | true on an idempotent re-release of an already released/expired hold (no error). Absent on the first release. |
| terms | string | create | Human-readable hold terms. |
Next step
While a reservation is active you have a 30-minute window to either release it or run initiate_deal_handoff to bring a human into the loop. Let the window lapse and the hold expires automatically.