Operaciones de extras
Consulta, crea, edita y borra extras opcionales de tus productos por API v1 o MCP.
Un extra es un complemento opcional que añades a un producto —una actividad, un alojamiento, un pack
o un alquiler— para que el cliente lo sume a su reserva: un seguro, un alquiler de material, un
servicio de fotos... Se configura una vez en el catálogo y el cliente lo ve y lo marca en el motor de
reservas. Más sobre cómo montarlos, en
Añadir extras a tus productos.
Operaciones de esta página: list-extras, get-extra, create-extra, update-extra, delete-extra
(solo lectura: list-extras, get-extra; escritura: create-extra, update-extra, delete-extra)
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. El
customer_id se toma siempre del token; solo hace falta pasarlo con tokens multicuenta.
list-extras: enumera los extras del catálogo
Devuelve el listado de extras del centro: título, modo de cobro, precio y si están activos. Es una
operación de solo lectura: vale con cualquier token.
Cómo llamarla
curl "https://api.bukyapp.com/v1/ops/list-extras" \
-H "Authorization: Bearer bk_TU_TOKEN"Por MCP: «¿Qué extras tengo configurados?» o «Enséñame los extras que tengan "neopreno" en el nombre».
Parámetros
| Parámetro | Tipo | Nivel | Qué hace |
|---|---|---|---|
q | texto | opcional | Busca por texto (sin tildes) en el nombre del extra, como el buscador del panel. |
disabled | booleano | opcional | true: solo desactivados. false: solo activos. Sin él, salen todos. |
created_from, created_to | fecha | opcional | Rango de fechas de creación (como el filtro del panel). |
detail | texto | opcional | compact (por defecto): lo justo para identificar cada extra. descriptive: añade descripción, texto de aviso y la pregunta al cliente, ya traducidos a texto plano. |
lang | texto | opcional | Solo con detail: "descriptive": fuerza el idioma de los textos (por ejemplo "es"). |
full | booleano | opcional | Documentos completos tal cual los guarda el servidor. Pesado: solo si lo necesitas de verdad. Gana a detail. |
limit | número | opcional | Máximo de resultados a devolver, tras aplicar los filtros anteriores. |
Qué devuelve
En la cuenta demo:
{
"success": true,
"operation": "list-extras",
"detail": "compact",
"count": 0,
"total": 0,
"items": []
}Ahora mismo el centro no tiene ningún extra dado de alta, por eso items sale vacío. Cuando haya
extras, cada fila de la vista compacta trae _id, title, internalName, mode, price_cents,
price_eur e is_disabled. Con detail: "descriptive" se añaden description, alert_text,
need_info, need_info_required, need_info_question y max.
| Campo | Significado |
|---|---|
count | Filas devueltas en items, después de aplicar limit. |
total | Cuántas coinciden con los filtros, antes de limit. Si count es menor que total, limit recortó la lista. |
items | Los extras, en la vista pedida (compact, descriptive o full). |
Consejos
- Antes de crear un extra con
create-extra, revisalist-extras(conqsi buscas uno concreto)
para no duplicar uno que ya existe: es más directo que provocar el error de get-extra.
detail: "descriptive"te da los textos ya en idioma plano: útil si el asistente los va a leer en
voz alta o resumirlos.
get-extra: consulta un extra por nombre o id
Devuelve el documento completo y actualizado de un extra: sirve para comprobar cómo quedó tras
crearlo o editarlo, o para conseguir su identificador exacto antes de otra operación.
Es una operación de solo lectura: vale con cualquier token.
Cómo llamarla
curl "https://api.bukyapp.com/v1/ops/get-extra?extra=Seguro" \
-H "Authorization: Bearer bk_TU_TOKEN"Por MCP: «¿Qué precio tiene el extra Seguro?» o «Busca el extra Toalla».
Parámetros
| Parámetro | Tipo | Nivel | Qué hace |
|---|---|---|---|
extra | texto | obligatorio | Nombre, título o identificador del extra. El manual lo marca como recomendado, pero sin él la operación responde con error (extra_intent_required): en la práctica es obligatorio. |
id, extra_id | texto | opcional | Alias de extra; usa el que te resulte más natural. |
Qué devuelve
En la cuenta demo no hay ningún extra dado de alta todavía, así que la respuesta real es la de «no
encontrado» — el mismo mecanismo de desambiguación que usan todas las operaciones get-*:
{
"success": false,
"operation": "get-extra",
"error": "extra_unresolved",
"details": "el customer no tiene ninguna entidad de este tipo configurada",
"candidates": [],
"hint": "El customer no tiene ningún extra / suplemento configurado todavía."
}Cuando el nombre coincide con un extra, la respuesta trae _id, resolved (qué se eligió y por qué)
y el documento completo en item: título, precio, impuesto, modo (per_person/full), máximo por
reserva, si pide información al cliente y el resto de ajustes que ves en el panel.
Si pasas un identificador de 24 caracteres que no está en el catálogo, get-extra lo consulta igual
contra el servidor:
{
"success": false,
"error": "extra_not_found",
"details": "GET /extras/64b5129ef8ffa3fffa559999 no devolvió la entidad (¿borrada o de otro customer?)",
"resolved": {
"id": "64b5129ef8ffa3fffa559999",
"reason": "fallback: _id de 24hex no presente en el catálogo cacheado — GET directo"
}
}| Campo | Significado |
|---|---|
resolved | Qué extra se eligió (o intentó resolver) y por qué: nombre exacto, candidato único o identificador directo. |
item | El documento completo, solo si success:true. |
candidates | Extras del customer que podrían coincidir, cuando el nombre es ambiguo o no hay ninguno. |
Errores propios
| Situación | Respuesta |
|---|---|
Falta extra (y sus alias) | 200 con success:false, error: "extra_intent_required". |
| Nombre sin coincidencias | 200 con success:false, error: "extra_unresolved" y candidates (vacío si el customer no tiene ningún extra). |
| Identificador de 24 caracteres que no existe o no es del customer | 200 con success:false, error: "extra_not_found". |
Consejos
- Antes de crear un extra con
create-extra, pruebaget-extracon un nombre inventado: si el
customer ya tiene extras, candidates te los enseña todos y evitas duplicar.
create-extra: crea un extra nuevo
Da de alta un extra —precio, título e impuesto— replicando lo que hace el panel. Es una operación de
escritura.
Cómo llamarla
curl -X POST https://api.bukyapp.com/v1/ops/create-extra \
-H "Authorization: Bearer bk_TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Alquiler neopreno", "price_eur": 8, "tax": "21%", "mode": "full"}'Por MCP: «Crea un extra llamado Alquiler neopreno a 8 euros, con IVA del 21% y precio para todo el
grupo».
Parámetros
| Parámetro | Tipo | Nivel | Qué hace |
|---|---|---|---|
title | texto | obligatorio | Título del extra. |
price_eur | número | recomendado | Precio en euros. Si lo omites, el extra se crea gratis (0 €); es un valor válido en Buky. |
tax | texto | recomendado | Impuesto: "default", un porcentaje ("21%"), un nombre ("IVA") o un identificador. Por defecto, el impuesto inclusive del centro. |
mode | texto | recomendado | per_person (precio y límite por persona, por defecto) o full (precio único para todo el grupo). Admite sinónimos («por persona», «grupo»). |
description | texto | opcional | Descripción del extra. |
Qué devuelve
Prueba en seco con impuesto y modo explícitos:
{
"operation": "create-extra",
"dry_run": true,
"success": true,
"applied_defaults": { "mode": "full" },
"resolved_tax": { "id": "69a181ce5d6272575493bcfd", "reason": "match por percent=21" },
"resolved_mode": { "mode": "full", "reason": "match exacto 'full'" },
"payload_preview": {
"title": { "es": "Alquiler neopreno", "en": "New", "de": "New", "...": "..." },
"description": { "es": "", "...": "..." },
"taxes": ["69a181ce5d6272575493bcfd"],
"price": 800,
"mode": "full"
}
}| Campo | Significado |
|---|---|
applied_defaults | Qué valores se rellenaron solos porque no los pasaste. |
resolved_tax | Qué impuesto del centro se usó y por qué coincidió con tu tax. |
resolved_mode | El modo aplicado y por qué. |
payload_preview | El documento que se crearía: título traducido a los idiomas del centro ("New" en los que no rellenas), precio en céntimos y el resto de campos. |
Cuando la creación se aplica de verdad (fuera de la prueba en seco), la respuesta también trae _id:
el identificador del extra recién creado.
Ejemplos
Extra gratis, sin precio:
{ "title": "Bienvenida al centro" }→ payload_preview.price: 0.
Impuesto que no existe en el centro:
{ "title": "Extra con IVA inventado", "price_eur": 5, "tax": "99%" }→ success:false, error: "tax_unresolved" y tax_candidates con los impuestos reales del centro
(en la cuenta demo, solo IVA al 21%).
Errores propios
| Situación | Respuesta |
|---|---|
Falta title | 400 con error: "invalid_params" y el campo en details. |
tax sin coincidencia | 200 con success:false, error: "tax_unresolved" y tax_candidates. |
Consejos
- Si no indicas
tax, se usa el impuesto marcado como inclusive por defecto del centro: revisa
resolved_tax.reason para saber cuál fue.
mode: "full"conviene para extras que se cobran una vez por reserva (alquiler de una caja);
per_person para lo que se multiplica por persona (seguro, comida).
update-extra: edita un extra existente
Cambia solo los campos que le pases —título, precio, impuesto, modo, máximo por reserva, si pide
información al cliente, condiciones de pago anticipado...— dejando el resto igual. Es una operación de
escritura.
Cómo llamarla
curl -X POST https://api.bukyapp.com/v1/ops/update-extra \
-H "Authorization: Bearer bk_TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"extra": "Seguro", "price_eur": 20}'Por MCP: «Sube el precio del extra Seguro a 20 euros».
Parámetros
| Parámetro | Tipo | Nivel | Qué hace |
|---|---|---|---|
extra | texto | obligatorio | Nombre, título o identificador del extra a editar. |
title, price_eur | texto / número | recomendado | Nuevo título o precio (euros). |
mode, tax, description, alertText, internalName | — | opcional | Igual sentido que en create-extra, más un texto de aviso y un nombre interno para el panel. |
max | número | opcional | Máximo de unidades por reserva. Sin valor, sin límite. |
show_in_calendar | booleano | opcional | Mostrar el extra en el calendario. |
need_info, need_info_required, need_info_question | booleano / booleano / texto | opcional | Pide información al cliente al reservar (por ejemplo, la talla del neopreno). Poner need_info en false desactiva también need_info_required. |
payment_mode | texto | opcional | Cómo se cobra si el extra se vende como producto propio: full, advance o none. |
payment_advance_mode, payment_advance_percent, payment_advance_fixed_eur | — | opcional | Solo con payment_mode: "advance": anticipo por porcentaje (0-100) o por importe fijo en euros, mutuamente excluyentes. |
checkin_mode | texto | opcional | Check-in online: vacío (todos), leader (solo el titular) u off. Necesita el check-in online activado en el centro. |
Qué devuelve
En la cuenta demo no hay extras dados de alta, así que la prueba en seco no llega a construir la
vista previa de cambios:
{
"operation": "update-extra",
"dry_run": true,
"success": false,
"error": "extra_unresolved",
"details": "el customer no tiene extras configurados",
"candidates": [],
"hint": "Especifica el extra (nombre/título o _id) entre candidates."
}Con un extra real, la prueba en seco devuelve changes: solo los campos que cambiarían, con su valor
nuevo, sin tocar nada.
| Campo | Significado |
|---|---|
_id | Identificador del extra resuelto. |
changes | Los campos que se actualizarían. |
candidates | Extras del customer que podrían coincidir, si el nombre no se resolvió. |
Errores propios
| Situación | Respuesta |
|---|---|
Falta extra | 400 con error: "invalid_params". A diferencia de get-extra, aquí el manual ya marca el parámetro como obligatorio y el error llega como validación de esquema, no como *_intent_required. |
| Nombre sin coincidencias | 200 con success:false, error: "extra_unresolved". |
Consejos
price_eurva siempre en euros; el servidor lo guarda en céntimos.- Los campos de texto (
title,description,alertText,need_info_question) solo tocan el
castellano: el resto de idiomas ya traducidos no se pierden.
payment_advance_percentypayment_advance_fixed_eurson excluyentes: manda solo uno de los dos.
delete-extra: borra un extra
El extra deja de verse en el catálogo y en el motor de reservas. No puedes deshacerlo desde la API ni
desde el asistente, pero el soporte de Buky puede recuperarlo si lo necesitas. No hace limpieza en
cascada: si el extra estaba asociado a un pack o a un recurso, esa referencia queda colgando (algo
menor, sin efecto visible para el cliente).
Cómo llamarla
curl -X POST https://api.bukyapp.com/v1/ops/delete-extra \
-H "Authorization: Bearer bk_TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"extra": "Toalla", "confirm": true}'Por MCP: «Borra el extra Toalla» (el asistente te pedirá confirmación antes de un borrado real).
Parámetros
| Parámetro | Tipo | Nivel | Qué hace |
|---|---|---|---|
extra | texto | obligatorio | Nombre, título o identificador del extra a borrar. |
confirm | booleano | recomendado | Tiene que ser true para borrar de verdad; sin él, la operación se queda en modo de prueba aunque no pidas dry_run. |
Qué devuelve
En la cuenta demo no hay extras, así que la prueba en seco no pasa de la resolución del nombre:
{
"operation": "delete-extra",
"dry_run": true,
"success": false,
"error": "extra_unresolved",
"details": "el customer no tiene extras configurados",
"candidates": [],
"hint": "Especifica el extra (nombre/título o _id) entre candidates."
}Con un extra real, la respuesta confirma el borrado una vez aplicado.
| Campo | Significado |
|---|---|
_id | Identificador del extra borrado. |
reversible | true: el soporte de Buky puede recuperarlo si lo pides. |
Errores propios
| Situación | Respuesta |
|---|---|
Falta extra | 400 con error: "invalid_params". |
| Nombre sin coincidencias | 200 con success:false, error: "extra_unresolved". |
Consejos
- Si te equivocas de extra, el soporte de Buky puede recuperarlo.
