Launching soon.Get early access
Veridien Docs
API Reference

Rate Management

The catalog and offer endpoints are read-only. These endpoints let an integration manage the rate stack: create rate plans, layer seasonal pricing, bundle inclusions and credits, and run promotions with codes. They are how a hotel drives its Veridien pricing from its own site or back office.

Every endpoint here requires the rates:write scope, except the management reads (GET), which require rates:read.

A promotion is a rate plan

A promotion is a rate plan with kind: "promotion" and a derivation from a base plan. There is no separate promotion endpoint: you create and edit one through the same /rate-plans endpoints, setting kind, derived_from_id, derivation_type, and derivation_value.

Idempotency

Every write here is a mutating request. Send an Idempotency-Key header to make retries safe, as described in Conventions.


POST /rate-plans
FieldRequiredNotes
room_type_idyesThe room type this plan prices.
nameyesInternal name (1 to 100 characters).
base_priceyesNightly price as a decimal string, for example "120.00".
currencynoMust be the property's base currency or a configured currency. Defaults to base.
public_namenoGuest-facing name.
descriptionnoGuest-facing blurb.
image_urlnoAbsolute URL.
extra_guest_chargenoPer-night charge per guest above base occupancy. Defaults to "0.00".
single_guest_discountnoDefaults to "0.00".
single_guest_discount_typenofixed or percent. Defaults to fixed.
min_los / max_losnoLength-of-stay bounds in nights.
booking_window_start / _endnoWhen the plan may be booked (YYYY-MM-DD).
stay_window_start / _endnoWhen the plan may be stayed.
active_for_booking_enginenoDefaults to false.
active_for_channelsnoDefaults to false.
kindnostandard (default) or promotion.
derived_from_idnoFor a promotion: the base plan it derives from.
derivation_typenopercent, fixed, or perPerson. Required with derived_from_id.
derivation_valuenoSigned decimal string. Negative is a discount, for example "-20.00". Required with derived_from_id.
curl -X POST "$VRDN_BASE/rate-plans" \
  -H "Authorization: Bearer $VRDN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
    "name": "Bed & Breakfast",
    "base_price": "120.00",
    "public_name": "Bed & Breakfast",
    "description": "A full breakfast for two each morning.",
    "active_for_booking_engine": true
  }'
{ "rate_plan_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02" }

Set kind, the parent, and a negative derivation. Gate it behind a code by adding one (see below) and setting requires_promo_code: true.

curl -X POST "$VRDN_BASE/rate-plans" \
  -H "Authorization: Bearer $VRDN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
    "name": "Advance Purchase, save 20%",
    "base_price": "120.00",
    "kind": "promotion",
    "derived_from_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02",
    "derivation_type": "percent",
    "derivation_value": "-20.00",
    "active_for_booking_engine": true
  }'

A derived plan needs both derivation_type and derivation_value, or the request is rejected. Its price is always the parent's current price with the derivation applied, so it follows the parent's seasonal pricing automatically.

PATCH /rate-plans/{id}

Send only the fields you want to change. Accepts the same fields as create (except room_type_id), plus is_active.

{ "rate_plan_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02", "updated": true }

DELETE /rate-plans/{id}

The default rate plan cannot be deleted (403). Reservations already booked on a deleted plan keep the price they were quoted.

{ "rate_plan_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02", "deleted": true }

Intervals layer date-specific pricing and stay rules over a plan's base price. Intervals on the same plan must not overlap; an overlapping range returns 409.

GET /rate-plans/{id}/intervals

Requires rates:read.

POST /rate-plans/{id}/intervals
FieldRequiredNotes
nameyesFor example "High Season".
start_date / end_dateyesYYYY-MM-DD. Start must be before end.
price_monprice_sunnoPer-weekday price. A blank day falls back to base price.
min_stay / max_staynoLength-of-stay rules for this range.
closed_to_arrival / closed_to_departure / stop_sellnoAvailability flags. Default false.
extra_guest_charge / single_guest_discountnoPer-season overrides. Default "0.00".
curl -X POST "$VRDN_BASE/rate-plans/5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02/intervals" \
  -H "Authorization: Bearer $VRDN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "High Season",
    "start_date": "2026-12-01",
    "end_date": "2027-03-31",
    "price_mon": "180.00", "price_fri": "210.00",
    "min_stay": 3
  }'
{ "interval_id": "d8a4c2f6-5e9b-4d7a-8f1c-3b6e0a9d5c28" }

PATCH /intervals/{id}
DELETE /intervals/{id}

PATCH accepts any interval field and re-checks the non-overlap rule.


An inclusion is a perk (a fixed included item) or a credit (a spendable allowance for a category, such as a spa credit). Inclusions are set as a whole list: a POST replaces the plan's entire inclusion set.

GET /rate-plans/{id}/inclusions

Requires rates:read.

POST /rate-plans/{id}/inclusions
FieldRequiredNotes
labelyesGuest-facing label, for example "Spa credit".
allocated_amountyesValue as a decimal string. "0.00" for a free perk.
frequencyyesperStay, perNight, perGuest, or perGuestPerNight.
inclusion_kindnoperk (default) or credit.
revenue_categoryyesroom, fnb, spa, excursions, activities, or other. For a credit this is the category it applies to.
service_item_idnoLink to a catalogue service item.
currencynoDefaults to the plan currency.
included_quantitynoDefaults to 1.
curl -X POST "$VRDN_BASE/rate-plans/5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02/inclusions" \
  -H "Authorization: Bearer $VRDN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inclusions": [
      { "label": "Daily breakfast for two", "allocated_amount": "20.00", "frequency": "perGuestPerNight", "revenue_category": "fnb" },
      { "label": "Spa credit", "allocated_amount": "150.00", "frequency": "perStay", "inclusion_kind": "credit", "revenue_category": "spa" }
    ]
  }'
{ "rate_plan_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02", "count": 2 }

A code unlocks a promotion. The discount lives in the promotion, so a code never carries a saving of its own. Attach codes to the plan they unlock.

GET /rate-plans/{id}/promo-codes

Requires rates:read.

POST /rate-plans/{id}/promo-codes
FieldRequiredNotes
codeyes3 to 40 characters. Stored and matched in upper case.
valid_from / valid_tonoYYYY-MM-DD window.
max_redemptionsnoTotal-use cap. Omit for unlimited.
max_per_guestnoPer-guest cap.
curl -X POST "$VRDN_BASE/rate-plans/e2a9d7c4-3f6b-4c1e-9a8d-7b5f0c2e4a19/promo-codes" \
  -H "Authorization: Bearer $VRDN_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "EARLYBIRD25", "max_redemptions": 100 }'
{ "promo_code_id": "a5e2c8f1-7d4b-4a6e-b9c3-0f8d2a5e7c41", "code": "EARLYBIRD25" }

PATCH /promo-codes/{id}
DELETE /promo-codes/{id}

PATCH accepts valid_from, valid_to, max_redemptions, max_per_guest, and is_active. The code string itself cannot be changed, because bookings freeze the code they were made with; delete it and create a new one instead. Deleting a code does not affect reservations already booked with it.