Build with Marola

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.

QuickstartAuthenticationAPI reference Response fieldsErrorsLicences & paymentFair use

Quickstart — live widget in 3 steps

Get a token — use the widget builder: pick your spot, enter your details, and your mk_… token is issued instantly. Free to try; the club licence is arranged after (see licences).
Paste the iframe anywhere on your site:
<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>
Done. The widget shows the live named sea state, wave height, water temperature and 2-hour trend, refreshing itself every 2 minutes. Your token is what makes the data live — without it the API serves 3-hour-delayed data.

Authentication

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.

API reference

Base URL: https://api.marola.surf · all responses JSON · CORS enabled (*).

GET/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
GET/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.

GET/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.

GET/api/spots

Public list of live spots: slug, name, lat, lon, is_real (real buoy vs simulated during rollout). No token needed.

GET/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, …}

Response fields

fieldtypemeaning
tsintreading time, epoch milliseconds UTC
hsmsignificant wave height (4√m₀, spectral)
tpspeak wave period
chopmwind-sea ("chop") height — the <8 s band
hswellmswell-band height — the ≥8 s band
dir°mean wave direction, met convention (coming from, 0° = N)
sst°Csea-surface (water) temperature
score0–100conditions score (100 = glassy). Derived server-side from hs + chop
verdictstringhuman label for the score — Clean & calm · Good · Choppy · Rough
name, lat, lonspot display name and position
delayedboolpresent + true only on free-tier (tokenless) responses
valid0/1data-quality flag from the buoy (0 = degenerate record)
Named sea states used across Marola (same thresholds as the app): score ≥80 Glassy · ≥60 Clean · ≥42 Lively · ≥24 Choppy · else Rough.

Errors

statusbodymeaning
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

Licences & payment

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.

Fair use & caching

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.