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.
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. |
child_ages | no | Array of child ages (integers ≥ 0). When present it is the authoritative child count and drives age-bracket extra-guest pricing. |
bed_config | no | The guest-chosen bed setup label; must be one the room type offers. Recorded on the reservation for housekeeping. |
add_ons | no | Array of guest-selected add-ons (up to 10), each priced onto the folio at hold time so they are inside the charged total. See the fields below. |
promo_code | no | Required if the chosen rate plan is promo-gated. |
Each entry in add_ons references a guest-bookable service:
| Add-on field | Required | Notes |
|---|---|---|
service_id | yes | The service being added. |
modifier_values | no | Object of { modifier_key: value } for the service's data-capture fields. Defaults to {}. |
quantity | no | Units of the add-on (integer 1–99). Defaults to 1. |
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": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
"rate_plan_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02",
"check_in": "2026-08-01",
"check_out": "2026-08-04",
"guest_id": "3f8a2c1b-9d4e-4c6a-8b7f-5e2d1a9c0b34",
"adults": 2
}'{
"reservation_id": "7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27",
"folio_id": "1a6c3e9f-4d2b-4e8a-b5c7-9f0e6d4a2c81",
"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. |
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/7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27/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": "7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27",
"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, with no second payment and 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.
GET /reservationsScope: reservations:read
Reservations for the property, ordered by check-in date, earliest 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, no_show. |
limit | Page size, default 25, max 100. |
offset | Records to skip. |
curl "$VRDN_BASE/reservations?guest_id=3f8a2c1b-9d4e-4c6a-8b7f-5e2d1a9c0b34&limit=10" -H "Authorization: Bearer $VRDN_KEY"{
"has_more": false,
"data": [
{
"id": "7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27",
"status": "confirmed",
"guest_id": "3f8a2c1b-9d4e-4c6a-8b7f-5e2d1a9c0b34",
"check_in_date": "2026-08-01",
"check_out_date": "2026-08-04",
"room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
"room_type_name": "Deluxe Ocean Villa",
"nightly_rate": "420.00",
"currency": "USD",
"folio_balance": "0.00",
"balances": []
}
]
}See Conventions for paging through results.
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/7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27" -H "Authorization: Bearer $VRDN_KEY"{
"id": "7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27",
"status": "confirmed",
"guest_id": "3f8a2c1b-9d4e-4c6a-8b7f-5e2d1a9c0b34",
"check_in_date": "2026-08-01",
"check_out_date": "2026-08-04",
"room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
"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": "1a6c3e9f-4d2b-4e8a-b5c7-9f0e6d4a2c81",
"folio_balance": "0.00",
"balances": [{ "currency": "USD", "charges": "1310.40", "payments": "1310.40", "balance": "0.00" }],
"accommodations": [
{
"id": "2b9e6f4d-8a3c-4e1b-9d5f-7a0c4e8b2d63",
"room_id": null,
"room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
"check_in_date": "2026-08-01",
"check_out_date": "2026-08-04",
"status": "confirmed",
"nightly_rate": "420.00"
}
]
}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). The folio and any invoices are voided (kept for audit), and if the reservation was paid, a policy-based refund is issued before the inventory is released.
| Body field | Required | Notes |
|---|---|---|
reason | no | Stored as the cancellation reason. |
curl -X POST "$VRDN_BASE/reservations/7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27/cancel" \
-H "Authorization: Bearer $VRDN_KEY" \
-H "Content-Type: application/json" \
-d '{ "reason": "Guest changed plans" }'{ "reservation_id": "7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27", "status": "cancelled", "refund_minor": 0, "refund_provider": null }| Field | Type | Notes |
|---|---|---|
refund_minor | integer | Amount refunded, in minor units (cents). 0 when the reservation was unpaid or the policy refunds nothing. |
refund_provider | string | null | The provider that processed the refund, or null when no refund was issued. |
- Folios: read the bill and post charges.
- Guests & Loyalty: the guest a reservation belongs to.