Is this spot good?
activity: "kitesurfing"location: {lat:36.013, lng:-5.604}window: {from:"…", to:"…"}
The predicate-query side of the engine. Hand the engine an activity, a location, and a time window — get back a 0-100 verdict with the full physics breakdown, per-dimension scores, and a confidence block. The booking-platform endpoint that decides whether tomorrow's session opens or closes.
One physics engine, two question shapes. The predicate path (this page) validates a chosen spot. The inverse path enumerates a region. Same calibrated curves, same hard gates, same confidence model. Two buyers, one bill.
activity: "kitesurfing"location: {lat:36.013, lng:-5.604}window: {from:"…", to:"…"}
activity: "kitesurfing"regionCenter: {lat:36.01, lng:-5.6}radiusKm: 50topK: 5
A real-world predicate call for a kitesurf weekend at a known spot. The engine scores six physics dimensions independently against the kitesurfing profile's calibrated curves, then folds them into the 0-100 verdict the booking flow consumes.
POST /v1/score
{
activity: "kitesurfing",
location: { lat: 36.0133, lng: -5.6044 },
window: {
from: "2026-07-15T10:00Z",
to: "2026-07-15T16:00Z"
}
}Every coefficient traces to a peer-reviewed formula. ML appears ONLY in two places — provider skill weights and curve calibration. Both train against real outcomes, never replace the physics. The verdict you read in production has a paper trail back to oceanography journals.
Skill-weighted blend of Open-Meteo + Stormglass + CMEMS — per-cell weights refit nightly against real outcomes.
25+ peer-reviewed formulas across 20 namespaces (wind, wave, tide, atmosphere, snow, lightning, AQI, ...).
Hierarchical Bayesian shrinkage along the 5-level catalog (base → region → cluster → sub-spot). Curves tighten as cohort outcomes accumulate.
Lightning ≥0.85 or hazardous AQI → verdict=unsafe regardless of other dimensions. Safety first.
0-100 score + verdict (favorable/workable/poor/unsafe) + confidence detail (forecast / historical / climate mode).
Validate booking-flow conditions before the customer pays.
Daily 'open or close' decision for the school.
Per-day go/no-go on a multi-day itinerary.
Score calls are metered per-event via Stripe. Free hard-caps at the included quota (no surprise bill). Starter/Pro overflow at the published rate. Scale runs on a contracted ceiling.
| Plan | Included | Overage | Typical buyer |
|---|---|---|---|
| Free | 1,000 / month | Hard cap | Prototype, single-spot test |
| Starter | 50,000 / month | €1.50 / 1k over | Single operator, weekend traffic |
| Pro | 500,000 / month | €0.80 / 1k over | Multi-spot brand, ensemble + AI explain |
| Scale | Unlimited | Contracted | Underwriting, climate, multi-country |
The confidence detail decomposes the scalar confidence into four interpretable factors. Booking flows can gate UX decisions on the SUB-factor they care about (e.g., "warn user when providerSkill < 0.7 for their region").
The block shape adapts to the call: mode is forecast for /v1/score (today's call), historical for /v1/score/historical (parametric underwriting), climate for /v1/projections (multi-decadal). Same envelope, different content.
{
"session_id": "a7b2...",
"score": 87,
"verdict": "favorable",
"confidence": 0.84,
"confidenceDetail": {
"mode": "forecast",
"providerSkill": 0.91,
"ensembleSpread": 0.78,
"profileMaturity": 0.85,
"hierarchicalCalibration": 0.95
},
"breakdown": [
{ "dim": "wind", "score": 94 },
{ "dim": "wave", "score": 78 },
{ "dim": "lightning","score": 100 }
],
"eco": { "carbonNeutral": true, "energyClass": "A" }
}Booking flow reports back: "did the session actually happen? was it cancelled? was the customer happy?". Each outcome feeds the calibration loop — curves tighten when reality disagrees with the engine's predictions.
(forecast × outcome) pairs are what unlock the next horizons — parametric underwriting needs them (T2) and the open research dataset publishes them with k≥10 anonymisation (Stream F, CC BY 4.0).