CelebraeCelebrae
Celebrae

Descubre experiencias únicas para grupos. Vive momentos inolvidables con tus amigos.

Explorar

  • Experiencias
  • Locales
  • Categorías
  • Blog

Para negocios

  • Vende más con Celebrae
  • Guía para negocios
  • Cómo vender más experiencias
  • API / Desarrolladores

Soporte

  • Qué es Celebrae
  • Centro de Ayuda
  • Sobre Nosotros
  • Contacto

Legal

  • Términos y Condiciones
  • Política de Privacidad
  • Política de Cookies
  • Eliminación de datos
  • Arrepentimiento / revocación

© 2026 Celebrae. Todos los derechos reservados.

Al usar esta plataforma, aceptas nuestros Términos y Condiciones y Política de Privacidad.

CelebraeCelebrae
Celebrae

Descubre experiencias únicas para grupos. Vive momentos inolvidables con tus amigos.

Explorar

  • Experiencias
  • Locales
  • Categorías
  • Blog

Para negocios

  • Vende más con Celebrae
  • Guía para negocios
  • Cómo vender más experiencias
  • API / Desarrolladores

Soporte

  • Qué es Celebrae
  • Centro de Ayuda
  • Sobre Nosotros
  • Contacto

Legal

  • Términos y Condiciones
  • Política de Privacidad
  • Política de Cookies
  • Eliminación de datos
  • Arrepentimiento / revocación

© 2026 Celebrae. Todos los derechos reservados.

Al usar esta plataforma, aceptas nuestros Términos y Condiciones y Política de Privacidad.

CelebraeCelebrae
Celebrae

Descubre experiencias únicas para grupos. Vive momentos inolvidables con tus amigos.

Explorar

  • Experiencias
  • Locales
  • Categorías
  • Blog

Para negocios

  • Vende más con Celebrae
  • Guía para negocios
  • Cómo vender más experiencias
  • API / Desarrolladores

Soporte

  • Qué es Celebrae
  • Centro de Ayuda
  • Sobre Nosotros
  • Contacto

Legal

  • Términos y Condiciones
  • Política de Privacidad
  • Política de Cookies
  • Eliminación de datos
  • Arrepentimiento / revocación

© 2026 Celebrae. Todos los derechos reservados.

Al usar esta plataforma, aceptas nuestros Términos y Condiciones y Política de Privacidad.

CelebraeCelebrae
CELEBRAE
¿Eres nuevo?Regístrate
ExperienciasLocalesMapaCómo FuncionaTiendaAPIVende más con Celebrae
CelebraeCelebrae
CELEBRAE
¿Eres nuevo?Regístrate
ExperienciasLocalesMapaCómo FuncionaTiendaAPIVende más con Celebrae
CelebraeCelebrae
CELEBRAE
¿Eres nuevo?Regístrate
ExperienciasLocalesMapaCómo FuncionaTiendaAPIVende más con Celebrae
Portal desarrolladores
Referencia APIGuía desarrolladorPostman

API Reference - Celebrae v1

Documentación técnica de la API pública de Celebrae para integraciones server-to-server.

Base URL: https://www.celebrae.com/api/v1

Colección Postman: Descarga celebrae-api-postman.json e impórtala en Postman. Configura las variables base_url (debe incluir /api/v1), client_id y secret en la colección.


Índice

  1. Autenticación
  2. Errores
  3. Shops
  4. Experiencias
  5. Extras
  6. Bookings
  7. Webhooks
  8. Webhooks salientes (consumir)

Autenticación

Todas las peticiones a /api/v1/* requieren autenticación server-to-server.

Formato

Authorization: Bearer <client_id>:<secret>
  • client_id: Identificador del API client (ej. ce_a1b2c3d4...)
  • secret: Secreto compartido (solo se muestra una vez al crear el client)

Ejemplo

curl -H "Authorization: Bearer ce_abc123:tu_secreto_aqui" \
  https://api.celebrae.com/api/v1/shops

Obtención de credenciales

Si tienes un local en Celebrae, crea tus credenciales desde el panel de seller: Mi local → API y webhooks → Credenciales. El client_id y el secret se muestran una sola vez al crear.

# Crear client de prueba (solo desarrollo/admin)
npx tsx scripts/seed-api-client.ts <shop_id>

Scopes

Cada API client tiene scopes que definen qué puede hacer:

ScopePermisos
shops:readListar y ver detalle de shops
shops:write(Reservado)
experiences:readListar y ver experiencias y extras
experiences:write(Reservado)
bookings:readVer reservas
bookings:writeCrear reservas
webhooks:readVer estado de deliveries y listar endpoints
webhooks:writeCrear, actualizar y eliminar endpoints de webhook

Multi-tenant

Un API client puede tener acceso a varios shops (negocios). La asociación se gestiona en api_client_shops.


Errores

La API usa RFC 7807 Problem Details.

Formato

{
  "type": "https://api.celebrae.com/errors/404",
  "title": "Not Found",
  "status": 404,
  "detail": "Resource not found",
  "instance": "/api/v1/shops/xxx",
  "code": "NOT_FOUND"
}

Códigos HTTP

StatusSignificado
200OK
201Created
400Bad Request - Validación fallida
401Unauthorized - Credenciales inválidas o faltantes
403Forbidden - Sin permiso (scope o tenant)
404Not Found - Recurso no existe o no tienes acceso
409Conflict - Idempotency key ya usada con otro body
429Too Many Requests - Rate limit excedido
500Internal Server Error

Rate limit y headers

Planes homologados: free (no consume por API), nitro, pro, enterprise. El plan del API client determina los límites.

  • X-RateLimit-Limit: Límite por minuto (ej. 100 para pro).
  • X-RateLimit-Remaining: Peticiones restantes en la ventana actual.
  • X-RateLimit-Reset: Timestamp Unix (segundos) de cuándo se resetea el contador.
  • x-request-id: ID de correlación (incluye en soporte si reportas un error).

Códigos de error comunes

codeDescripción
INSUFFICIENT_SCOPEFalta el scope requerido
IDEMPOTENCY_KEY_REQUIREDPOST /bookings requiere header Idempotency-Key
IDEMPOTENCY_CONFLICTMisma key con body distinto
VALIDATION_ERRORBody inválido
NOT_FOUNDRecurso no encontrado

Shops

GET /shops

Lista los shops a los que tiene acceso el API client.

Scope: shops:read

Query params:

ParamTipoDefaultDescripción
limitnumber20Máx 100
offsetnumber0Paginación

Respuesta 200:

{
  "shops": [
    {
      "id": "uuid",
      "name": "Mi Local",
      "slug": "mi-local",
      "short_description": "...",
      "address": "...",
      "country": "ES",
      "currency": "EUR",
      "email": "contacto@local.com",
      "phone": "+34...",
      "website": "https://...",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 1
}

GET /shops/:id

Detalle de un shop.

Scope: shops:read

Respuesta 200:

{
  "id": "uuid",
  "name": "Mi Local",
  "slug": "mi-local",
  "description": "...",
  "short_description": "...",
  "address": "...",
  "address_line_2": "...",
  "country": "ES",
  "currency": "EUR",
  "email": "...",
  "phone": "...",
  "website": "...",
  "created_at": "2024-01-15T10:00:00Z"
}

Experiencias

GET /shops/:id/experiences

Lista experiencias (kits) del shop.

Scope: experiences:read

Query params:

ParamTipoDefaultDescripción
limitnumber20Máx 100
offsetnumber0Paginación
statusstring-active, paused, draft, archived

Respuesta 200:

{
  "experiences": [
    {
      "id": "uuid",
      "title": "Tour guiado",
      "slug": "tour-guiado",
      "short_description": "...",
      "base_price": 25.00,
      "currency": "EUR",
      "duration_minutes": 120,
      "status": "active",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ]
}

GET /experiences/:id

Detalle de una experiencia.

Scope: experiences:read

Query params:

ParamValorDescripción
includeextrasIncluir lista de extras

Respuesta 200:

{
  "id": "uuid",
  "title": "Tour guiado",
  "slug": "tour-guiado",
  "description": "...",
  "short_description": "...",
  "base_price": 25.00,
  "currency": "EUR",
  "duration_minutes": 120,
  "base_capacity": 4,
  "max_capacity": 10,
  "status": "active",
  "shop_id": "uuid",
  "created_at": "2024-01-15T10:00:00Z",
  "extras": [
    {
      "id": "uuid",
      "name": "Fotos",
      "price": 5.00,
      "description": "..."
    }
  ]
}

GET /experiences/:id/extras

Lista extras de la experiencia.

Scope: experiences:read

Query params:

ParamTipoDefault
limitnumber50
offsetnumber0

Respuesta 200:

{
  "extras": [
    {
      "id": "uuid",
      "name": "Fotos",
      "description": "...",
      "price": 5.00,
      "category": "Servicios",
      "max_quantity": 10
    }
  ]
}

Bookings

GET /bookings

Lista reservas de los shops del partner.

Scope: bookings:read

Query params:

ParamTipoDefaultDescripción
shop_idUUID-Filtrar por shop (debe estar en tus shops)
statusstring-pending, confirmed, completed, cancelled
date_fromstring-Fecha desde (YYYY-MM-DD)
date_tostring-Fecha hasta (YYYY-MM-DD)
limitnumber20Máx 100
offsetnumber0Paginación

Respuesta 200:

{
  "bookings": [
    {
      "id": "uuid",
      "order_id": "uuid",
      "kit_id": "uuid",
      "booking_date": "2024-06-15",
      "booking_time": "10:00:00",
      "number_of_people": 2,
      "total_price": 60.00,
      "status": "pending",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 42
}

GET /bookings/:id

Detalle de una reserva.

Scope: bookings:read

Respuesta 200:

{
  "id": "uuid",
  "order_id": "uuid",
  "kit_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00:00",
  "number_of_people": 2,
  "price_per_person": 25.00,
  "extras_total": 10.00,
  "total_price": 60.00,
  "status": "pending",
  "selected_extras": [...],
  "special_requests": "...",
  "created_at": "2024-01-15T10:00:00Z",
  "order": { ... },
  "kit": { ... }
}

POST /bookings

Crea una reserva. Requiere header Idempotency-Key.

Scope: bookings:write

Headers:

HeaderRequeridoDescripción
Idempotency-KeySíUUID o string único para evitar duplicados

Body:

{
  "kit_id": "uuid",
  "shop_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00",
  "number_of_people": 2,
  "buyer_name": "Juan Pérez",
  "buyer_email": "juan@ejemplo.com",
  "buyer_phone": "+34600000000",
  "selected_extras": [
    { "extra_id": "uuid", "quantity": 1 }
  ],
  "special_requests": "Sin gluten"
}
CampoTipoRequeridoDescripción
kit_idUUIDSíID de la experiencia
shop_idUUIDSíID del shop (debe estar en tus shops)
booking_datestringSíYYYY-MM-DD
booking_timestringSíHH:mm o HH:mm:ss
number_of_peoplenumberSí1-100
buyer_namestringSíMáx 200
buyer_emailstringSíEmail válido
buyer_phonestringNoMáx 50
selected_extrasarrayNo[{ extra_id, quantity }]
special_requestsstringNoMáx 1000

Nota: Las reservas creadas vía API tienen payment_source: 'external'. El pago no se gestiona en Celebrae.

Restricciones de reservas con payment_source: 'external':

  • No pasan por el checkout de Celebrae; el pago se gestiona fuera de la plataforma.
  • El order tiene payment_status: 'pending' (o 'external'); no se genera flujo de pago CELEBRAE.
  • QR y validación: consulta la documentación del producto para reglas específicas de generación de QR y validación en punto de venta.
  • Notificaciones: se dispara el webhook booking.created para sincronización; las notificaciones por email pueden variar según configuración.
  • Integraciones externas (Turitop, Octo, etc.): pueden tener restricciones adicionales; contacta a soporte si necesitas integración con proveedores externos.

Respuesta 201:

{
  "booking": {
    "id": "uuid",
    "order_id": "uuid",
    "kit_id": "uuid",
    "booking_date": "2024-06-15",
    "booking_time": "10:00:00",
    "number_of_people": 2,
    "total_price": 60.00,
    "status": "pending",
    "created_at": "2024-01-15T10:00:00Z"
  }
}

Idempotencia: Si repites la misma petición con la misma Idempotency-Key y el mismo body, recibirás la misma respuesta sin crear duplicados. Si el body es distinto, recibirás 409 Conflict.


Webhooks

GET /webhooks/deliveries

Lista intentos de envío de webhooks salientes.

Scope: webhooks:read

Query params:

ParamDescripción
event_idFiltrar por evento
endpoint_idFiltrar por endpoint
statuspending, delivered, failed
limit20 (default), máx 100
offset0

Respuesta 200:

{
  "deliveries": [
    {
      "id": "uuid",
      "event_id": "uuid",
      "endpoint_id": "uuid",
      "attempt_number": 1,
      "status": "delivered",
      "response_status": 200,
      "error_message": null,
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 1
}

GET /webhooks/deliveries/:id

Detalle de un intento de envío.

Scope: webhooks:read


POST /webhooks/deliveries/:id/retry

Reintenta manualmente un envío fallido. Solo administradores (sesión Celebrae, no API client).


Webhooks salientes (consumir)

Cuando ocurren eventos (ej. booking.created), Celebrae envía un POST a la URL configurada.

Headers

HeaderDescripción
X-Celebrae-SignatureHMAC-SHA256 de timestamp + "." + body
X-Celebrae-TimestampUnix timestamp (segundos)
X-Celebrae-Event-IdID del evento
X-Celebrae-Idempotency-Key(Opcional) Para deduplicar en tu lado
Content-Typeapplication/json

Verificación de firma

const crypto = require('crypto');
const payload = `${timestamp}.${rawBody}`;
const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

Eventos

event_typeCuándo
booking.createdSe crea una reserva
booking.updatedSe actualiza una reserva (ej. confirmación)
booking.completedSe marca una reserva como completada
booking.cancelledSe cancela una reserva
*Todos los eventos

Ejemplo de payload (booking.created)

{
  "booking_id": "uuid",
  "order_id": "uuid",
  "kit_id": "uuid",
  "shop_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00",
  "number_of_people": 2,
  "status": "pending",
  "payment_source": "external"
}

Configuración de endpoints

Puedes registrar tus endpoints de webhook vía API (scope webhooks:write):

  • POST /webhooks/endpoints — Crear endpoint. Body: { shop_id, url, events?: ["booking.created", "booking.updated", "booking.completed", "booking.cancelled", "*"] }. Devuelve signing_secret (guárdalo, no se muestra de nuevo).
  • GET /webhooks/endpoints — Listar endpoints. Query: shop_id (opcional).
  • PATCH /webhooks/endpoints/:id — Actualizar URL, eventos o status (active, paused, disabled).
  • DELETE /webhooks/endpoints/:id — Eliminar endpoint.

También puedes gestionarlos desde el panel seller: Mi local → API y webhooks → Webhooks.


Resumen de endpoints

MétodoRutaScope
GET/shopsshops:read
GET/shops/:idshops:read
GET/shops/:id/experiencesexperiences:read
GET/experiences/:idexperiences:read
GET/experiences/:id/extrasexperiences:read
GET/bookingsbookings:read
GET/bookings/:idbookings:read
POST/bookingsbookings:write
GET/webhooks/deliverieswebhooks:read
GET/webhooks/deliveries/:idwebhooks:read
Portal desarrolladores
Referencia APIGuía desarrolladorPostman

API Reference - Celebrae v1

Documentación técnica de la API pública de Celebrae para integraciones server-to-server.

Base URL: https://www.celebrae.com/api/v1

Colección Postman: Descarga celebrae-api-postman.json e impórtala en Postman. Configura las variables base_url (debe incluir /api/v1), client_id y secret en la colección.


Índice

  1. Autenticación
  2. Errores
  3. Shops
  4. Experiencias
  5. Extras
  6. Bookings
  7. Webhooks
  8. Webhooks salientes (consumir)

Autenticación

Todas las peticiones a /api/v1/* requieren autenticación server-to-server.

Formato

Authorization: Bearer <client_id>:<secret>
  • client_id: Identificador del API client (ej. ce_a1b2c3d4...)
  • secret: Secreto compartido (solo se muestra una vez al crear el client)

Ejemplo

curl -H "Authorization: Bearer ce_abc123:tu_secreto_aqui" \
  https://api.celebrae.com/api/v1/shops

Obtención de credenciales

Si tienes un local en Celebrae, crea tus credenciales desde el panel de seller: Mi local → API y webhooks → Credenciales. El client_id y el secret se muestran una sola vez al crear.

# Crear client de prueba (solo desarrollo/admin)
npx tsx scripts/seed-api-client.ts <shop_id>

Scopes

Cada API client tiene scopes que definen qué puede hacer:

ScopePermisos
shops:readListar y ver detalle de shops
shops:write(Reservado)
experiences:readListar y ver experiencias y extras
experiences:write(Reservado)
bookings:readVer reservas
bookings:writeCrear reservas
webhooks:readVer estado de deliveries y listar endpoints
webhooks:writeCrear, actualizar y eliminar endpoints de webhook

Multi-tenant

Un API client puede tener acceso a varios shops (negocios). La asociación se gestiona en api_client_shops.


Errores

La API usa RFC 7807 Problem Details.

Formato

{
  "type": "https://api.celebrae.com/errors/404",
  "title": "Not Found",
  "status": 404,
  "detail": "Resource not found",
  "instance": "/api/v1/shops/xxx",
  "code": "NOT_FOUND"
}

Códigos HTTP

StatusSignificado
200OK
201Created
400Bad Request - Validación fallida
401Unauthorized - Credenciales inválidas o faltantes
403Forbidden - Sin permiso (scope o tenant)
404Not Found - Recurso no existe o no tienes acceso
409Conflict - Idempotency key ya usada con otro body
429Too Many Requests - Rate limit excedido
500Internal Server Error

Rate limit y headers

Planes homologados: free (no consume por API), nitro, pro, enterprise. El plan del API client determina los límites.

  • X-RateLimit-Limit: Límite por minuto (ej. 100 para pro).
  • X-RateLimit-Remaining: Peticiones restantes en la ventana actual.
  • X-RateLimit-Reset: Timestamp Unix (segundos) de cuándo se resetea el contador.
  • x-request-id: ID de correlación (incluye en soporte si reportas un error).

Códigos de error comunes

codeDescripción
INSUFFICIENT_SCOPEFalta el scope requerido
IDEMPOTENCY_KEY_REQUIREDPOST /bookings requiere header Idempotency-Key
IDEMPOTENCY_CONFLICTMisma key con body distinto
VALIDATION_ERRORBody inválido
NOT_FOUNDRecurso no encontrado

Shops

GET /shops

Lista los shops a los que tiene acceso el API client.

Scope: shops:read

Query params:

ParamTipoDefaultDescripción
limitnumber20Máx 100
offsetnumber0Paginación

Respuesta 200:

{
  "shops": [
    {
      "id": "uuid",
      "name": "Mi Local",
      "slug": "mi-local",
      "short_description": "...",
      "address": "...",
      "country": "ES",
      "currency": "EUR",
      "email": "contacto@local.com",
      "phone": "+34...",
      "website": "https://...",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 1
}

GET /shops/:id

Detalle de un shop.

Scope: shops:read

Respuesta 200:

{
  "id": "uuid",
  "name": "Mi Local",
  "slug": "mi-local",
  "description": "...",
  "short_description": "...",
  "address": "...",
  "address_line_2": "...",
  "country": "ES",
  "currency": "EUR",
  "email": "...",
  "phone": "...",
  "website": "...",
  "created_at": "2024-01-15T10:00:00Z"
}

Experiencias

GET /shops/:id/experiences

Lista experiencias (kits) del shop.

Scope: experiences:read

Query params:

ParamTipoDefaultDescripción
limitnumber20Máx 100
offsetnumber0Paginación
statusstring-active, paused, draft, archived

Respuesta 200:

{
  "experiences": [
    {
      "id": "uuid",
      "title": "Tour guiado",
      "slug": "tour-guiado",
      "short_description": "...",
      "base_price": 25.00,
      "currency": "EUR",
      "duration_minutes": 120,
      "status": "active",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ]
}

GET /experiences/:id

Detalle de una experiencia.

Scope: experiences:read

Query params:

ParamValorDescripción
includeextrasIncluir lista de extras

Respuesta 200:

{
  "id": "uuid",
  "title": "Tour guiado",
  "slug": "tour-guiado",
  "description": "...",
  "short_description": "...",
  "base_price": 25.00,
  "currency": "EUR",
  "duration_minutes": 120,
  "base_capacity": 4,
  "max_capacity": 10,
  "status": "active",
  "shop_id": "uuid",
  "created_at": "2024-01-15T10:00:00Z",
  "extras": [
    {
      "id": "uuid",
      "name": "Fotos",
      "price": 5.00,
      "description": "..."
    }
  ]
}

GET /experiences/:id/extras

Lista extras de la experiencia.

Scope: experiences:read

Query params:

ParamTipoDefault
limitnumber50
offsetnumber0

Respuesta 200:

{
  "extras": [
    {
      "id": "uuid",
      "name": "Fotos",
      "description": "...",
      "price": 5.00,
      "category": "Servicios",
      "max_quantity": 10
    }
  ]
}

Bookings

GET /bookings

Lista reservas de los shops del partner.

Scope: bookings:read

Query params:

ParamTipoDefaultDescripción
shop_idUUID-Filtrar por shop (debe estar en tus shops)
statusstring-pending, confirmed, completed, cancelled
date_fromstring-Fecha desde (YYYY-MM-DD)
date_tostring-Fecha hasta (YYYY-MM-DD)
limitnumber20Máx 100
offsetnumber0Paginación

Respuesta 200:

{
  "bookings": [
    {
      "id": "uuid",
      "order_id": "uuid",
      "kit_id": "uuid",
      "booking_date": "2024-06-15",
      "booking_time": "10:00:00",
      "number_of_people": 2,
      "total_price": 60.00,
      "status": "pending",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 42
}

GET /bookings/:id

Detalle de una reserva.

Scope: bookings:read

Respuesta 200:

{
  "id": "uuid",
  "order_id": "uuid",
  "kit_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00:00",
  "number_of_people": 2,
  "price_per_person": 25.00,
  "extras_total": 10.00,
  "total_price": 60.00,
  "status": "pending",
  "selected_extras": [...],
  "special_requests": "...",
  "created_at": "2024-01-15T10:00:00Z",
  "order": { ... },
  "kit": { ... }
}

POST /bookings

Crea una reserva. Requiere header Idempotency-Key.

Scope: bookings:write

Headers:

HeaderRequeridoDescripción
Idempotency-KeySíUUID o string único para evitar duplicados

Body:

{
  "kit_id": "uuid",
  "shop_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00",
  "number_of_people": 2,
  "buyer_name": "Juan Pérez",
  "buyer_email": "juan@ejemplo.com",
  "buyer_phone": "+34600000000",
  "selected_extras": [
    { "extra_id": "uuid", "quantity": 1 }
  ],
  "special_requests": "Sin gluten"
}
CampoTipoRequeridoDescripción
kit_idUUIDSíID de la experiencia
shop_idUUIDSíID del shop (debe estar en tus shops)
booking_datestringSíYYYY-MM-DD
booking_timestringSíHH:mm o HH:mm:ss
number_of_peoplenumberSí1-100
buyer_namestringSíMáx 200
buyer_emailstringSíEmail válido
buyer_phonestringNoMáx 50
selected_extrasarrayNo[{ extra_id, quantity }]
special_requestsstringNoMáx 1000

Nota: Las reservas creadas vía API tienen payment_source: 'external'. El pago no se gestiona en Celebrae.

Restricciones de reservas con payment_source: 'external':

  • No pasan por el checkout de Celebrae; el pago se gestiona fuera de la plataforma.
  • El order tiene payment_status: 'pending' (o 'external'); no se genera flujo de pago CELEBRAE.
  • QR y validación: consulta la documentación del producto para reglas específicas de generación de QR y validación en punto de venta.
  • Notificaciones: se dispara el webhook booking.created para sincronización; las notificaciones por email pueden variar según configuración.
  • Integraciones externas (Turitop, Octo, etc.): pueden tener restricciones adicionales; contacta a soporte si necesitas integración con proveedores externos.

Respuesta 201:

{
  "booking": {
    "id": "uuid",
    "order_id": "uuid",
    "kit_id": "uuid",
    "booking_date": "2024-06-15",
    "booking_time": "10:00:00",
    "number_of_people": 2,
    "total_price": 60.00,
    "status": "pending",
    "created_at": "2024-01-15T10:00:00Z"
  }
}

Idempotencia: Si repites la misma petición con la misma Idempotency-Key y el mismo body, recibirás la misma respuesta sin crear duplicados. Si el body es distinto, recibirás 409 Conflict.


Webhooks

GET /webhooks/deliveries

Lista intentos de envío de webhooks salientes.

Scope: webhooks:read

Query params:

ParamDescripción
event_idFiltrar por evento
endpoint_idFiltrar por endpoint
statuspending, delivered, failed
limit20 (default), máx 100
offset0

Respuesta 200:

{
  "deliveries": [
    {
      "id": "uuid",
      "event_id": "uuid",
      "endpoint_id": "uuid",
      "attempt_number": 1,
      "status": "delivered",
      "response_status": 200,
      "error_message": null,
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 1
}

GET /webhooks/deliveries/:id

Detalle de un intento de envío.

Scope: webhooks:read


POST /webhooks/deliveries/:id/retry

Reintenta manualmente un envío fallido. Solo administradores (sesión Celebrae, no API client).


Webhooks salientes (consumir)

Cuando ocurren eventos (ej. booking.created), Celebrae envía un POST a la URL configurada.

Headers

HeaderDescripción
X-Celebrae-SignatureHMAC-SHA256 de timestamp + "." + body
X-Celebrae-TimestampUnix timestamp (segundos)
X-Celebrae-Event-IdID del evento
X-Celebrae-Idempotency-Key(Opcional) Para deduplicar en tu lado
Content-Typeapplication/json

Verificación de firma

const crypto = require('crypto');
const payload = `${timestamp}.${rawBody}`;
const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

Eventos

event_typeCuándo
booking.createdSe crea una reserva
booking.updatedSe actualiza una reserva (ej. confirmación)
booking.completedSe marca una reserva como completada
booking.cancelledSe cancela una reserva
*Todos los eventos

Ejemplo de payload (booking.created)

{
  "booking_id": "uuid",
  "order_id": "uuid",
  "kit_id": "uuid",
  "shop_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00",
  "number_of_people": 2,
  "status": "pending",
  "payment_source": "external"
}

Configuración de endpoints

Puedes registrar tus endpoints de webhook vía API (scope webhooks:write):

  • POST /webhooks/endpoints — Crear endpoint. Body: { shop_id, url, events?: ["booking.created", "booking.updated", "booking.completed", "booking.cancelled", "*"] }. Devuelve signing_secret (guárdalo, no se muestra de nuevo).
  • GET /webhooks/endpoints — Listar endpoints. Query: shop_id (opcional).
  • PATCH /webhooks/endpoints/:id — Actualizar URL, eventos o status (active, paused, disabled).
  • DELETE /webhooks/endpoints/:id — Eliminar endpoint.

También puedes gestionarlos desde el panel seller: Mi local → API y webhooks → Webhooks.


Resumen de endpoints

MétodoRutaScope
GET/shopsshops:read
GET/shops/:idshops:read
GET/shops/:id/experiencesexperiences:read
GET/experiences/:idexperiences:read
GET/experiences/:id/extrasexperiences:read
GET/bookingsbookings:read
GET/bookings/:idbookings:read
POST/bookingsbookings:write
GET/webhooks/deliverieswebhooks:read
GET/webhooks/deliveries/:idwebhooks:read
Portal desarrolladores
Referencia APIGuía desarrolladorPostman

API Reference - Celebrae v1

Documentación técnica de la API pública de Celebrae para integraciones server-to-server.

Base URL: https://www.celebrae.com/api/v1

Colección Postman: Descarga celebrae-api-postman.json e impórtala en Postman. Configura las variables base_url (debe incluir /api/v1), client_id y secret en la colección.


Índice

  1. Autenticación
  2. Errores
  3. Shops
  4. Experiencias
  5. Extras
  6. Bookings
  7. Webhooks
  8. Webhooks salientes (consumir)

Autenticación

Todas las peticiones a /api/v1/* requieren autenticación server-to-server.

Formato

Authorization: Bearer <client_id>:<secret>
  • client_id: Identificador del API client (ej. ce_a1b2c3d4...)
  • secret: Secreto compartido (solo se muestra una vez al crear el client)

Ejemplo

curl -H "Authorization: Bearer ce_abc123:tu_secreto_aqui" \
  https://api.celebrae.com/api/v1/shops

Obtención de credenciales

Si tienes un local en Celebrae, crea tus credenciales desde el panel de seller: Mi local → API y webhooks → Credenciales. El client_id y el secret se muestran una sola vez al crear.

# Crear client de prueba (solo desarrollo/admin)
npx tsx scripts/seed-api-client.ts <shop_id>

Scopes

Cada API client tiene scopes que definen qué puede hacer:

ScopePermisos
shops:readListar y ver detalle de shops
shops:write(Reservado)
experiences:readListar y ver experiencias y extras
experiences:write(Reservado)
bookings:readVer reservas
bookings:writeCrear reservas
webhooks:readVer estado de deliveries y listar endpoints
webhooks:writeCrear, actualizar y eliminar endpoints de webhook

Multi-tenant

Un API client puede tener acceso a varios shops (negocios). La asociación se gestiona en api_client_shops.


Errores

La API usa RFC 7807 Problem Details.

Formato

{
  "type": "https://api.celebrae.com/errors/404",
  "title": "Not Found",
  "status": 404,
  "detail": "Resource not found",
  "instance": "/api/v1/shops/xxx",
  "code": "NOT_FOUND"
}

Códigos HTTP

StatusSignificado
200OK
201Created
400Bad Request - Validación fallida
401Unauthorized - Credenciales inválidas o faltantes
403Forbidden - Sin permiso (scope o tenant)
404Not Found - Recurso no existe o no tienes acceso
409Conflict - Idempotency key ya usada con otro body
429Too Many Requests - Rate limit excedido
500Internal Server Error

Rate limit y headers

Planes homologados: free (no consume por API), nitro, pro, enterprise. El plan del API client determina los límites.

  • X-RateLimit-Limit: Límite por minuto (ej. 100 para pro).
  • X-RateLimit-Remaining: Peticiones restantes en la ventana actual.
  • X-RateLimit-Reset: Timestamp Unix (segundos) de cuándo se resetea el contador.
  • x-request-id: ID de correlación (incluye en soporte si reportas un error).

Códigos de error comunes

codeDescripción
INSUFFICIENT_SCOPEFalta el scope requerido
IDEMPOTENCY_KEY_REQUIREDPOST /bookings requiere header Idempotency-Key
IDEMPOTENCY_CONFLICTMisma key con body distinto
VALIDATION_ERRORBody inválido
NOT_FOUNDRecurso no encontrado

Shops

GET /shops

Lista los shops a los que tiene acceso el API client.

Scope: shops:read

Query params:

ParamTipoDefaultDescripción
limitnumber20Máx 100
offsetnumber0Paginación

Respuesta 200:

{
  "shops": [
    {
      "id": "uuid",
      "name": "Mi Local",
      "slug": "mi-local",
      "short_description": "...",
      "address": "...",
      "country": "ES",
      "currency": "EUR",
      "email": "contacto@local.com",
      "phone": "+34...",
      "website": "https://...",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 1
}

GET /shops/:id

Detalle de un shop.

Scope: shops:read

Respuesta 200:

{
  "id": "uuid",
  "name": "Mi Local",
  "slug": "mi-local",
  "description": "...",
  "short_description": "...",
  "address": "...",
  "address_line_2": "...",
  "country": "ES",
  "currency": "EUR",
  "email": "...",
  "phone": "...",
  "website": "...",
  "created_at": "2024-01-15T10:00:00Z"
}

Experiencias

GET /shops/:id/experiences

Lista experiencias (kits) del shop.

Scope: experiences:read

Query params:

ParamTipoDefaultDescripción
limitnumber20Máx 100
offsetnumber0Paginación
statusstring-active, paused, draft, archived

Respuesta 200:

{
  "experiences": [
    {
      "id": "uuid",
      "title": "Tour guiado",
      "slug": "tour-guiado",
      "short_description": "...",
      "base_price": 25.00,
      "currency": "EUR",
      "duration_minutes": 120,
      "status": "active",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ]
}

GET /experiences/:id

Detalle de una experiencia.

Scope: experiences:read

Query params:

ParamValorDescripción
includeextrasIncluir lista de extras

Respuesta 200:

{
  "id": "uuid",
  "title": "Tour guiado",
  "slug": "tour-guiado",
  "description": "...",
  "short_description": "...",
  "base_price": 25.00,
  "currency": "EUR",
  "duration_minutes": 120,
  "base_capacity": 4,
  "max_capacity": 10,
  "status": "active",
  "shop_id": "uuid",
  "created_at": "2024-01-15T10:00:00Z",
  "extras": [
    {
      "id": "uuid",
      "name": "Fotos",
      "price": 5.00,
      "description": "..."
    }
  ]
}

GET /experiences/:id/extras

Lista extras de la experiencia.

Scope: experiences:read

Query params:

ParamTipoDefault
limitnumber50
offsetnumber0

Respuesta 200:

{
  "extras": [
    {
      "id": "uuid",
      "name": "Fotos",
      "description": "...",
      "price": 5.00,
      "category": "Servicios",
      "max_quantity": 10
    }
  ]
}

Bookings

GET /bookings

Lista reservas de los shops del partner.

Scope: bookings:read

Query params:

ParamTipoDefaultDescripción
shop_idUUID-Filtrar por shop (debe estar en tus shops)
statusstring-pending, confirmed, completed, cancelled
date_fromstring-Fecha desde (YYYY-MM-DD)
date_tostring-Fecha hasta (YYYY-MM-DD)
limitnumber20Máx 100
offsetnumber0Paginación

Respuesta 200:

{
  "bookings": [
    {
      "id": "uuid",
      "order_id": "uuid",
      "kit_id": "uuid",
      "booking_date": "2024-06-15",
      "booking_time": "10:00:00",
      "number_of_people": 2,
      "total_price": 60.00,
      "status": "pending",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 42
}

GET /bookings/:id

Detalle de una reserva.

Scope: bookings:read

Respuesta 200:

{
  "id": "uuid",
  "order_id": "uuid",
  "kit_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00:00",
  "number_of_people": 2,
  "price_per_person": 25.00,
  "extras_total": 10.00,
  "total_price": 60.00,
  "status": "pending",
  "selected_extras": [...],
  "special_requests": "...",
  "created_at": "2024-01-15T10:00:00Z",
  "order": { ... },
  "kit": { ... }
}

POST /bookings

Crea una reserva. Requiere header Idempotency-Key.

Scope: bookings:write

Headers:

HeaderRequeridoDescripción
Idempotency-KeySíUUID o string único para evitar duplicados

Body:

{
  "kit_id": "uuid",
  "shop_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00",
  "number_of_people": 2,
  "buyer_name": "Juan Pérez",
  "buyer_email": "juan@ejemplo.com",
  "buyer_phone": "+34600000000",
  "selected_extras": [
    { "extra_id": "uuid", "quantity": 1 }
  ],
  "special_requests": "Sin gluten"
}
CampoTipoRequeridoDescripción
kit_idUUIDSíID de la experiencia
shop_idUUIDSíID del shop (debe estar en tus shops)
booking_datestringSíYYYY-MM-DD
booking_timestringSíHH:mm o HH:mm:ss
number_of_peoplenumberSí1-100
buyer_namestringSíMáx 200
buyer_emailstringSíEmail válido
buyer_phonestringNoMáx 50
selected_extrasarrayNo[{ extra_id, quantity }]
special_requestsstringNoMáx 1000

Nota: Las reservas creadas vía API tienen payment_source: 'external'. El pago no se gestiona en Celebrae.

Restricciones de reservas con payment_source: 'external':

  • No pasan por el checkout de Celebrae; el pago se gestiona fuera de la plataforma.
  • El order tiene payment_status: 'pending' (o 'external'); no se genera flujo de pago CELEBRAE.
  • QR y validación: consulta la documentación del producto para reglas específicas de generación de QR y validación en punto de venta.
  • Notificaciones: se dispara el webhook booking.created para sincronización; las notificaciones por email pueden variar según configuración.
  • Integraciones externas (Turitop, Octo, etc.): pueden tener restricciones adicionales; contacta a soporte si necesitas integración con proveedores externos.

Respuesta 201:

{
  "booking": {
    "id": "uuid",
    "order_id": "uuid",
    "kit_id": "uuid",
    "booking_date": "2024-06-15",
    "booking_time": "10:00:00",
    "number_of_people": 2,
    "total_price": 60.00,
    "status": "pending",
    "created_at": "2024-01-15T10:00:00Z"
  }
}

Idempotencia: Si repites la misma petición con la misma Idempotency-Key y el mismo body, recibirás la misma respuesta sin crear duplicados. Si el body es distinto, recibirás 409 Conflict.


Webhooks

GET /webhooks/deliveries

Lista intentos de envío de webhooks salientes.

Scope: webhooks:read

Query params:

ParamDescripción
event_idFiltrar por evento
endpoint_idFiltrar por endpoint
statuspending, delivered, failed
limit20 (default), máx 100
offset0

Respuesta 200:

{
  "deliveries": [
    {
      "id": "uuid",
      "event_id": "uuid",
      "endpoint_id": "uuid",
      "attempt_number": 1,
      "status": "delivered",
      "response_status": 200,
      "error_message": null,
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "total": 1
}

GET /webhooks/deliveries/:id

Detalle de un intento de envío.

Scope: webhooks:read


POST /webhooks/deliveries/:id/retry

Reintenta manualmente un envío fallido. Solo administradores (sesión Celebrae, no API client).


Webhooks salientes (consumir)

Cuando ocurren eventos (ej. booking.created), Celebrae envía un POST a la URL configurada.

Headers

HeaderDescripción
X-Celebrae-SignatureHMAC-SHA256 de timestamp + "." + body
X-Celebrae-TimestampUnix timestamp (segundos)
X-Celebrae-Event-IdID del evento
X-Celebrae-Idempotency-Key(Opcional) Para deduplicar en tu lado
Content-Typeapplication/json

Verificación de firma

const crypto = require('crypto');
const payload = `${timestamp}.${rawBody}`;
const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

Eventos

event_typeCuándo
booking.createdSe crea una reserva
booking.updatedSe actualiza una reserva (ej. confirmación)
booking.completedSe marca una reserva como completada
booking.cancelledSe cancela una reserva
*Todos los eventos

Ejemplo de payload (booking.created)

{
  "booking_id": "uuid",
  "order_id": "uuid",
  "kit_id": "uuid",
  "shop_id": "uuid",
  "booking_date": "2024-06-15",
  "booking_time": "10:00",
  "number_of_people": 2,
  "status": "pending",
  "payment_source": "external"
}

Configuración de endpoints

Puedes registrar tus endpoints de webhook vía API (scope webhooks:write):

  • POST /webhooks/endpoints — Crear endpoint. Body: { shop_id, url, events?: ["booking.created", "booking.updated", "booking.completed", "booking.cancelled", "*"] }. Devuelve signing_secret (guárdalo, no se muestra de nuevo).
  • GET /webhooks/endpoints — Listar endpoints. Query: shop_id (opcional).
  • PATCH /webhooks/endpoints/:id — Actualizar URL, eventos o status (active, paused, disabled).
  • DELETE /webhooks/endpoints/:id — Eliminar endpoint.

También puedes gestionarlos desde el panel seller: Mi local → API y webhooks → Webhooks.


Resumen de endpoints

MétodoRutaScope
GET/shopsshops:read
GET/shops/:idshops:read
GET/shops/:id/experiencesexperiences:read
GET/experiences/:idexperiences:read
GET/experiences/:id/extrasexperiences:read
GET/bookingsbookings:read
GET/bookings/:idbookings:read
POST/bookingsbookings:write
GET/webhooks/deliverieswebhooks:read
GET/webhooks/deliveries/:idwebhooks:read