API para Parceiros
Aulas de surf reais, numa chamada à API.
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.
API live · Bearer / X-Partner-API-Key
{
"spot": "Carcavelos",
"date": "2026-06-22",
"time": "10:00",
"level": "iniciante",
"capacity": 6,
"vacancy": 4
}Sem protocolo fechado. Falamos OCTO — o standard aberto das reservas de atividades.
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.
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.
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.
Pacotes com surf
Incluem aulas de surf em qualquer pacote, diretamente reserváveis via API, com idempotência em pedidos repetidos.
Surf no roteiro
Adicionam surf a qualquer roteiro e confirmam disponibilidade em tempo real, com vagas ao vivo.
Listagens + disponibilidade ao vivo
Mostram escolas, spots e disponibilidade ao vivo. Scope forecast adiciona condições por spot.
Upsell de experiências
Alojamento local e apartamentos fazem upsell de surf no checkout — confirmado em segundos via API.
Como funciona.
Uma integração. Todas as escolas da plataforma. Vagas reais, preços reais, anti-overbooking — confirmado em milissegundos.
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.
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.
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.
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.
Três coisas. Disponibilidade, serviços, reservas.
Tudo em REST + JSON, autenticado por chave da escola.
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.
Listar serviços
Os tipos de aula da escola (nível, grupo/privada, intervalo de preço) — em nativo SB ou como products OCTO.
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.
Uma chamada e vês a API a responder.
O descritor é público. Cola no terminal:
# 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).
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:
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.
Um assistente dentro da tua escola, com uma chave só tua.
Além da API de parceiros, cada escola pode ligar um assistente MCP à sua própria operação. Está desligado por defeito e ainda não foi validado com um cliente real.
/api/mcp/escola
JSON-RPC 2.0, protocolo MCP 2025-06-18. Cabeçalho Authorization: Bearer sbek_…. A escola vem sempre da chave, nunca dos argumentos.
/api/schools/:id/conector/tokens
Gera a chave com a sessão do dono. Corpo: label, role, staffId?, scopes (read, ou read e propose), expiresInDays (30, 90 ou 365). A chave vem uma única vez.
/api/schools/:id/conector/tokens/:tokenId
Revoga a chave e expira as propostas pendentes que ela pediu.
/api/schools/:id/conector/propostas/:pid/confirmar
Só o dono. Envia o payloadHash que viu; a mudança passa pelo mesmo caminho do painel, e uma aula que mudou entretanto fica em conflito.
Ferramentas: 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
Limites: 60 chamadas por minuto por chave e 2000 por dia. Sem ferramentas de dinheiro, e nada se aplica sem a confirmação do dono. O detalhe está na página MCP. /mcp
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:
Cabeçalho nativo SB
X-Partner-API-Key: sbpk_xxxx… — o formato canónico da SurfBooking.
Compatível OCTO
Authorization: Bearer sbpk_xxxx… — para clientes que falam OCTO. A mesma chave.
Gera e revoga chaves em Centro de Controlo → Canais de venda → API Parceiros. Nunca guardamos a chave em claro — só o seu resumo.
Os endpoints.
Base: https://www.surfbooking.eu/api/partner/v1
/
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.
/availabilities
Aulas reserváveis. Parâmetros: from, to, level?, format? (sb·fh·bl·octo). Defaults: from=hoje, to=+30 dias.
/availability
Alias OCTO de /availabilities — assume format=octo por defeito (plug-and-play OCTO).
/services
Tipos de aula da escola. format? (sb·octo) — em OCTO devolve products.
/products
Alias OCTO de /services — assume format=octo por defeito. Array de products OCTO.
/supplier
Identidade do fornecedor (descritor OCTO supplier): id, name, endpoint, contact, locales, timeZone.
/bookings
Cria reserva. Corpo: lessonSlotId, customerName, customerEmail, customerPhone?, participants?, externalRef?, notes?.
/bookings/:id
Consulta o estado de uma reserva.
/bookings/:id
Cancela uma reserva.
O descritor — GET /api/partner/v1 (sem chave):
{
"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):
{
"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": "…" }
}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:
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"
}'Resposta — 201 Created:
{
"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:
[
{
"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/…" }
}
]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):
{
"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" }
}Outro 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" }
}
]
}Outro 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" }
}
]
}Em octo a resposta é um array simples (sem envelope). Em sb/fh vem em availabilities; em bl, em data.
Códigos de estado.
Cada erro traz um corpo JSON { "error": "…" } — legível por máquina.
missing_api_key · invalid_api_key
Chave ausente, demasiado curta, inválida ou revogada. Inclui hint quando falta o cabeçalho.
missing_fields · invalid_email · invalid_date_range
Corpo incompleto, email malformado, ou intervalo de datas inválido (máx 180 dias, from ≤ to).
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.
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).
forbidden · not_owner
A chave é válida mas não alcança esse recurso: a reserva ou a aula é de outra escola. Uma chave só vê o que é da escola que a criou.
hold_expired
A reserva estava a aguardar confirmação e a janela passou. Não é um erro do teu lado: o lugar foi devolvido a quem o quiser. Cria outra vez.
rate_limit_exceeded
Acima de 120 pedidos/min por chave. Espera o Retry-After (60s). Cada resposta traz X-RateLimit-Remaining.
internal_error
Falhámos nós. Volta a tentar com o mesmo externalRef: a criação de reservas é idempotente por essa chave, portanto repetir não duplica nada.
Chave em falta ou inválida — 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:
# 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.
O que podes pedir, e quanto.
Por chave, não por parceiro
Cada resposta traz X-RateLimit-Limit e X-RateLimit-Remaining. Ao passar, um 429 com Retry-After: 60. Não é preciso adivinhar: os números vêm em todas as respostas.
É a página, e não há cursor
O intervalo from–to é o que limita a resposta; acima de 180 dias devolve 400. Não há paginação por cursor de propósito: uma aula tem data, e pedir por datas é a paginação natural deste domínio. Se precisares de mais, são dois pedidos.
Chaves activas por escola
Revoga as que não usas antes de criar novas. Uma chave revogada deixa de servir no pedido seguinte, sem espera.
Estes três números são lidos do código que serve a API, não escritos aqui à mão: se mudarem lá, esta página fica errada e há uma prova a dizê-lo.
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.
/sizing/board
Prancha recomendada por level + weight. Scope sizing.
/sizing/board/conditions
Prancha afinada ao dia: level, weight, swellPeriodS, swellDirectionDeg, bestSwellDirDeg. Scope sizing.
/sizing/wetsuit
Tamanho de fato por weight + height. Scope sizing.
/sizing/leash
Leash por boardSize + category (board·soft_board). Scope sizing.
/sizing/boots
Botas por shoeSizeEu (ex.: 42). Scope sizing.
/spots
Lista os spots que podes consultar — usa um id daqui em /conditions/:spotId. Scope forecast.
/conditions/:spotId
Condições do spot — a mesma shape pública, sanitizada (nunca expõe modelo nem fontes). Scope forecast.
/intelligence/surf-now
Os melhores spots do país agora, ordenados pelo score ao vivo — limit + level. Scope forecast.
/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.
/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:
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" } }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.
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.
<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).
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.
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 escola manda. Sempre.
Por escola, revogável
Cada chave vê só a oferta da própria escola. Revoga num clique e o acesso morre na hora.
Nunca há overbooking
Cada reserva revalida vagas e rácios de instrutor dentro de uma transação. Esgotado é esgotado.
Confirmado na SurfBooking
O fluxo de dinheiro fica do nosso lado — o parceiro encaminha, a SurfBooking confirma.
Dados protegidos
Só sai o necessário para a reserva. Os contactos dos teus alunos não viram lista de ninguém.
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

