Surf Booking.ENOCTO
ManifestoAgenteCamada InteligenteTecnologiaConstituiçãoIAMCPPartner API
API para Parceiros

Uma integração.Mil canais.

Permite aos teus clientes reservar aulas de surf diretamente na tua plataforma. REST · JSON · OCTO — disponibilidade real de cada escola, legível por qualquer marketplace ou channel manager. Liga uma vez, chega a muitos.

API live · Bearer / X-Partner-API-Key
surfbooking.eu/developers
/api/partner/v1/availabilities
GET
{
  "spot":     "Carcavelos",
  "date":     "2026-06-22",
  "time":     "10:00",
  "level":    "iniciante",
  "capacity": 6,
  "vacancy":  4
}
Plataforma aberta

Sem protocolo fechado. Falamos OCTO — o standard aberto das reservas de atividades. Integras uma vez, chegas a toda a gente.

OCTO (octo.travel) é como os sistemas de reservas, channel managers e marketplaces de atividades falam entre si. Uma integração contra a SurfBooking, e a oferta fica legível por qualquer comprador OCTO. Para quem prefere, também devolvemos o formato nativo SB e variantes para adaptadores existentes.

Quem liga

Cinco tipos de parceiro. Uma API.

Se distribuis experiências — um hotel, uma agência, um DMC, uma app de turismo ou uma plataforma de alojamento — a API da SurfBooking coloca disponibilidade real de aulas de surf nas tuas mãos.

Hotéis

Experiência no check-in

Oferecem aulas de surf como extra ao hóspede, com reserva em tempo real — sem telefonemas, sem coordenação manual.

Agências de viagem

Pacotes com surf

Incluem aulas de surf em qualquer pacote, diretamente reserváveis via API, com idempotência em pedidos repetidos.

DMCs

Surf no roteiro

Adicionam surf a qualquer roteiro e confirmam disponibilidade em tempo real, com vagas ao vivo.

Apps de turismo

Listagens + disponibilidade ao vivo

Mostram escolas, spots e disponibilidade ao vivo. Scope forecast adiciona condições por spot.

Alojamento

Upsell de experiências

Alojamento local e apartamentos fazem upsell de surf no checkout — confirmado em segundos via API.

Como funciona

Em 5 segundos, qualquer CTO percebe.

A tua plataforma
Hotel · OTA · Agência · App
SurfBooking API
REST · JSON · OCTO
Escolas
Disponibilidade
Pagamentos
Reservas

Uma integração. Todas as escolas da plataforma. Vagas reais, preços reais, anti-overbooking — confirmado em milissegundos.

Parceiros diferentes, acessos diferentes

Cada parceiro liga só ao que lhe serve.

Não é a mesma API para todos. Cada chave é limitada (least-privilege) ao que esse parceiro precisa — nunca mais do que isso.

Hotéis · OTAs · channel managers

Disponibilidade + reservas

Lêem as aulas disponíveis e criam reservas em nome do hóspede/cliente. Caminho v1 (OCTO). O acesso de quem distribui aulas.

Marcas de equipamento · apps · IA

Sizing + condições

Recomendam a prancha/fato certos e lêem as condições do spot. Caminho v2, com scope sizing e/ou forecast — nunca tocam em reservas.

Parceiros

Atribuição, sem API

Trazem clientes e recebem comissão via /aff + cookie de 90 dias. Sem chave, sem integração técnica.

As chaves de plataforma carregam scopes. Uma chave de sizing só abre os endpoints de sizing — tudo o resto devolve 403 insufficient_scope.

O que a API faz

Três coisas. Disponibilidade, serviços, reservas.

Tudo em REST + JSON, autenticado por chave da escola.

availabilities

Ler disponibilidade

As aulas reais com dia, hora, spot, nível, vagas e preço. Filtra por data e nível. Formatos sb · fh · bl · octo.

services

Listar serviços

Os tipos de aula da escola (nível, grupo/privada, intervalo de preço) — em nativo SB ou como products OCTO.

bookings

Criar e gerir reservas

Cria, consulta e cancela reservas em nome do cliente final. Idempotente por externalRef, com revalidação de vagas e rácios.

Ao vivo

Uma chamada e vês a API a responder.

O descritor é público. Cola no terminal:

terminal · descritor da API
# ver a API (sem chave)
curl -s https://www.surfbooking.eu/api/partner/v1

Contrato completo, máquina-legível — pensado para agentes de IA e geradores de SDK auto-descobrirem a API: /openapi.json (OpenAPI 3.1) · referência interativa em /docs (Swagger UI).

OCTO
Para OTAs e revendedores
Produtos, disponibilidade e reserva em 2 passos (hold → confirm). Plug-and-play estilo Bókun/Rezdy.
iCal
Universal, nos dois sentidos
Importa o feed de qualquer canal para o calendário SB — e exporta o calendário SB (com cancelamentos) de volta para o canal.
MCP
Para agentes de IA
11 ferramentas — procurar aulas, score de surf ao vivo por pico, tamanhos de material — via Model Context Protocol.

Reserva em 2 passos com 2 chamadas — segura a vaga enquanto o teu cliente paga, depois 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"

Com a chave da escola, lês a disponibilidade — aqui em formato OCTO:

terminal · disponibilidade (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"

Limite: 120 pedidos/min por chave. Cada resposta traz X-RateLimit-Limit e X-RateLimit-Remaining; ao exceder recebes 429 com Retry-After: 60.

Autenticação

Uma chave por escola. Tu controlas.

Cada escola gera a sua própria chave no Centro de Controlo — e revoga-a quando quiser. A chave segue num cabeçalho, em qualquer um dos dois formatos:

X-Partner-API-Key

Cabeçalho nativo SB

X-Partner-API-Key: sbpk_xxxx… — o formato canónico da SurfBooking.

Authorization: Bearer

Compatível OCTO

Authorization: Bearer sbpk_xxxx… — para clientes que falam OCTO. A mesma chave.

Gera e revoga chaves em Centro de Controlo → Canais Externos → API Parceiros. Nunca guardamos a chave em claro — só o seu resumo.

Referência

Os endpoints.

Base: https://www.surfbooking.eu/api/partner/v1

GET

/

Descritor da API (raiz, sem chave). Devolve name, version, auth, octo e o mapa completo de endpoints. Abrir no browser redireciona para esta página.

GET

/availabilities

Aulas reserváveis. Parâmetros: from, to, level?, format? (sb·fh·bl·octo). Defaults: from=hoje, to=+30 dias.

GET

/availability

Alias OCTO de /availabilities — assume format=octo por defeito (plug-and-play OCTO).

GET

/services

Tipos de aula da escola. format? (sb·octo) — em OCTO devolve products.

GET

/products

Alias OCTO de /services — assume format=octo por defeito. Array de products OCTO.

GET

/supplier

Identidade do fornecedor (descritor OCTO supplier): id, name, endpoint, contact, locales, timeZone.

POST

/bookings

Cria reserva. Corpo: lessonSlotId, customerName, customerEmail, customerPhone?, participants?, externalRef?, notes?.

GET

/bookings/:id

Consulta o estado de uma reserva.

DELETE

/bookings/:id

Cancela uma reserva.

O descritor — GET /api/partner/v1 (sem chave):

resposta · descritor
{
  "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" }
  }
}

Identidade do fornecedor — GET /supplier (OCTO):

resposta · 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": "…" }
}
Exemplos

Pedido e resposta, a sério.

O corpo de uma reserva e o que recebes de volta — tal como a API responde hoje.

Criar uma reserva — POST /bookings:

pedido · 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": "BOKUN-7782",
    "notes": "Primeira aula"
  }'

Resposta — 201 Created:

resposta · 201
{
  "ok": true,
  "bookingId": "f1e2d3c4-…",
  "createdAt": "2026-06-21T11:42:00.000Z",
  "lessonSlotId": "a1b2c3d4-…",
  "schoolId": "…",
  "status": "confirmed",
  "participants": 2,
  "totalAmountCents": 7000,
  "currency": "EUR"
}

Disponibilidade em OCTO — GET /availabilities?format=octo devolve um array:

resposta · availabilities (OCTO)
[
  {
    "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/aulas/…" }
  }
]

Preços em cents (minor units) — 3500 = 35,00 €, conforme currencyPrecision: 2 do OCTO. As datas vêm em hora local da escola (Europe/Lisbon).

A mesma disponibilidade noutros formatos. Nativo SB — ?format=sb (envelope com _meta):

resposta · availabilities (SB)
{
  "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/aulas/a1b2c3d4-…"
    }
  ],
  "_meta": { "format": "sb", "total": 1, "from": "2026-07-01", "to": "2026-07-07" }
}

FareHarbor — ?format=fh (envelope availabilities):

resposta · availabilities (FH)
{
  "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/aulas/a1b2c3d4-…" }
    }
  ]
}

Booking Layer — ?format=bl (envelope data):

resposta · availabilities (BL)
{
  "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/aulas/a1b2c3d4-…" }
    }
  ]
}

Em octo a resposta é um array simples (sem envelope). Em sb/fh vem em availabilities; em bl, em data.

Erros

Códigos de estado.

Cada erro traz um corpo JSON { "error": "…" } — legível por máquina.

401

missing_api_key · invalid_api_key

Chave ausente, demasiado curta, inválida ou revogada. Inclui hint quando falta o cabeçalho.

400

missing_fields · invalid_email · invalid_date_range

Corpo incompleto, email malformado, ou intervalo de datas inválido (máx 180 dias, from ≤ to).

404

slot_not_found · booking_not_found · booking_not_found_or_already_cancelled

A aula ou a reserva não existe nesta escola — ou, no DELETE, já tinha sido cancelada.

409

insufficient_spots · slot_expired · slot_not_purchasable · ratio_exceeded · external_ref_exists

Conflito de estado: sem vagas, aula no passado, fechada à venda, rácio de instrutor excedido, ou externalRef repetido (idempotência — devolve o bookingId que já existe).

429

rate_limit_exceeded

Acima de 120 pedidos/min por chave. Espera o Retry-After (60s). Cada resposta traz X-RateLimit-Remaining.

Chave em falta ou inválida — 401:

resposta · 401
# sem cabeçalho de chave
{
  "error": "missing_api_key",
  "hint": "Set X-Partner-API-Key header (or Authorization: Bearer)"
}

# chave inexistente ou revogada
{ "error": "invalid_api_key" }

Sem vagas suficientes (anti-overbooking) — 409:

resposta · 409
# a aula já não tem lugares para o nº de participantes
{
  "error": "insufficient_spots",
  "remaining": 1
}

# externalRef repetido → idempotência: devolve o bookingId existente
{
  "error": "external_ref_exists",
  "bookingId": "f1e2d3c4-…"
}

A revalidação de vagas e rácios corre dentro de uma transação com SELECT … FOR UPDATE — esgotado é esgotado, nunca há dupla-marcação.

Sizing + condições · v2

Recomenda o equipamento certo. Sem tocar em reservas.

O caminho v2 para marcas de equipamento, apps e IA. Chave de plataforma com scope sizing, forecast e/ou brand:read — determinístico, sem dados pessoais, nunca toca em reservas. Descobre os teus scopes em /api/partner/v2/meta. Base: https://www.surfbooking.eu/api/partner/v2.

GET

/sizing/board

Prancha recomendada por level + weight. Scope sizing.

GET

/sizing/board/conditions

Prancha afinada ao dia: level, weight, swellPeriodS, swellDirectionDeg, bestSwellDirDeg. Scope sizing.

GET

/sizing/wetsuit

Tamanho de fato por weight + height. Scope sizing.

GET

/sizing/leash

Leash por boardSize + category (board·soft_board). Scope sizing.

GET

/sizing/boots

Botas por shoeSizeEu (ex.: 42). Scope sizing.

GET

/spots

Lista os spots que podes consultar — usa um id daqui em /conditions/:spotId. Scope forecast.

GET

/conditions/:spotId

Condições do spot — a mesma shape pública, sanitizada (nunca expõe modelo nem fontes). Scope forecast.

GET

/intelligence/surf-now

Os melhores spots do país agora, ordenados pelo score ao vivo — limit + level. Scope forecast.

GET

/brand/equipment-stats

Para marcas de equipamento: quantas vezes cada tamanho da tua marca foi usado em aulas, por month (YYYY-MM). Só os teus dados. Scope brand:read.

GET

/brand/spot-activity

Em que spots o equipamento da tua marca foi mais usado, últimos months (1–12). Scope brand:read.

Recomendação de prancha — GET /sizing/board:

terminal · sizing (v2)
curl -s "https://www.surfbooking.eu/api/partner/v2/sizing/board?level=beginner&weight=75" \
  -H "X-Partner-API-Key: sbpd_xxxxxxxxxxxxxxxxxxxxxxxx"
resposta · sizing
{ "recommendation": { "category": "soft_board", "size": "8'0" } }

As chaves de plataforma (sbpd_…) são emitidas pela SurfBooking, não pela escola. Scope errado → 403 insufficient_scope. Limite 240 pedidos/min por chave, com Retry-After: 60 ao exceder.

Widget embedável

Sizing no teu site. Uma linha.

Uma página iframe self-contained, "Powered by SurfBooking". Mostra as condições do pico, recomenda a prancha pelo peso e nível, e leva o cliente a reservar uma aula — com o teu link de parceiro premium embutido. PII-free, sem cookies de seguimento.

Exemplo ao vivo — é exatamente isto que os teus visitantes veem:
html · embed
<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 = a tua chave de plataforma (scope sizing, e forecast se quiseres as condições no topo). spot e slug são opcionais — o slug liga as reservas geradas ao teu /aff (cookie de 90 dias).

Versões

v1 — estável.

A base é /api/partner/v1. Mudanças que quebram compatibilidade entram numa versão nova (/v2) — a v1 não tem depreciação prevista. Podemos acrescentar campos sem aviso, por isso lê de forma tolerante: ignora o que ainda não conheces.

Para quem

Channel managers, marketplaces, hotéis.

Qualquer parceiro que queira vender ou mostrar aulas de surf reais. Desenhado no padrão aberto OCTO, que muitos sistemas de reservas e channel managers já falam.

Hotéis & resorts

Oferece aulas reais aos hóspedes sem gerir nada — a reserva e o pagamento ficam na SurfBooking.

Channel managers

Sincroniza a disponibilidade em tempo real, sem dupla-marcação. OCTO de fábrica.

Marketplaces

Lista a oferta das escolas e encaminha a reserva — com vagas e rácios sempre revalidados do nosso lado.

A tua segurança

A escola manda. Sempre.

CHAVE

Por escola, revogável

Cada chave vê só a oferta da própria escola. Revoga num clique e o acesso morre na hora.

VAGAS

Nunca há overbooking

Cada reserva revalida vagas e rácios de instrutor dentro de uma transação. Esgotado é esgotado.

PAGAMENTO

Confirmado na SurfBooking

O fluxo de dinheiro fica do nosso lado — o parceiro encaminha, a SurfBooking confirma.

ALUNOS

Dados protegidos

Só sai o necessário para a reserva. Os contactos dos teus alunos não viram lista de ninguém.

Pronto a ligar

Arranja uma chave e começa.

A API está viva. Se tens uma escola de surf, geras a tua própria chave no Centro de Controlo. Se és parceiro externo — marca de equipamento, app, IA ou hotel — pedes uma chave de plataforma (emitida pela SurfBooking).

Sou escola · Abrir o Centro de Controlo Sou parceiro externo · Pedir acesso Ver o descritor