Reservations
A reservation is created in two steps: hold the inventory while the guest pays, then confirm the hold into a reservation. Splitting it this way means inventory is reserved the moment a guest commits, and the reservation is only finalized once payment succeeds.
The reservation lifecycle
POST /holds creates a tentative reservation that holds a room for 15 minutes. POST /holds/{id}/confirm turns it into a confirmed reservation and records the payment. Unconfirmed holds simply expire and release their inventory.
Hold inventory
POST /holdsScope: reservations:write · supports Idempotency-Key
Creates a tentative reservation that holds a room type on a rate plan for the date range. The stay is priced (room nights + applicable taxes) onto a new folio. The hold counts against availability until it is confirmed or its 15-minute window lapses.
| Body field | Required | Notes |
|---|---|---|
room_type_id | yes | Must belong to this property. |
rate_plan_id | yes | Active plan for the room type; its visibility rules are re-checked. |
check_in | yes | YYYY-MM-DD. |
check_out | yes | YYYY-MM-DD, after check_in; max 30 nights. |
guest_id | yes | The guest the hold is for. |
adults | yes | Integer 1–20; party must fit max_occupancy. |
children | no | Integer 0–20, default 0. |
promo_code | no | Required if the chosen rate plan is promo-gated. |
curl -X POST "$VRDN_BASE/holds" \
-H "Authorization: Bearer $VRDN_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1d2c9a-8b3e-4a17-9c2f-1e5b7d0a4c83" \
-d '{
"room_type_id": "rt_deluxe",
"rate_plan_id": "rp_flex",
"check_in": "2026-08-01",
"check_out": "2026-08-04",
"guest_id": "G7K2P9QX",
"adults": 2
}'{
"reservation_id": "RES4K9PA",
"folio_id": "fl_2b7c",
"hold_expires_at": "2026-06-19T08:45:00.000Z",
"total": "1260.00",
"currency": "USD",
"status": "tentative"
}| Error | When |
|---|---|
409 no_availability | The room type is sold out for the range. |
404 rate_plan_not_found | The plan is inactive, or its visibility rules exclude this guest/context. |
400 party_too_large | adults + children exceeds the room type's max_occupancy. |
Confirm a hold
POST /holds/{id}/confirmScope: reservations:write · supports Idempotency-Key
Take payment in your own flow, then confirm the hold with a payment_reference. Veridien re-checks availability (excluding the hold itself), marks the reservation and its accommodation confirmed, records the payment on the folio, and — for USD stays — awards loyalty points for the room revenue.
Method 1 is a trusted assertion model — read this
This endpoint is trust-based. Your payment_reference is an assertion that you captured the money — a claim, never proof. Veridien does not verify the payment moved: your hotel is the merchant of record, and you own the funds, disputes, and refunds. Because of that:
- Send a real, unique reference for each booking. Never reuse or mutate a payment id across reservations.
- Every confirm is audit-logged as a payment assertion (who asserted, the reference, the amount).
- Confirm-time guards reject obviously-wrong input, but they cannot validate that money actually changed hands.
If you want Veridien to verify payment itself (Stripe-hosted, platform-verified capture), that is the hosted booking engine (Method 2), not this API.
| Body field | Required | Notes |
|---|---|---|
payment_reference | yes | Your payment identifier — an unverified assertion you captured payment. Confirmation is idempotent on this value. |
payment_currency | no | Optional ISO-4217 currency you assert you charged. Rejected if it differs from the reservation currency. |
payment_amount | no | Optional amount you assert you captured. Rejected if it differs from the folio total. |
curl -X POST "$VRDN_BASE/holds/RES4K9PA/confirm" \
-H "Authorization: Bearer $VRDN_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 9a2e7c10-4b3f-4d28-8c1f-2e6b8d0a5d94" \
-d '{ "payment_reference": "pay_abc123", "payment_currency": "USD", "payment_amount": 1260.00 }'{
"reservation_id": "RES4K9PA",
"status": "confirmed",
"check_in_date": "2026-08-01",
"check_out_date": "2026-08-04",
"currency": "USD",
"folio_balance": "0.00",
"already_confirmed": false
}| Error | When |
|---|---|
409 hold_expired | The hold's 15-minute payment window lapsed before you confirmed. Create a fresh hold. |
409 no_availability | The hold lost its inventory between hold and confirm. |
409 not_confirmable | The reservation is not a confirmable tentative hold (e.g. already cancelled). |
400 currency_mismatch | payment_currency differs from the reservation currency. |
400 amount_mismatch | payment_amount differs from the folio total. |
Idempotent two ways
Re-confirming an already-confirmed reservation, or replaying the same payment_reference, returns the existing confirmed result with "already_confirmed": true — no second payment, no second reservation (a unique (folio, reference) index makes this race-safe). Combined with an Idempotency-Key, confirmation is safe to retry.
Loyalty is USD-denominated
Loyalty points are earned on USD room revenue. A non-USD stay does not silently earn zero — the skipped earn is recorded for reconciliation until multi-currency earning ships.
List reservations
GET /reservationsScope: reservations:read
Reservations for the property, newest stays first, with each one's outstanding folio balance.
| Query parameter | Notes |
|---|---|
guest_id | Filter to one guest. |
status | Filter by status: tentative, confirmed, checked_in, checked_out, cancelled. |
limit | Page size, default 25, max 100. |
offset | Records to skip. |
curl "$VRDN_BASE/reservations?guest_id=G7K2P9QX&limit=10" -H "Authorization: Bearer $VRDN_KEY"{
"has_more": false,
"data": [
{
"id": "RES4K9PA",
"status": "confirmed",
"guest_id": "G7K2P9QX",
"check_in_date": "2026-08-01",
"check_out_date": "2026-08-04",
"room_type_id": "rt_deluxe",
"room_type_name": "Deluxe Ocean Villa",
"nightly_rate": "420.00",
"currency": "USD",
"folio_balance": "0.00"
}
]
}See Conventions for paging through results.
Get a reservation
GET /reservations/{id}Scope: reservations:read
A single reservation with its accommodations (the per-room legs of the stay) and folio balance.
curl "$VRDN_BASE/reservations/RES4K9PA" -H "Authorization: Bearer $VRDN_KEY"{
"id": "RES4K9PA",
"status": "confirmed",
"guest_id": "G7K2P9QX",
"check_in_date": "2026-08-01",
"check_out_date": "2026-08-04",
"room_type_id": "rt_deluxe",
"room_type_name": "Deluxe Ocean Villa",
"nightly_rate": "420.00",
"currency": "USD",
"adults": 2,
"children": 0,
"number_of_guests": 2,
"booking_source": "direct_web",
"special_notes": null,
"folio_id": "fl_2b7c",
"folio_balance": "0.00",
"accommodations": [
{
"id": "ACC2M5QT",
"room_id": null,
"room_type_id": "rt_deluxe",
"check_in_date": "2026-08-01",
"check_out_date": "2026-08-04",
"status": "confirmed",
"nightly_rate": "420.00"
}
]
}Cancel a reservation
POST /reservations/{id}/cancelScope: reservations:write
Cancels a tentative or confirmed reservation and frees its inventory. Reservations that are already checked in, checked out, or cancelled cannot be cancelled through the API (409 not_cancellable).
| Body field | Required | Notes |
|---|---|---|
reason | no | Stored as the cancellation reason. |
curl -X POST "$VRDN_BASE/reservations/RES4K9PA/cancel" \
-H "Authorization: Bearer $VRDN_KEY" \
-H "Content-Type: application/json" \
-d '{ "reason": "Guest changed plans" }'{ "reservation_id": "RES4K9PA", "status": "cancelled" }Related pages
- Folios — read the bill and post charges.
- Guests & Loyalty — the guest a reservation belongs to.