Operaciones de disponibilidad, calendario y precios
Consulta días reservables, sesiones con plazas y precios de actividades, alojamientos, packs y alquileres por API v1 o MCP, con enlace de reserva.
Antes de que un cliente pague, tu motor de reservas responde tres preguntas seguidas: qué días puede venir, qué sesión concreta tiene plazas y cuánto le va a costar. Estas tres operaciones resuelven exactamente eso, en el mismo orden y con las mismas reglas que ve tu tienda pública: get-calendar da los días, get-avail da las sesiones y sus plazas reales, y get-quote da el precio y la disponibilidad de una selección concreta. Cómo se calcula el aforo de cada sesión (personal, vehículos, exclusiones) está explicado en Gestionar disponibilidad y aforo.
Operaciones de esta página: get-calendar, get-avail, get-quote (las tres de solo lectura).
Las bases comunes (autenticación, GET frente a POST, prueba en seco, errores HTTP, límites) están en API v1 — Introducción y primeros pasos.
get-calendar: días reservables de un producto
get-calendar responde a la pregunta «¿qué días puedo venir con N personas?» para una actividad, un alojamiento, un pack o un alquiler. Calcula lo mismo que el primer paso de tu motor de reservas, con las mismas reglas, y devuelve los días con plazas, los días cerrados con su motivo y el enlace al motor de reservas con la fecha y las personas ya rellenas. Es una operación de solo lectura: vale con cualquier token.
Cómo llamarla
Por API, con GET y los parámetros en la URL, o con POST y un cuerpo JSON:
curl "https://api.bukyapp.com/v1/ops/get-calendar?activity=Surf%20Principiante&from=2026-09-16&to=2026-10-15&pax=2" \
-H "Authorization: Bearer bk_TU_TOKEN"curl -X POST https://api.bukyapp.com/v1/ops/get-calendar \
-H "Authorization: Bearer bk_TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"activity": "Surf Principiante", "from": "2026-09-16", "to": "2026-10-15", "pax": 2}'Por MCP, el asistente la ejecuta solo cuando le preguntas por fechas. Si quieres forzarla: «Ejecuta get-calendar para Surf Principiante entre el 16 de septiembre y el 15 de octubre con 2 personas».
El manual completo, siempre actualizado, está en GET https://api.bukyapp.com/v1/ops/get-calendar/manual.
Parámetros
| Parámetro | Tipo | Nivel | Qué hace |
|---|---|---|---|
from | fecha | obligatorio | Inicio del rango, en formato ISO (2026-10-01). |
to | fecha | obligatorio | Fin del rango. Como máximo 199 días después de from. El motor de reservas consulta dos meses. |
product | texto | recomendado | Nombre, nombre interno o identificador del producto. Se busca en los cuatro catálogos a la vez; si no se resuelve a uno solo, la respuesta trae los candidatos para que elijas. |
activity, accommodation, pack, rental | texto | opcional | Alternativa a product cuando ya sabes de qué tipo es. Solo busca en ese catálogo. |
pax | número | recomendado | Personas del grupo. Cambia qué días son reservables. Si lo omites, se usa el mínimo del producto (1 si no tiene). |
per_person | booleano | opcional | Solo actividades. true si cada persona puede ir a una sesión distinta: entonces basta con un hueco libre por día. Por defecto false, el grupo va junto. |
admin_view | booleano | opcional | true para ver el calendario como lo ve el panel: sin el plazo mínimo de antelación y con las sesiones ocultas de la tienda. Por defecto false, la vista del cliente. |
entry | fecha | opcional | Solo alojamientos. Día de entrada: la respuesta añade exits_for_entry, las salidas válidas para esa entrada. |
option | texto | opcional | Solo packs. Opción o variación del pack (título, nombre o identificador). Por defecto, la primera. |
only_stay | número | opcional | Solo packs. Acompañantes que solo se alojan, sin actividades (de 0 a 6). Por defecto 0. |
Qué devuelve
Ejemplo real, recortado, para una actividad con dos personas:
{
"success": true,
"operation": "get-calendar",
"kind": "activity",
"resolved_activity": {
"id": "6aa3db20f4b405ea4e3dfc20",
"title": "Surf Principiante en piscina",
"reason": "match exacto por nombre 'Surf Principiante en piscina'"
},
"range": { "from": "2026-09-16", "to": "2026-10-15" },
"timezone": "Europe/Madrid",
"pax": { "requested": 2, "min": 1, "max_effective": 10, "mode": "group" },
"count_entry_days": 10,
"entry_days": ["2026-09-17", "2026-09-18", "2026-09-21", "2026-09-22", "..."],
"days": [
{ "day": "2026-09-16", "sessions": 1, "plazas": 0, "unlimited": false, "fits_group": false },
{ "day": "2026-09-17", "sessions": 2, "plazas": 8, "unlimited": false, "fits_group": true }
],
"closed_days": [
{ "day": "2026-09-16", "reason": "no_quota" },
{ "day": "2026-09-19", "reason": "no_session" }
],
"booker_url": "https://app.bukyapp.com/front/<cuenta>/product/6aa3db20f4b405ea4e3dfc20",
"booker_prefill_url": "https://app.bukyapp.com/front/<cuenta>/product/6aa3db20f4b405ea4e3dfc20?default=...",
"warnings": []
}| Campo | Significado |
|---|---|
resolved_activity (o resolved_accommodation, etc.) | Qué producto se eligió a partir del nombre que diste y por qué. Compruébalo cuando el nombre sea ambiguo. |
pax | Personas pedidas, mínimo del producto, máximo efectivo en ese rango y modo (group o per_person). |
entry_days | Los días en los que el grupo puede venir, en la zona horaria del centro. Es la respuesta corta. |
days | Todos los días con alguna sesión visible: cuántas sesiones hay, cuántas plazas quedan y si cabe el grupo. Sirve para explicar «hay sesión pero no cabéis». |
closed_days | Días sin opción y el motivo: no_session (no hay sesión), no_quota (hay sesión pero sin plazas para el grupo) y, en alojamientos, past, occupied o day_enter. |
booker_url | Enlace a la ficha del producto en tu motor de reservas. |
booker_prefill_url | El mismo enlace con la primera fecha disponible y el número de personas ya rellenos. Es el que conviene dar al cliente. |
no_date_required | Solo packs sin fecha (de tipo voucher o regalo): true. No hay días que consultar y la respuesta no trae booker_prefill_url; el pack se compra desde booker_url. |
exits_for_entry | Solo alojamientos con entry: salidas válidas para esa entrada, respetando estancia mínima y máxima y días de salida permitidos. |
activity_candidates (o accommodation_candidates, etc.) | Solo si el nombre no se resolvió a un único producto: lista de coincidencias con identificador, tipo y título. La operación no ejecuta hasta que concretes. |
Cómo se calcula
- Actividades. Un día es reservable si tiene al menos una sesión visible cuyo cupo real admite al grupo entero. En modo por persona basta con un hueco. El máximo de personas es el menor entre el máximo de la actividad y el mayor cupo del rango.
- Alojamientos. Un día es entrada válida si no es pasado, si esa noche quedan unidades libres suficientes (en alojamientos compartidos, una cama por persona) y si el alojamiento admite entradas ese día de la semana. Con
entryobtienes además las salidas válidas. - Packs y alquileres. Mismo principio aplicado a la opción del pack o al material, con las restricciones propias de cada uno.
- Packs sin fecha (voucher o regalo). No tienen días que elegir: la respuesta llega con
no_date_required: true, sin días que consultar y sinbooker_prefill_url. El cliente lo compra directamente desdebooker_url.
Los datos vienen de la misma consulta que usa tu motor de reservas, con una caché de un minuto: lo que devuelve esta operación es lo que vería un cliente en ese momento.
Ejemplos
¿Qué días puede venir un grupo de 4 en octubre?
{ "activity": "Clase Surf", "from": "2026-10-01", "to": "2026-11-01", "pax": 4 }Vista del panel, sin plazo de antelación
{ "activity": "Clase Surf", "from": "2026-09-04", "to": "2026-09-11", "pax": 2, "admin_view": true }Alojamiento: salidas válidas entrando el día 10
{ "accommodation": "Habitación doble", "from": "2026-10-01", "to": "2026-11-01", "pax": 2, "entry": "2026-10-10" }Pack: ¿qué días puede empezar un grupo de 3 con la opción de 5 noches?
{ "pack": "Surf Camp", "option": "5 noches", "from": "2026-10-01", "to": "2026-11-01", "pax": 3 }Errores propios de esta operación
| Situación | Respuesta |
|---|---|
Falta from o to | 400 con error: "invalid_params" y el campo que falta en details. |
| Rango de más de 199 días | 200 con success: false y error: "range_too_wide". Acota el rango o trocéalo. |
| Nombre que no coincide con ningún producto | 200 con success: false, error: "activity_unresolved" (o product_unresolved, accommodation_unresolved, etc.) y la lista activity_candidates con los productos disponibles de ese tipo. |
| Nombre que coincide con varios | Misma respuesta, con los candidatos en activity_candidates. Repite la llamada con el nombre exacto o el identificador. |
Consejos
- Pasa siempre
pax: sin él se usa el mínimo del producto y los días reservables pueden ser más de los que caben a tu grupo. - Para el cliente final, entrega
booker_prefill_url: llega al motor de reservas con fecha y personas puestas. En un pack sin fecha no existe: entregabooker_url. - Cuando expliques un «no», mira
closed_days: la diferencia entre «no hay sesión» y «no quedan plazas» cambia la respuesta que darás.
get-avail: plazas reales por sesión de una actividad
get-avail responde a «¿hay plazas, y para cuántos?» sesión por sesión, no día por día: es el mismo cálculo que hace tu motor de reservas al pintar el calendario, con el cupo real de cada sesión (personal necesario, vehículos o embarcaciones asociadas, plazo mínimo de antelación...). Es una operación de solo lectura: vale con cualquier token.
Cómo llamarla
curl "https://api.bukyapp.com/v1/ops/get-avail?activity=Surf%20Principiante%20en%20piscina&from=2026-09-16&to=2026-10-15&pax=2" \
-H "Authorization: Bearer bk_TU_TOKEN"curl -X POST https://api.bukyapp.com/v1/ops/get-avail \
-H "Authorization: Bearer bk_TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"activity": "Surf Principiante en piscina", "from": "2026-09-16", "to": "2026-10-15", "pax": 2}'Por MCP: «¿Qué sesiones de Surf Principiante en piscina tienen hueco para 2 entre el 16 de septiembre y el 15 de octubre?».
Parámetros
| Parámetro | Tipo | Nivel | Qué hace |
|---|---|---|---|
activity | texto | obligatorio | Nombre, nombre interno o identificador de la actividad. Si no se resuelve a una sola, la respuesta trae los candidatos. |
from | fecha | obligatorio | Inicio del rango. Se devuelven las sesiones que solapan [from, to). |
to | fecha | obligatorio | Fin del rango. Como máximo 199 días después de from. |
pax | número | opcional | Tamaño del grupo. No cambia el cálculo: solo marca fits_group en cada sesión. |
strict | booleano | opcional | Por defecto true, la vista del cliente (con el plazo de antelación aplicado). false es la vista del panel, sin ese plazo. |
Qué devuelve
Ejemplo real, recortado, para el mismo rango de un mes:
{
"success": true,
"operation": "get-avail",
"activity_id": "6aa3db20f4b405ea4e3dfc20",
"resolved_activity": {
"id": "6aa3db20f4b405ea4e3dfc20",
"reason": "match exacto por nombre 'Surf Principiante en piscina'"
},
"range": { "from": "2026-09-16T00:00:00.000Z", "to": "2026-10-15T00:00:00.000Z" },
"timezone": "Europe/Madrid",
"strict": true,
"pax": 2,
"count": 11,
"available_sessions": 10,
"sessions_fitting_group": 10,
"sessions": [
{ "session_id": "69dbaf7eb227f96a4e3ba8c6", "start": "2026-09-16T07:00:00.000Z", "end": "2026-09-16T09:00:00.000Z", "capacity": 10, "quota": { "total": 0, "active": 0 }, "unlimited": false, "available": false, "fits_group": false },
{ "session_id": "69dbaf7eb227f96a4e3ba8c7", "start": "2026-09-17T07:00:00.000Z", "end": "2026-09-17T09:00:00.000Z", "capacity": 10, "quota": { "total": 10, "active": 0 }, "unlimited": false, "available": true, "fits_group": true },
"..."
],
"booker_url": "https://app.bukyapp.com/front/<cuenta>/product/6aa3db20f4b405ea4e3dfc20",
"booker_prefill_url": "https://app.bukyapp.com/front/<cuenta>/product/6aa3db20f4b405ea4e3dfc20?default=...",
"warnings": []
}| Campo | Significado |
|---|---|
resolved_activity | Qué actividad se eligió a partir del nombre que diste y por qué. |
range, timezone | El rango consultado y la zona horaria del centro. |
strict | true si es la vista del cliente (con plazo de antelación), false si es la vista del panel. |
count | Sesiones devueltas en el rango. |
available_sessions | Cuántas de esas sesiones tienen al menos una plaza libre. |
sessions_fitting_group | Cuántas caben para el pax que pediste. |
sessions | Una entrada por sesión: horario, capacity, quota (cupo total y activo), unlimited (sin control de aforo) y fits_group. |
booker_url / booker_prefill_url | Ficha del producto y la misma con fecha y personas ya puestas. |
Errores propios de esta operación
| Situación | Respuesta |
|---|---|
| Nombre de actividad que no coincide con ninguna | success: false, error: "activity_unresolved" y activity_candidates con las actividades del catálogo. |
| Rango de más de 199 días | success: false, error: "range_too_wide" con el número de días pedidos. Acorta el rango o trocéalo. |
Consejos
- Es la fuente real de plazas por sesión: úsala para «¿hay hueco?». Para «¿qué días puedo venir?» agregado por día, usa
get-calendar; la agenda delist-sessions(capacidad − reservas) es solo una aproximación. - Pasa
paxpara saber cuántas sesiones caben al grupo entero, no solo cuáles tienen alguna plaza. - Usa
strict:falsecuando necesites ver el calendario como lo ve el panel, sin el plazo de antelación.
get-quote: precio y disponibilidad de una selección concreta
get-quote da el precio real y la disponibilidad de una selección ya concreta: fechas y personas en un alojamiento, o fechas, opción y unidades en un alquiler. Es el mismo cálculo que el paso 2 de tu motor de reservas. Para actividades y packs, por ahora solo da el precio «desde» del catálogo. Es una operación de solo lectura: vale con cualquier token.
Cómo llamarla
curl "https://api.bukyapp.com/v1/ops/get-quote?accommodation=bungalow%201&start=2026-10-10&end=2026-10-13&pax=2" \
-H "Authorization: Bearer bk_TU_TOKEN"curl -X POST https://api.bukyapp.com/v1/ops/get-quote \
-H "Authorization: Bearer bk_TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"accommodation": "bungalow 1", "start": "2026-10-10", "end": "2026-10-13", "pax": 2}'Por MCP: «¿Cuánto cuesta el bungalow 1 del 10 al 13 de octubre para 2 personas?».
Parámetros
| Parámetro | Tipo | Nivel | Qué hace |
|---|---|---|---|
product | texto | recomendado | Alojamiento, alquiler, actividad o pack: nombre, nombre interno o identificador. Se busca en los catálogos; si casa en varios, trae candidatos con su tipo. |
accommodation, rental, activity, pack | texto | opcional | Alternativa a product cuando ya sabes de qué tipo es. En actividades y packs, hoy solo da price_from_cents. |
start | fecha | recomendado | Alojamiento: día de entrada (YYYY-MM-DD). Alquiler: recogida (YYYY-MM-DDTHH:mm). |
end | fecha | recomendado | Alojamiento: día de salida. Alquiler: devolución. |
pax | número | recomendado | Alojamiento: huéspedes. Alquiler: personas por unidad. |
option | texto | opcional | Solo alquileres: variación u opción (nombre o identificador). Por defecto, la primera. |
quantity | número | opcional | Solo alquileres: unidades de la opción. Por defecto 1. |
size | texto | opcional | Solo alquileres: talla, si la opción tiene material por tallas. |
lang | texto | opcional | Idioma de los mensajes de conditions. Por defecto español. |
Qué devuelve
Ejemplo real, recortado, para un alojamiento con 1 persona 3 noches:
{
"success": true,
"operation": "get-quote",
"kind": "accommodation",
"product_id": "6a37ee3830e0c1f575f79611",
"resolved": {
"id": "6a37ee3830e0c1f575f79611",
"reason": "match exacto por nombre 'bungalow 1'",
"title": "bungalow 1",
"type": "BasicAccommodation"
},
"price_from_cents": 5000,
"taxes": [ { "name": "IVA", "percent": 21, "inclusive": true, "compound": false } ],
"selection": { "start": "2026-10-10", "end": "2026-10-13", "nights": 3, "pax": 1 },
"conditions": { "ok": true, "errors": [] },
"available": true,
"price_cents": 15000,
"price_with_taxes_cents": 15000,
"booker_url": "https://app.bukyapp.com/front/<cuenta>/product/6a37ee3830e0c1f575f79611",
"booker_prefill_url": "https://app.bukyapp.com/front/<cuenta>/product/6a37ee3830e0c1f575f79611?default=...",
"warnings": []
}Para una actividad, la respuesta se reduce a lo que hay en el catálogo:
{ "success": true, "kind": "activity", "price_from_cents": 6000, "taxes": [ { "name": "IVA", "percent": 21, "inclusive": true } ], "quote": null }| Campo | Significado |
|---|---|
kind | Tipo de producto resuelto: accommodation, rental, activity o pack. |
resolved | Qué producto se eligió a partir del nombre que diste y por qué. |
price_from_cents | El «desde» del catálogo, en céntimos: el mínimo de tarifas vigentes, sin clases extra ni extra-pax. |
taxes | Impuestos del producto: nombre, porcentaje y si van incluidos en el precio o se suman aparte. |
selection | La selección concreta pedida: fechas, noches (alojamiento) y personas. |
conditions | Si la selección cumple las reglas del producto (capacidad, mínimo o máximo de noches o de personas por unidad...). ok:false trae los mensajes en errors. |
available | Si quedan unidades libres para todas las noches (alojamiento) o para el rango pedido (alquiler). |
price_cents / price_with_taxes_cents | Precio de la selección: el que calcula el servidor y el que se pinta en el total de la tienda con impuestos aplicados. |
booker_url / booker_prefill_url | Ficha del producto y la misma con fecha, personas y opción ya puestas. |
Errores propios de esta operación
| Situación | Respuesta |
|---|---|
| Nombre que no coincide con ningún alojamiento o alquiler | success: false, error: "accommodation_unresolved" (o rental_unresolved) con candidates, la lista de productos de ese tipo. |
| La cuenta no tiene ningún alquiler configurado | success: false, error: "rental_unresolved" con candidates: [] y el detalle «el customer no tiene ninguna entidad de este tipo configurada». |
Consejos
conditionsyavailablevan por separado: en una prueba real, un bungalow con capacidad para 1 devolvióavailable: truey un precio calculado incluso pidiendo 2 personas, peroconditions.ok: falsecon el mensaje «Capacidad máxima: 1». Revisa siempreconditions.errorsantes de dar un precio por bueno a tu cliente.- Para actividades y packs no compares precios exactos:
price_from_centses el «desde» del catálogo, no el de una selección concreta. - Entrega
booker_prefill_urlal cliente: llega al motor de reservas con la selección ya puesta.
