Measured — not modelled — sea state from our buoys on the Costa del Sol, in your product. One iframe for a live widget, or a tiny JSON API for anything custom. Tokens are instant and free to try.
mk_… token is issued instantly. Free to try; the club licence is arranged after (see licences).<iframe src="https://api.marola.surf/widget?spot=venus&token=mk_embed_…"
style="width:320px;height:170px;border:none;border-radius:18px"
title="Live sea state — Marola"></iframe>Every request can carry your token one of two ways — both are equivalent:
# header (recommended for server-side)
curl -H "Authorization: Bearer mk_live_…" https://api.marola.surf/api/latest?spot=venus
# query parameter (for iframes / clients that can't set headers)
https://api.marola.surf/api/latest?spot=venus&token=mk_live_…
Two token kinds exist — mk_embed_… (widget) and mk_live_… (API) — both unlock the same live data; the split is for licensing/analytics. Tokens don't expire but are tied to your organisation and domain under the licence.
Base URL: https://api.marola.surf · all responses JSON · CORS enabled (*).
/embed/{spot} token required
The one-call endpoint: latest conditions for a spot, cached 2 min at the edge. Ideal for menus/screens/dashboards.
curl -H "Authorization: Bearer mk_live_…" https://api.marola.surf/embed/venus
/api/latest?spot={spot}
Latest reading. With a token: real-time. Without: free tier — the most recent reading that is at least 3 h old, flagged "delayed": true.
/api/history?spot={spot}&hours={1–168} token required
Time series of ts, hs, tp, chop, sst, score — up to 7 days. Returns 402 without a token.
/api/spots
Public list of live spots: slug, name, lat, lon, is_real (real buoy vs simulated during rollout). No token needed.
/api/stream?spot={spot} token required
Server-Sent Events — a push stream of readings as they arrive from the buoy. Reconnects automatically (EventSource).
const es = new EventSource("https://api.marola.surf/api/stream?spot=venus&token=mk_live_…");
es.onmessage = e => console.log(JSON.parse(e.data)); // {spot, ts, hs, tp, chop, sst, score, …}
| field | type | meaning |
|---|---|---|
ts | int | reading time, epoch milliseconds UTC |
hs | m | significant wave height (4√m₀, spectral) |
tp | s | peak wave period |
chop | m | wind-sea ("chop") height — the <8 s band |
hswell | m | swell-band height — the ≥8 s band |
dir | ° | mean wave direction, met convention (coming from, 0° = N) |
sst | °C | sea-surface (water) temperature |
score | 0–100 | conditions score (100 = glassy). Derived server-side from hs + chop |
verdict | string | human label for the score — Clean & calm · Good · Choppy · Rough |
name, lat, lon | spot display name and position | |
delayed | bool | present + true only on free-tier (tokenless) responses |
valid | 0/1 | data-quality flag from the buoy (0 = degenerate record) |
| status | body | meaning |
|---|---|---|
401 | {"error":"token_required"} | /embed/… without a valid token — get one at /embed |
402 | {"error":"upgrade_required"} | gated feature (history, live stream) without a token/plan |
404 | {"error":"no data"} | unknown spot, or no readings yet |
Try free, instantly. Tokens from the builder work immediately so you can integrate and demo today.
Going live commercially: the club/venue widget licence is from €29/month and the data API is priced on usage — we confirm your licence by email after you generate a token (it's tied to your organisation + domain) and invoice monthly. Card checkout (Stripe) is coming; today it's a simple invoice.
Something bigger? Multiple spots, white-label, or a buoy off your own beach — hello@marola.surf.
Readings update every few minutes (buoy cadence), so please: poll /api/latest no more than once per minute, prefer /api/stream for push, and rely on /embed/{spot}'s built-in 2-minute edge cache. The iframe widget already does the right thing (2-minute refresh). Not for navigation or safety-of-life use.