Skip to content
Log in
Reservations

Reservations

You create a reservation in two steps: hold the inventory while the guest checks out, then confirm the hold. Splitting it this way reserves the room the moment the guest commits, and finalizes the reservation only when you confirm it.

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, when you send a payment reference, records the payment. A hold you do not confirm expires and releases its inventory.


Hold inventory

POST /holds

Scope: 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, add-ons, and applicable taxes) onto a new folio, at the same price /rates quoted, including any revenue-optimization daily prices. The hold counts against availability until you confirm it or its 15-minute window passes.

Body fieldRequiredNotes
room_type_idyesMust belong to this property.
rate_plan_idyesAn active plan for the room type. Its visibility and offer rules are checked again.
check_inyesYYYY-MM-DD.
check_outyesYYYY-MM-DD, after check_in; at most 30 nights.
guest_idyesThe guest the hold is for.
adultsyesInteger from 1 to 20. The party must fit the room type's max_occupancy.
childrennoInteger from 0 to 20. Default 0.
child_agesnoArray of child ages (integers, 0 or more; up to 20). When present it is the child count and drives age-based extra-guest pricing.
add_onsnoArray of up to 10 guest-selected add-ons, each priced onto the folio at hold time so it is inside the total. See the fields below.
promo_codenoNeeded when the chosen rate plan is gated behind a promo code.

Each entry in add_ons names a guest-bookable service:

Add-on fieldRequiredNotes
service_idyesThe service being added. Each service may appear once.
modifier_valuesnoObject of { modifier_key: value } for the service's fields. Defaults to {}.
quantitynoUnits of the add-on, a whole number from 1 to 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
  }'

Returns 201:

{
  "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",
  "deposit_amount": "378.00",
  "balance_due_date": "2026-07-18",
  "status": "tentative"
}
FieldTypeNotes
hold_expires_atstringWhen the hold lapses if you have not confirmed it.
totalstringThe full price of the stay.
deposit_amountstringWhat the property's payment terms ask for when reserved. Frozen with the hold.
balance_due_datestring | nullWhen the rest is due, under the same terms.
ErrorWhen
409 no_availabilityThe room type is sold out for the range.
404 rate_plan_not_foundThe plan is inactive, its visibility rules exclude this guest, the stay falls outside its sale or stay window or its length-of-stay or day-of-week rules, or it needs a promo code you did not send. These all read the same, so a hidden plan is never revealed.
404 room_type_not_found / 404 guest_not_foundThe room type or guest does not exist in this property.
409 guest_mergedThe guest was merged into another profile. Hold for that guest instead.
400 party_too_largeThe party is larger than the room type's max_occupancy.
400 bed_config_removedThe body still sends bed_config. Bed configuration was removed from Veridien, so leave the field out.
400 exchange_rate_not_configuredThe plan's currency has no exchange rate set up.
404 service_not_found / 409 addon_unavailableAn add-on does not exist or can no longer be added.
400 duplicate_addon, missing_modifier, invalid_modifier_option, invalid_modifier_value, addon_currency_mismatchAn add-on was listed twice, a required field is missing, a value is not allowed, or its currency differs from the reservation's.

Confirm a hold

POST /holds/{id}/confirm

Scope: reservations:write · supports Idempotency-Key

Confirms the hold. Veridien checks availability again (leaving out the hold itself), assigns a physical room, marks the reservation and its stays confirmed, and records the payment you report. It then awards loyalty points on the room revenue, valued in the property's base currency, and sends the guest's confirmation email when the source is set to send it.

You may confirm without a payment. Veridien takes no payments online, so a reservation can be confirmed unpaid; the frozen deposit_amount and balance_due_date then say what is owed, and staff record the money when it arrives.

A payment reference is a claim, not proof

A payment_reference is your assertion that you captured the money. Veridien does not check that any money 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 reservation. Never reuse or change a payment id across reservations.
  • Every confirm with a reference is audit-logged as a payment assertion (which key asserted it, the reference, the amount).
  • The checks below reject obviously wrong input, but they cannot prove that money changed hands.
Body fieldRequiredNotes
payment_referencenoYour payment id, up to 200 characters. Leave it out to confirm unpaid. Confirmation is idempotent on this value.
payment_currencynoThe 3-letter currency you charged in. Rejected if it differs from the reservation currency.
payment_amountnoThe amount you captured, as a number. It must be at least the deposit and at most the folio total. When you leave it out, the deposit amount is recorded.
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": "example-payment-1001", "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",
  "deposit_amount": "378.00",
  "balance_due_date": "2026-07-18",
  "already_confirmed": false
}
ErrorWhen
404 reservation_not_foundNo reservation with this id in the property.
409 hold_expiredThe hold's 15-minute window passed before you confirmed. Create a new hold.
409 no_availabilityThe hold lost its inventory between hold and confirm.
409 no_room_to_assignNo physical room is free to assign for the stay.
409 not_confirmableThe reservation is not a tentative hold (for example, it was cancelled).
400 currency_mismatchpayment_currency differs from the reservation currency.
400 amount_below_depositpayment_amount is less than the deposit.
400 amount_above_totalpayment_amount is more than the folio total.
400 promo_code_exhausted / promo_code_guest_limitThe reservation's promo code ran out of uses, or this guest has used it as often as it allows.

Idempotent two ways

Confirming a reservation that is already confirmed, or replaying the same payment_reference, returns the existing result with "already_confirmed": true: no second payment and no second reservation. A unique index on the folio and reference keeps this safe under concurrent requests. Add an Idempotency-Key and confirmation is safe to retry.


List reservations

GET /reservations

Scope: reservations:read

Returns the property's reservations, earliest check-in first, each with its folio balance.

Query parameterNotes
guest_idOnly this guest's reservations.
statusOnly this status: tentative, confirmed, checked_in, checked_out, cancelled, or no_show. Any other value is ignored.
limitPage size. Default 25, maximum 100.
offsetRecords 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",
      "confirmation_code": "B7XKQ4M2",
      "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": [{ "currency": "USD", "charges": "1260.00", "payments": "1260.00", "balance": "0.00" }]
    }
  ]
}

confirmation_code is the code to show guests and staff. Address the reservation in requests by its id. See Conventions for paging through results.


Get a reservation

GET /reservations/{id}

Scope: reservations:read

Returns one reservation with its stays (one per room) and folio balance. accommodations is a deprecated copy of stays, kept until 1.0.0; read stays. An unknown id returns 404 reservation_not_found.

curl "$VRDN_BASE/reservations/7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27" -H "Authorization: Bearer $VRDN_KEY"
{
  "id": "7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27",
  "confirmation_code": "B7XKQ4M2",
  "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": "1260.00", "payments": "1260.00", "balance": "0.00" }],
  "stays": [
    {
      "id": "2b9e6f4d-8a3c-4e1b-9d5f-7a0c4e8b2d63",
      "room_id": "c3a7e1f9-5b2d-4e8c-a6f0-9d4b2e7c1a35",
      "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"
    }
  ]
}

Cancel a reservation

POST /reservations/{id}/cancel

Scope: reservations:write · supports Idempotency-Key

Cancels a tentative or confirmed reservation and frees its inventory. A reservation in any other status cannot be cancelled through the API (409 not_cancellable).

Nothing is refunded automatically. If the reservation was paid, the cancellation policy's fee is posted to the folio, which stays open, and refund_due_minor reports what is owed back. When no fee is kept, the folio and any invoice are voided and kept for audit. A promo-code use the reservation claimed is released.

Body fieldRequiredNotes
reasonnoUp to 500 characters. Stored as the cancellation reason. Defaults to "Cancelled via API".
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_due_minor": 0 }
FieldTypeNotes
refund_due_minorintegerWhat the cancellation policy says is owed back to the guest, in minor units (cents). 0 when the reservation was unpaid or the policy refunds nothing. This is an obligation, not a completed refund: Veridien does not move money, so your property returns it.