Let your customers book surf lessons directly in your platform. REST · JSON · OCTO — real availability from every school, readable by any marketplace or channel manager. Connect once, reach many.
{
"spot": "Carcavelos",
"date": "2026-06-22",
"time": "10:00",
"level": "iniciante",
"capacity": 6,
"vacancy": 4
}No closed protocol. We speak OCTO — the open standard for activity bookings. Integrate once, reach everyone.
OCTO (octo.travel) is how activity booking systems, channel managers and marketplaces talk to each other. One integration against SurfBooking, and your offer becomes readable by any OCTO buyer. For those who prefer, we also return the native SB format and variants for existing adapters.
If you distribute experiences — a hotel, an agency, a DMC, a tourism app or an accommodation platform — the SurfBooking API puts real-time surf lesson availability in your hands.
Offer surf lessons as an add-on for guests, with real-time booking — no phone calls, no manual coordination.
Include surf lessons in any travel package, bookable directly via API, with idempotency on duplicate requests.
Add surf to any group itinerary and confirm real-time availability, with live opening counts.
Show schools, spots and live availability in your app. The forecast scope adds surf conditions per spot.
Short-term rentals and apartments upsell surf at checkout — confirmed in seconds via API, no manual back-and-forth.
One integration. Every school on the platform. Real openings, real prices, anti-overbooking — confirmed in milliseconds.
It's not the same API for everyone. Each key is limited (least-privilege) to what that partner needs — never more than that.
They read the available lessons and create bookings on behalf of the guest/customer. The v1 path (OCTO). Access for those who distribute lessons.
They recommend the right board/wetsuit and read the spot conditions. The v2 path, with scope sizing and/or forecast — they never touch bookings.
They bring customers and earn commission via /aff + a 90-day cookie. No key, no technical integration.
Platform keys carry scopes. A sizing key only opens the sizing endpoints — everything else returns 403 insufficient_scope.
All in REST + JSON, authenticated by the school's key.
The real lessons with day, time, spot, level, openings and price. Filter by date and level. Formats sb · fh · bl · octo.
The school's lesson types (level, group/private, price range) — in native SB or as OCTO products.
Create, query and cancel bookings on behalf of the end customer. Idempotent by externalRef, with revalidation of openings and ratios.
The descriptor is public. Paste into the terminal:
# view the API (no key) curl -s https://www.surfbooking.eu/api/partner/v1
Full, machine-readable contract — designed for AI agents and SDK generators to auto-discover the API: /openapi.json (OpenAPI 3.1) · interactive reference at /docs (Swagger UI).
Two-step booking in two calls — hold the spot while your customer pays, then confirm:
# 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"
With the school's key, you read the availability — here in OCTO format:
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"Limit: 120 requests/min per key. Each response carries X-RateLimit-Limit and X-RateLimit-Remaining; when you exceed it you get 429 with Retry-After: 60.
Each school generates its own key in SurfBooking OS — and revokes it whenever it wants. The key goes in a header, in either of two formats:
X-Partner-API-Key: sbpk_xxxx… — SurfBooking's canonical format.
Authorization: Bearer sbpk_xxxx… — for clients that speak OCTO. The same key.
Generate and revoke keys in SurfBooking OS → External Channels → Partner API. We never store the key in plaintext — only its digest.
Base: https://www.surfbooking.eu/api/partner/v1
API descriptor (root, no key). Returns name, version, auth, octo and the full map of endpoints. Opening it in a browser redirects to this page.
Bookable lessons. Parameters: from, to, level?, format? (sb·fh·bl·octo). Defaults: from=today, to=+30 days.
OCTO alias of /availabilities — assumes format=octo by default (plug-and-play OCTO).
The school's lesson types. format? (sb·octo) — in OCTO it returns products.
OCTO alias of /services — assumes format=octo by default. Array of OCTO products.
Supplier identity (OCTO supplier descriptor): id, name, endpoint, contact, locales, timeZone.
Creates a booking. Body: lessonSlotId, customerName, customerEmail, customerPhone?, participants?, externalRef?, notes?.
Queries the state of a booking.
Cancels a booking.
The descriptor — GET /api/partner/v1 (no key):
{
"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" }
}
} Supplier identity — 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": "…" }
}The body of a booking and what you get back — exactly as the API responds today.
Create a booking — 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"
}'Response — 201 Created:
{
"ok": true,
"bookingId": "f1e2d3c4-…",
"createdAt": "2026-06-21T11:42:00.000Z",
"lessonSlotId": "a1b2c3d4-…",
"schoolId": "…",
"status": "confirmed",
"participants": 2,
"totalAmountCents": 7000,
"currency": "EUR"
}Availability in OCTO — GET /availabilities?format=octo returns an 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/aulas/…" }
}
]Prices in cents (minor units) — 3500 = €35.00, per OCTO's currencyPrecision: 2. Dates come in the school's local time (Europe/Lisbon).
The same availability in other formats. Native SB — ?format=sb (envelope with _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/aulas/a1b2c3d4-…"
}
],
"_meta": { "format": "sb", "total": 1, "from": "2026-07-01", "to": "2026-07-07" }
}FareHarbor — ?format=fh (availabilities envelope):
{
"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 (data envelope):
{
"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-…" }
}
]
}In octo the response is a plain array (no envelope). In sb/fh it comes in availabilities; in bl, in data.
Each error carries a JSON body { "error": "…" } — machine-readable.
Key missing, too short, invalid or revoked. Includes a hint when the header is missing.
Incomplete body, malformed email, or invalid date range (max 180 days, from ≤ to).
The lesson or booking doesn't exist at this school — or, on DELETE, it had already been cancelled.
State conflict: no openings, lesson in the past, closed to sale, instructor ratio exceeded, or repeated externalRef (idempotency — returns the bookingId that already exists).
Above 120 requests/min per key. Wait for Retry-After (60s). Each response carries X-RateLimit-Remaining.
Missing or invalid key — 401:
# no key header { "error": "missing_api_key", "hint": "Set X-Partner-API-Key header (or Authorization: Bearer)" } # nonexistent or revoked key { "error": "invalid_api_key" }
Not enough openings (anti-overbooking) — 409:
# the lesson no longer has room for the number of participants { "error": "insufficient_spots", "remaining": 1 } # repeated externalRef → idempotency: returns the existing bookingId { "error": "external_ref_exists", "bookingId": "f1e2d3c4-…" }
Revalidation of openings and ratios runs inside a transaction with SELECT … FOR UPDATE — sold out is sold out, there's never double-booking.
The v2 path for equipment brands, apps and AI. Platform key with scope sizing, forecast and/or brand:read — deterministic, no personal data, never touches bookings. Discover your scopes at /api/partner/v2/meta. Base: https://www.surfbooking.eu/api/partner/v2.
Recommended board by level + weight. Scope sizing.
Board tuned to the day: level, weight, swellPeriodS, swellDirectionDeg, bestSwellDirDeg. Scope sizing.
Wetsuit size by weight + height. Scope sizing.
Leash by boardSize + category (board·soft_board). Scope sizing.
Boots by shoeSizeEu (e.g.: 42). Scope sizing.
Lists the spots you can query — use an id from here in /conditions/:spotId. Scope forecast.
Spot conditions — the same public shape, sanitized (never exposes model or sources). Scope forecast.
The best spots in the country right now, ranked by the live score — limit + level. Scope forecast.
For equipment brands: how many times each size of your brand was used in lessons, by month (YYYY-MM). Only your data. Scope brand:read.
Which spots your brand's equipment was most used at, last months (1–12). Scope brand:read.
Board recommendation — 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" } }Platform keys (sbpd_…) are issued by SurfBooking, not by the school. Wrong scope → 403 insufficient_scope. Limit 240 requests/min per key, with Retry-After: 60 when exceeded.
A self-contained iframe page, "Powered by SurfBooking". It shows the spot conditions, recommends the board by weight and level, and takes the customer to book a lesson — with your premium partner link built in. PII-free, no tracking cookies.
<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 = your platform key (scope sizing, and forecast if you want the conditions at the top). spot and slug are optional — the slug links the bookings generated to your /aff (90-day cookie).
The base is /api/partner/v1. Breaking changes go into a new version (/v2) — v1 has no deprecation planned. We may add fields without notice, so read tolerantly: ignore what you don't yet know.
Any partner that wants to sell or show real surf lessons. Designed on the open OCTO standard, which many booking systems and channel managers already speak.
Offer real lessons to guests without managing anything — the booking and payment stay on SurfBooking.
Sync availability in real time, no double-booking. OCTO out of the box.
List the schools' offer and route the booking — with openings and ratios always revalidated on our side.
Each key sees only its own school's offer. Revoke in one click and access dies instantly.
Each booking revalidates openings and instructor ratios inside a transaction. Sold out is sold out.
The money flow stays on our side — the partner routes, SurfBooking confirms.
Only what's needed for the booking goes out. Your students' contacts don't become anyone's list.
The API is live. If you run a surf school, generate your own key in SurfBooking OS. If you're an external partner — an equipment brand, app, AI or hotel — request a platform key (issued by SurfBooking).
I'm a school · Open SurfBooking OS I'm an external partner · Request access View the descriptor