Skip to content
Iniciar sesión
Veridien Docs

Ofertas y códigos promocionales

Los endpoints de catálogo responden a "qué puedo reservar en cada tipo de habitación". Estos responden a "qué ofertas se aplican a esta estancia", que es lo que un motor de reservas necesita para su escaparate: nombres públicos, descripciones, imágenes, qué incluye un paquete y el precio para el grupo en cuestión.

Una tarifa, un paquete y una promoción son el mismo tipo de objeto. Se diferencian por su kind y por cómo deriva su precio de una tarifa madre, y por eso un paquete se distribuye y se tarifica exactamente igual que cualquier otra tarifa.


GET /rate-plans

Ámbito: availability:read

Todas las ofertas que el establecimiento ha publicado para el motor de reservas, con el precio calculado para la estancia y el grupo pedidos.

ParámetroObligatorioNotas
check_inYYYY-MM-DD.
check_outYYYY-MM-DD, excluida.
adultsnoPor defecto, 2.
childrennoPor defecto, 0.
room_type_idnoLimita a un tipo de habitación.
curl "$VRDN_BASE/rate-plans?check_in=2026-08-01&check_out=2026-08-04&adults=2" \
  -H "Authorization: Bearer $VRDN_KEY"
{
  "check_in": "2026-08-01",
  "check_out": "2026-08-04",
  "data": [
    {
      "rate_plan_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02",
      "room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
      "room_type_name": "Ocean Suite",
      "public_name": "Half Board Escape",
      "kind": "package",
      "description": "Breakfast and dinner included daily.",
      "image_url": "https://cdn.example.com/half-board.jpg",
      "inclusions": [
        { "label": "Breakfast", "frequency": "perGuestPerNight", "included_quantity": 1 },
        { "label": "Dinner", "frequency": "perGuestPerNight", "included_quantity": 1 }
      ],
      "min_los": 2,
      "max_los": null,
      "currency": "USD",
      "total": "1341.60",
      "room_subtotal": "1020.00",
      "taxes_total": "321.60",
      "base_occupancy": 2,
      "nightly_rates": [{ "date": "2026-08-01", "day_of_week": 6, "rate": "340.00", "source": "interval" }]
    }
  ]
}

Una oferta solo aparece cuando se cumple todo lo siguiente. Lo que no lo cumple simplemente no está en la respuesta; no hay entradas parciales ni marcadas como "no disponible".

  • La tarifa está activa y el establecimiento la ha habilitado para el motor de reservas.
  • La estancia cae dentro de la ventana de reserva y de la ventana de estancia de la oferta.
  • La duración de la estancia respeta el mínimo y el máximo de la oferta, y todas las noches caen en días de la semana permitidos.
  • El tipo de habitación admite al grupo.
  • La tarifa no está protegida por un código promocional.

Las ofertas protegidas por un código promocional nunca aparecen aquí. Solo se llega a ellas validando un código correctamente, como se explica más abajo.

inclusions enumera lo que agrupa un paquete, con la frecuencia con la que se repite cada elemento: perStay, perNight, perGuest o perGuestPerNight. Son descriptivas. El precio al que se vende un paquete es el total único; el establecimiento reparte internamente ese total entre las inclusiones para que cada componente reciba el tratamiento fiscal correcto, pero el huésped paga una sola cifra.


POST /promo-codes/validate

Ámbito: availability:read

CampoObligatorioNotas
codeSe ignoran las mayúsculas y los espacios alrededor.
check_inYYYY-MM-DD.
check_outYYYY-MM-DD, excluida.
room_type_idnoSi lo envías y la oferta del código está en otro tipo de habitación, la respuesta es el valid: false uniforme.
adultsnoPor defecto, 2.
childrennoPor defecto, 0.
child_agesnoPor defecto, []. Cuando no está vacío, su longitud es el número de niños y manda sobre children.

El tamaño del grupo se comprueba contra la ocupación máxima del tipo de habitación, así que un grupo declarado por debajo puede validar aquí y fallar después en POST /holds.

Un código desbloquea una tarifa. No aplica un descuento propio: el ahorro ya está incorporado en la tarifa que el código revela, así que el precio que recibes es el precio, sin nada más que calcular.

curl -X POST "$VRDN_BASE/promo-codes/validate" \
  -H "Authorization: Bearer $VRDN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "SUMMER26",
    "check_in": "2026-08-01",
    "check_out": "2026-08-04",
    "adults": 2
  }'

Un código que se aplica devuelve la oferta que desbloquea, con la misma forma que una entrada de /rate-plans.

{
  "valid": true,
  "code": "SUMMER26",
  "rate_plan": {
    "rate_plan_id": "e2a9d7c4-3f6b-4c1e-9a8d-7b5f0c2e4a19",
    "room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
    "room_type_name": "Ocean Suite",
    "public_name": "Early Bird",
    "kind": "promotion",
    "description": "Book 60 days ahead and save.",
    "image_url": "https://cdn.example.com/early-bird.jpg",
    "inclusions": [],
    "min_los": 3,
    "max_los": null,
    "currency": "USD",
    "total": "1140.36",
    "room_subtotal": "867.00",
    "taxes_total": "273.36",
    "nightly_rates": [{ "date": "2026-08-01", "day_of_week": 6, "rate": "289.00", "source": "interval" }]
  }
}

Un código que no se aplica devuelve una única respuesta, sea cual sea la causa.

{
  "valid": false,
  "reason": "That code is not valid for these dates."
}

La respuesta de fallo es deliberadamente idéntica para un código que no existe, uno que ha caducado, uno que ya se ha canjeado por completo y uno cuya oferta no cubre las fechas pedidas. Distinguirlos permitiría a quien llama averiguar qué códigos son reales, así que la causa concreta nunca se revela.

Al comparar códigos se ignoran las mayúsculas y los espacios alrededor, así que summer26 y SUMMER26 son el mismo código.

La validación de códigos tiene un límite más estricto que el resto de la API, además de los límites por clave y por IP descritos en Autenticación. Los fallos repetidos devuelven 429. Valida un código cuando el huésped lo envíe, no en cada pulsación de tecla.


Pasa el código a la llamada de reserva. El servidor lo resuelve otra vez desde cero y vuelve a calcular el precio de la estancia.

curl -X POST "$VRDN_BASE/holds" \
  -H "Authorization: Bearer $VRDN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "guest_id": "c4e7b9d2-6a1f-4e3c-9b8d-2f5a7c0e1d46",
    "room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63",
    "rate_plan_id": "e2a9d7c4-3f6b-4c1e-9a8d-7b5f0c2e4a19",
    "check_in": "2026-08-01",
    "check_out": "2026-08-04",
    "adults": 2,
    "promo_code": "SUMMER26"
  }'

Dos consecuencias que conviene tener en cuenta al diseñar:

  • Una respuesta de validación es orientativa. Refleja el momento en que se emitió. Si el código caduca, se desactiva o alcanza su límite de canjes antes de que el huésped complete el pago, la reserva falla en lugar de respetar el precio anterior. Gestiona ese fallo en tu flujo de compra.
  • Nunca envíes un precio. El servidor calcula el precio de cada reserva por su cuenta e ignora cualquier importe que envíe un cliente. Un precio consultado es solo para mostrarlo.

El canje se contabiliza cuando se confirma una reserva, no cuando se valida un código, y se libera si la reserva se cancela. Un código limitado a un número fijo de canjes no puede venderse de más por reservas simultáneas.