API para socios
Clases de surf reales,en una llamada a la API.
Permite a tus clientes reservar clases de surf directamente en tu plataforma. REST · JSON · OCTO — disponibilidad real de cada escuela, legible por cualquier marketplace o channel manager. Conecta una vez, llega a muchos.
API activa · Bearer / X-Partner-API-Key
{
"spot": "Carcavelos",
"date": "2026-06-22",
"time": "10:00",
"level": "iniciante",
"capacity": 6,
"vacancy": 4
}Sin protocolo cerrado. Hablamos OCTO — el estándar abierto de las reservas de actividades. Integras una vez, llegas a todo el mundo.
OCTO (octo.travel) es como los sistemas de reservas, channel managers y marketplaces de actividades hablan entre sí. Una integración contra SurfBooking, y la oferta queda legible por cualquier comprador OCTO. Para quien lo prefiera, también devolvemos el formato nativo SB y variantes para adaptadores existentes.
Cinco tipos de socio. Una API.
Si distribuyes experiencias — un hotel, una agencia, un DMC, una app de turismo o una plataforma de alojamiento — la API de SurfBooking pone disponibilidad real de clases de surf en tus manos.
Experiencia en el check-in
Ofrecen clases de surf como extra al huésped, con reserva en tiempo real — sin llamadas, sin coordinación manual.
Paquetes con surf
Incluyen clases de surf en cualquier paquete, reservables directamente vía API, con idempotencia en peticiones repetidas.
Surf en el itinerario
Añaden surf a cualquier itinerario de grupo y confirman disponibilidad en tiempo real, con plazas libres en directo.
Listados + disponibilidad en directo
Muestran escuelas, spots y disponibilidad en directo. El scope forecast añade las condiciones por spot.
Upsell de experiencias
El alojamiento local y los apartamentos hacen upsell de surf en el checkout — confirmado en segundos vía API.
Cómo funciona.
Una integración. Todas las escuelas de la plataforma. Plazas reales, precios reales, anti-overbooking — confirmado en milisegundos.
Cada socio se conecta solo a lo que le sirve.
No es la misma API para todos. Cada clave está limitada (least-privilege) a lo que ese socio necesita — nunca más que eso.
Disponibilidad + reservas
Leen las clases disponibles y crean reservas en nombre del huésped/cliente. Camino v1 (OCTO). El acceso de quien distribuye clases.
Tallas + condiciones
Recomiendan la tabla/neopreno correctos y leen las condiciones del spot. Camino v2, con scope sizing y/o forecast — nunca tocan reservas.
Atribución, sin API
Traen clientes y cobran comisión vía /aff + cookie de 90 días. Sin clave, sin integración técnica.
Las claves de plataforma llevan scopes. Una clave de sizing solo abre los endpoints de sizing — todo lo demás devuelve 403 insufficient_scope.
Tres cosas. Disponibilidad, servicios, reservas.
Todo en REST + JSON, autenticado con la clave de la escuela.
Leer disponibilidad
Las clases reales con día, hora, spot, nivel, plazas y precio. Filtra por fecha y nivel. Formatos sb · fh · bl · octo.
Listar servicios
Los tipos de clase de la escuela (nivel, grupo/privada, rango de precio) — en nativo SB o como products OCTO.
Crear y gestionar reservas
Crea, consulta y cancela reservas en nombre del cliente final. Idempotente por externalRef, con revalidación de plazas y ratios.
Una llamada y ves la API responder.
El descriptor es público. Pégalo en el terminal:
# ver la API (sin clave) curl -s https://www.surfbooking.eu/api/partner/v1
Contrato completo, legible por máquina — pensado para que agentes de IA y generadores de SDK autodescubran la API: /openapi.json (OpenAPI 3.1) · referencia interactiva en /docs (Swagger UI).
Reserva en 2 pasos con 2 llamadas — bloquea la plaza mientras tu cliente paga, luego confirma:
# 1 — hold (expira sozinho; a vaga fica segura)
curl -X POST https://www.surfbooking.eu/api/partner/v1/bookings -H "X-Partner-API-Key: A_TUA_CHAVE" -H "Content-Type: application/json" -d '{"lessonSlotId":"…","customerName":"…","customerEmail":"…",
"status":"ON_HOLD","expirationMinutes":30}'
# 2 — confirm (idempotente; hold expirado devolve 410 e liberta a vaga)
curl -X POST https://www.surfbooking.eu/api/partner/v1/bookings/{id}/confirm -H "X-Partner-API-Key: A_TUA_CHAVE"
Con la clave de la escuela, lees la disponibilidad — aquí en formato OCTO:
curl -s "https://www.surfbooking.eu/api/partner/v1/availabilities?format=octo&from=2026-07-01&to=2026-07-07" \
-H "Authorization: Bearer sbpk_xxxxxxxxxxxxxxxxxxxxxxxx"Límite: 120 peticiones/min por clave. Cada respuesta trae X-RateLimit-Limit y X-RateLimit-Remaining; al excederlo recibes 429 con Retry-After: 60.
Un asistente dentro de tu escuela, con una clave solo tuya.
Además de la API de socios, cada escuela puede conectar un asistente MCP a su propia operación. Está desactivado por defecto y aún no se ha validado con un cliente real.
/api/mcp/escola
JSON-RPC 2.0, protocolo MCP 2025-06-18. Cabecera Authorization: Bearer sbek_…. La escuela sale siempre de la clave, nunca de los argumentos.
/api/schools/:id/conector/tokens
Genera la clave con la sesión del propietario. Cuerpo: label, role, staffId?, scopes (read, o read y propose), expiresInDays (30, 90 o 365). La clave se devuelve una sola vez.
/api/schools/:id/conector/tokens/:tokenId
Revoca la clave y caduca las propuestas pendientes que pidió.
/api/schools/:id/conector/propostas/:pid/confirmar
Solo el propietario. Envía el payloadHash que vio; el cambio pasa por el mismo camino que el panel, y una clase que cambió entretanto queda en conflicto.
Herramientas: list_my_schools · get_school_briefing · get_school_schedule · get_bookings_summary · get_lesson_roster · get_stock_summary · get_conditions_for_my_lessons · review_week_with_sea · prepare_lesson_move · prepare_stock_change · list_pending_proposals
Límites: 60 llamadas por minuto por clave y 2000 al día. Sin herramientas de dinero, y nada se aplica sin la confirmación del propietario. El detalle está en la página MCP. /mcp
Una clave por escuela. Tú mandas.
Cada escuela genera su propia clave en SurfBooking OS — y la revoca cuando quiera. La clave va en una cabecera, en cualquiera de los dos formatos:
Cabecera nativa SB
X-Partner-API-Key: sbpk_xxxx… — el formato canónico de SurfBooking.
Compatible con OCTO
Authorization: Bearer sbpk_xxxx… — para clientes que hablan OCTO. La misma clave.
Genera y revoca claves en SurfBooking OS → Canales de venta → API Socios. Nunca guardamos la clave en claro — solo su resumen.
Los endpoints.
Base: https://www.surfbooking.eu/api/partner/v1
/
Descriptor de la API (raíz, sin clave). Devuelve name, version, auth, octo y el mapa completo de endpoints. Abrirlo en el navegador redirige a esta página.
/availabilities
Clases reservables. Parámetros: from, to, level?, format? (sb·fh·bl·octo). Por defecto: from=hoy, to=+30 días.
/availability
Alias OCTO de /availabilities — asume format=octo por defecto (plug-and-play OCTO).
/services
Tipos de clase de la escuela. format? (sb·octo) — en OCTO devuelve products.
/products
Alias OCTO de /services — asume format=octo por defecto. Array de products OCTO.
/supplier
Identidad del proveedor (descriptor OCTO supplier): id, name, endpoint, contact, locales, timeZone.
/bookings
Crea una reserva. Cuerpo: lessonSlotId, customerName, customerEmail, customerPhone?, participants?, externalRef?, notes?.
/bookings/:id
Consulta el estado de una reserva.
/bookings/:id
Cancela una reserva.
El descriptor — GET /api/partner/v1 (sin clave):
{
"name": "SurfBooking Partner API v1",
"version": "1.0.0",
"auth": "X-Partner-API-Key header, ou Authorization: Bearer (compatível OCTO).",
"octo": {
"supported": true,
"formatParam": "octo",
"supplierEndpoint": "/api/partner/v1/supplier"
},
"endpoints": {
"availabilities": { "method": "GET", "path": "/api/partner/v1/availabilities" },
"services": { "method": "GET", "path": "/api/partner/v1/services" },
"supplier": { "method": "GET", "path": "/api/partner/v1/supplier" },
"createBooking": { "method": "POST", "path": "/api/partner/v1/bookings" },
"getBooking": { "method": "GET", "path": "/api/partner/v1/bookings/:id" },
"cancelBooking": { "method": "DELETE", "path": "/api/partner/v1/bookings/:id" }
}
} Identidad del proveedor — GET /supplier (OCTO):
{
"id": "school-uuid-…",
"name": "Nome da Escola",
"endpoint": "https://www.surfbooking.eu/api/partner/v1",
"contact": { "website": "https://www.surfbooking.eu", "email": null, "telephone": null, "address": null },
"locales": ["pt", "en"],
"timeZone": "Europe/Lisbon",
"_sb": { "description": "…", "logoUrl": "…" }
}Petición y respuesta, de verdad.
El cuerpo de una reserva y lo que recibes de vuelta — tal como la API responde hoy.
Crear una reserva — POST /bookings:
curl -s -X POST https://www.surfbooking.eu/api/partner/v1/bookings \
-H "Authorization: Bearer sbpk_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"lessonSlotId": "a1b2c3d4-…",
"customerName": "Ana Silva",
"customerEmail": "[email protected]",
"customerPhone": "+351912345678",
"participants": 2,
"externalRef": "EXT-7782",
"notes": "Primeira aula"
}'Respuesta — 201 Created:
{
"ok": true,
"bookingId": "f1e2d3c4-…",
"createdAt": "2026-06-21T11:42:00.000Z",
"lessonSlotId": "a1b2c3d4-…",
"schoolId": "…",
"status": "confirmed",
"participants": 2,
"totalAmountCents": 7000,
"currency": "EUR"
}Disponibilidad en OCTO — GET /availabilities?format=octo devuelve un array:
[
{
"id": "a1b2c3d4-…",
"localDateTimeStart": "2026-07-02T10:00:00",
"localDateTimeEnd": "2026-07-02T12:00:00",
"available": true,
"status": "AVAILABLE",
"vacancies": 4,
"capacity": 6,
"maxUnits": 4,
"pricing": {
"original": 3500, "retail": 3500, "net": 3500,
"currency": "EUR", "currencyPrecision": 2
},
"_sb": { "level": "beginner", "spotName": "…", "bookingUrl": "https://www.surfbooking.eu/aula/…" }
}
]Precios en céntimos (minor units) — 3500 = 35,00 €, conforme al currencyPrecision: 2 de OCTO. Las fechas vienen en hora local de la escuela (Europe/Lisbon).
La misma disponibilidad en otros formatos. Nativo SB — ?format=sb (envelope con _meta):
{
"availabilities": [
{
"id": "a1b2c3d4-…",
"date": "2026-07-02",
"startTime": "10:00",
"endTime": "12:00",
"level": "beginner",
"spotsTotal": 6,
"spotsRemaining": 4,
"pricePerPerson": 3500,
"currency": "EUR",
"instructorName": "…",
"spotName": "…",
"schoolId": "…",
"schoolName": "…",
"bookingUrl": "https://www.surfbooking.eu/aula/9f3c1a2b7d"
}
],
"_meta": { "format": "sb", "total": 1, "from": "2026-07-01", "to": "2026-07-07" }
}Otro sistema de reservas — ?format=fh (envelope availabilities):
{
"availabilities": [
{
"pk": "a1b2c3d4-…",
"start_at": "2026-07-02T10:00:00",
"end_at": "2026-07-02T12:00:00",
"capacity": 6,
"num_remaining": 4,
"is_available": true,
"customer_type_rates": [
{ "pk": "a1b2c3d4-…_default", "total": { "amount": "35.00", "currency": "EUR" } }
],
"_sb_meta": { "level": "beginner", "bookingUrl": "https://www.surfbooking.eu/aula/9f3c1a2b7d" }
}
]
}Otro sistema de reservas — ?format=bl (envelope data):
{
"data": [
{
"id": "a1b2c3d4-…",
"date": "2026-07-02",
"startTime": "10:00",
"endTime": "12:00",
"serviceName": "Surf beginner",
"capacity": 6,
"spotsLeft": 4,
"pricePerPerson": 3500,
"currency": "EUR",
"_sb_meta": { "level": "beginner", "bookingUrl": "https://www.surfbooking.eu/aula/9f3c1a2b7d" }
}
]
}En octo la respuesta es un array simple (sin envelope). En sb/fh viene en availabilities; en bl, en data.
Códigos de estado.
Cada error trae un cuerpo JSON { "error": "…" } — legible por máquina.
missing_api_key · invalid_api_key
Clave ausente, demasiado corta, inválida o revocada. Incluye un hint cuando falta la cabecera.
missing_fields · invalid_email · invalid_date_range
Cuerpo incompleto, email mal formado, o intervalo de fechas inválido (máx 180 días, from ≤ to).
slot_not_found · booking_not_found · booking_not_found_or_already_cancelled
La clase o la reserva no existe en esta escuela — o, en el DELETE, ya había sido cancelada.
insufficient_spots · slot_expired · slot_not_purchasable · ratio_exceeded · external_ref_exists
Conflicto de estado: sin plazas, clase en el pasado, cerrada a la venta, ratio de instructor excedido, o externalRef repetido (idempotencia — devuelve el bookingId que ya existe).
forbidden · not_owner
La clave es válida pero no alcanza ese recurso: la reserva o la clase es de otra escuela. Una clave solo ve lo de la escuela que la creó.
hold_expired
La reserva estaba esperando confirmación y la ventana pasó. No es un error tuyo: la plaza volvió a quien la quiera. Créala de nuevo.
rate_limit_exceeded
Por encima de 120 peticiones/min por clave. Espera el Retry-After (60s). Cada respuesta trae X-RateLimit-Remaining.
internal_error
Ese es nuestro. Reintenta con el mismo externalRef: crear reservas es idempotente por esa clave, así que repetir no duplica nada.
Clave ausente o inválida — 401:
# sin cabecera de clave { "error": "missing_api_key", "hint": "Set X-Partner-API-Key header (or Authorization: Bearer)" } # clave inexistente o revocada { "error": "invalid_api_key" }
Sin plazas suficientes (anti-overbooking) — 409:
# la clase ya no tiene plazas para el nº de participantes { "error": "insufficient_spots", "remaining": 1 } # externalRef repetido → idempotencia: devuelve el bookingId existente { "error": "external_ref_exists", "bookingId": "f1e2d3c4-…" }
La revalidación de plazas y ratios corre dentro de una transacción con SELECT … FOR UPDATE — agotado es agotado, nunca hay doble reserva.
Lo que puedes pedir, y cuánto.
Por clave, no por socio
Cada respuesta trae X-RateLimit-Limit y X-RateLimit-Remaining. Al pasarte, un 429 con Retry-After: 60. Sin adivinar: los números viajan en cada respuesta.
Esa es la página, y no hay cursor
El intervalo from–to es lo que limita la respuesta; por encima de 180 días devuelve 400. No hay paginación por cursor a propósito: una clase tiene fecha, y pedir por fechas es la paginación natural de este dominio. Si necesitas más, son dos peticiones.
Claves activas por escuela
Revoca las que no usas antes de crear nuevas. Una clave revocada deja de servir en la petición siguiente, sin espera.
Estos tres números se leen del código que sirve la API, no se escriben aquí a mano: si cambian allí, esta página queda mal y hay una prueba que lo dice.
Recomienda el equipo correcto. Sin tocar las reservas.
El camino v2 para marcas de equipamiento, apps e IA. Clave de plataforma con scope sizing, forecast y/o brand:read — determinista, sin datos personales, nunca toca reservas. Descubre tus scopes en /api/partner/v2/meta. Base: https://www.surfbooking.eu/api/partner/v2.
/sizing/board
Tabla recomendada por level + weight. Scope sizing.
/sizing/board/conditions
Tabla ajustada al día: level, weight, swellPeriodS, swellDirectionDeg, bestSwellDirDeg. Scope sizing.
/sizing/wetsuit
Talla de neopreno por weight + height. Scope sizing.
/sizing/leash
Leash por boardSize + category (board·soft_board). Scope sizing.
/sizing/boots
Botas por shoeSizeEu (ej.: 42). Scope sizing.
/spots
Lista los spots que puedes consultar — usa un id de aquí en /conditions/:spotId. Scope forecast.
/conditions/:spotId
Condiciones del spot — la misma shape pública, sanitizada (nunca expone el modelo ni las fuentes). Scope forecast.
/intelligence/surf-now
Los mejores spots del país ahora mismo, ordenados por el score en directo — limit + level. Scope forecast.
/brand/equipment-stats
Para marcas de equipamiento: cuántas veces se usó en clases cada talla de tu marca, por month (YYYY-MM). Solo tus datos. Scope brand:read.
/brand/spot-activity
En qué spots se usó más el equipamiento de tu marca, últimos months (1–12). Scope brand:read.
Recomendación de tabla — GET /sizing/board:
curl -s "https://www.surfbooking.eu/api/partner/v2/sizing/board?level=beginner&weight=75" \
-H "X-Partner-API-Key: sbpd_xxxxxxxxxxxxxxxxxxxxxxxx"{ "recommendation": { "category": "soft_board", "size": "8'0" } }Las claves de plataforma (sbpd_…) las emite SurfBooking, no la escuela. Scope equivocado → 403 insufficient_scope. Límite 240 peticiones/min por clave, con Retry-After: 60 al excederlo.
Tallas en tu web. Una línea.
Una página iframe autocontenida, "Powered by SurfBooking". Muestra las condiciones del spot, recomienda la tabla por peso y nivel, y lleva al cliente a reservar una clase — con tu enlace de socio premium incorporado. Sin PII, sin cookies de seguimiento.
<iframe
src="https://www.surfbooking.eu/w/surf?key=sbpd_xxxx&spot=SPOT_ID&slug=O_TEU_SLUG"
width="360" height="520" frameborder="0"></iframe>key = tu clave de plataforma (scope sizing, y forecast si quieres las condiciones arriba). spot y slug son opcionales — el slug liga las reservas generadas a tu /aff (cookie de 90 días).
v1 — estable.
La base es /api/partner/v1. Los cambios que rompen compatibilidad entran en una versión nueva (/v2) — la v1 no tiene depreciación prevista. Podemos añadir campos sin aviso, así que lee de forma tolerante: ignora lo que aún no conozcas.
Channel managers, marketplaces, hoteles.
Cualquier socio que quiera vender o mostrar clases de surf reales. Diseñado sobre el estándar abierto OCTO, que muchos sistemas de reservas y channel managers ya hablan.
Hoteles & resorts
Ofrece clases de verdad a tus huéspedes sin gestionar nada — la reserva y el pago se quedan en SurfBooking.
Channel managers
Sincroniza la disponibilidad en tiempo real, sin doble reserva. OCTO de fábrica.
Marketplaces
Lista la oferta de las escuelas y encamina la reserva — con plazas y ratios siempre revalidados de nuestro lado.
La escuela manda. Siempre.
Por escuela, revocable
Cada clave ve solo la oferta de su propia escuela. Revócala con un clic y el acceso muere al instante.
Nunca hay overbooking
Cada reserva revalida plazas y ratios de instructor dentro de una transacción. Agotado es agotado.
Confirmado en SurfBooking
El flujo de dinero se queda de nuestro lado — el socio encamina, SurfBooking confirma.
Datos protegidos
Solo sale lo necesario para la reserva. Los contactos de tus alumnos no acaban en la lista de nadie.
Consigue una clave y empieza.
La API está viva. Si tienes una escuela de surf, generas tu propia clave en el SurfBooking OS. Si eres socio externo — marca de material, app, IA u hotel — pides una clave de plataforma (emitida por SurfBooking).
Soy escuela · Abrir el SurfBooking OS Soy socio externo · Pedir acceso Ver el descriptor

