Launching soon.Get early access
Veridien Docs
API Reference

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 /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 + applicable taxes) onto a new folio. The hold counts against availability until it is confirmed or its 15-minute window lapses.

Body fieldRequiredNotes
room_type_idyesMust belong to this property.
rate_plan_idyesActive plan for the room type; its visibility rules are re-checked.
check_inyesYYYY-MM-DD.
check_outyesYYYY-MM-DD, after check_in; max 30 nights.
guest_idyesThe guest the hold is for.
adultsyesInteger 1–20; party must fit max_occupancy.
childrennoInteger 0–20, default 0.
child_agesnoArray of child ages (integers ≥ 0). When present it is the authoritative child count and drives age-bracket extra-guest pricing.
bed_confignoThe guest-chosen bed setup label; must be one the room type offers. Recorded on the reservation for housekeeping.
add_onsnoArray 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_codenoRequired if the chosen rate plan is promo-gated.

Each entry in add_ons references a guest-bookable service:

Add-on fieldRequiredNotes
service_idyesThe service being added.
modifier_valuesnoObject of { modifier_key: value } for the service's data-capture fields. Defaults to {}.
quantitynoUnits 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"
}
ErrorWhen
409 no_availabilityThe room type is sold out for the range.
404 rate_plan_not_foundThe plan is inactive, or its visibility rules exclude this guest/context.
400 party_too_largeadults + children exceeds the room type's max_occupancy.

POST /holds/{id}/confirm

Scope: 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 fieldRequiredNotes
payment_referenceyesYour payment identifier: an unverified assertion you captured payment. Confirmation is idempotent on this value.
payment_currencynoOptional ISO-4217 currency you assert you charged. Rejected if it differs from the reservation currency.
payment_amountnoOptional 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
}
ErrorWhen
409 hold_expiredThe hold's 15-minute payment window lapsed before you confirmed. Create a fresh hold.
409 no_availabilityThe hold lost its inventory between hold and confirm.
409 not_confirmableThe reservation is not a confirmable tentative hold (e.g. already cancelled).
400 currency_mismatchpayment_currency differs from the reservation currency.
400 amount_mismatchpayment_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 /reservations

Scope: reservations:read

Reservations for the property, ordered by check-in date, earliest first, with each one's outstanding folio balance.

Query parameterNotes
guest_idFilter to one guest.
statusFilter by status: tentative, confirmed, checked_in, checked_out, cancelled, no_show.
limitPage size, default 25, max 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",
      "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}/cancel

Scope: 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 fieldRequiredNotes
reasonnoStored 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 }
FieldTypeNotes
refund_minorintegerAmount refunded, in minor units (cents). 0 when the reservation was unpaid or the policy refunds nothing.
refund_providerstring | nullThe provider that processed the refund, or null when no refund was issued.