ALL SYSTEMS · NOMINAL
UTC --:--:--
Spot discovery

Ask where, not just is.

The inverse-query side of the engine. Given an activity, a region, and a window, return the top-K ranked sub-spots — calibrated per-spot, safety-gated, optionally personalised. The endpoint that powers 'best kitesurf near me this weekend' inside booking apps and consumer products. Sub-spot coverage is in active expansion: see the open catalogue for current regions, and note that the predicate /v1/score endpoint works on any coordinate worldwide regardless.

01
Two questions, one engine

The flip-side of /v1/score

One physics engine, two question shapes. The predicate path validates a chosen spot. The inverse path enumerates a region, scores every candidate, drops the unsafe ones and returns the top-K — same calibrated curves, same hard gates, same confidence model. Two buyers, one bill.

/v1/score

Is this spot good?

activity: "kitesurfing"
location: {lat:36.013, lng:-5.604}
window: {from:"…", to:"…"}
responsescore: 87 · favorable
/v1/recommend-spot

Where should I go?

activity: "kitesurfing"
regionCenter: {lat:36.01, lng:-5.6}
radiusKm: 50
topK: 5
responsetop 5 ranked sub-spots
02
Worked example

One call · Tarifa · Saturday 10–16 UTC

A real-world inverse query for a kitesurf weekend on the Cádiz coast. The engine resolves five catalog sub-spots within 25km of the region centre, scores each across the six-hour window, drops the unsafe ones, and returns this ranked list. Every row is the same score you'd get calling /v1/score one location at a time.

Request
POST /v1/recommend-spot
{
 activity: "kitesurfing",
 regionCenter: { lat: 36.013, lng: -5.604 },
 radiusKm: 25,
 topK: 5,
 window: {
 from: "2026-07-15T10:00Z",
 to: "2026-07-15T16:00Z"
 }
}
resolver finds 5 catalog sub-spots in radius
5 internal scores, concurrency 6
0 hard-gated (no lightning, AQI ok)
sorted + sliced · ~412ms p50
Response · ranked results5 of 5 returned
  1. 01
    Balneario0.3 km
    Steady 22kt cross-onshore, low gust
    87
  2. 02
    Valdevaqueros6.1 km
    Same wind, slightly choppier
    84
  3. 03
    Punta Paloma8.4 km
    Wind drops 4kt in lee
    79
  4. 04
    Los Lances Sur1.2 km
    Crowded · busy-spot penalty
    73
  5. 05
    Bolonia19.0 km
    Side-shore, gusty afternoon
    68
Reading the result · Balneario and Valdevaqueros both top 80 — same wind regime, but Balneario wins on lower gust factor. Punta Paloma sits in the lee of the headland (4kt drop). Los Lances Sur is 0.9km closer to the centre but the catalog tier marks it as crowded → busy-spot penalty drops it to fourth. The confidence detail on each row tells the consumer app whether to surface the rank or warn about uncertainty.
03
How it works

Composition over new ML

The endpoint introduces zero new physics and zero new machine learning. It's pure orchestration of layers you already trust. The novelty is the spatial enumeration step — and the discipline of dropping unsafe spots BEFORE ranking, not after.

1

Resolve · R-tree

Catalog sub-spots looked up in microseconds against an in-memory R-tree built at boot.

2

Score each

Same physics + calibration + confidence pipeline as /v1/score, fanned out at concurrency 6 to spare upstream providers.

3

Drop unsafe

Lightning ≥0.85 or hazardous AQI → dropped before ranking. allGated=true when EVERY candidate fails.

4

Rank + tiebreak

Sorted DESC by score; within ±0.5 the closer sub-spot wins. Top-K slice returned.

5

Persist + webhook

One audit row + recommendation.completed event (HMAC-signed, top-3 payload).

04
Buyers

Three personas, one endpoint

Komoot · Strava · FATMAP · brand apps

Consumer discovery

Replace N client-side score calls with one ranked recommend.

25km · topK=5 · personalised
The 'find a spot near me' surface that today's weather apps don't have. Drop-in for existing 'check conditions' flows.
FareHarbor · Bookeo · vertical engines

Booking platforms

Powers region-and-activity search result lists.

50km · topK=10 · no personalisation
Sub-spot calibration means an intermediate-friendly bay outranks a big-wave reef when conditions favour learning — funnel converts on quality fit, not just proximity.
Much Better Adventures · Intrepid · enterprise

Travel + tour planners

Itinerary tooling. One call instead of an analyst with five tabs.

200km · topK=20 · counterfactual hints
Pro plan's 200km × topK=20 fits multi-day-route research; Scale's 1000km supports multi-country sweeps with binding-constraint annotations.
05
Plan tiers

Caps scale with the use case

Radius and topK are tiered. Personalisation (cold-start blend on a per-user pseudonym) unlocks at Pro; counterfactual hints (binding-constraint surfacing) at Scale. Daily quota is separate from /v1/score — each recommend call fans out N internal scores, so the cap is independent and tighter. Starter includes 1,500 recommend calls/month, Pro 5,000; overage at €7.50/1k (Starter) and €4.00/1k (Pro).

Free
25km · top5
Single-spot operators, prototypes
Starter
50km · top10
Weekend planning, small school networks
Pro
200km · top20
personal blend
Regional planners, multi-spot brand apps
Scale
1000km · top50
personal + counterfactual hints
Travel agents, multi-country, insurance-adjacent
06
Personalisation

The personal blend, capped at 50%

50% blend cap

The physics-driven score always carries the majority signal. Even a user with 30+ logged outcomes can't override the engine's objective ranking — the personal model nudges within a ±20 point window, never beyond. Discovery results stay anchored to fitness, not bias.

Pseudonym only · never PII

The caller hashes the user identity client-side; we store the hash + model weights + nothing else. GDPR Article 17 deletion via DELETE /v1/decision/user-data/:pseudonym scrubs every trace from the personalization + audit + recommendation stores in one call.

07
Operational

Webhook + audit

Every successful call writes one row to recommendation_runs (region centre as PostGIS POINT, full top-K, latency, allGated flag). That's the primitive behind the upcoming search-heatmap analytics and the forecast-verification join.

Tenants subscribed to recommendation.completed receive an HMAC-signed webhook after each call. Payload trims to the top 3 — the full top-K stays in the audit DB for query-time access.

webhook · HMAC-SHA-256 · 0 results in body
{
  "event": "recommendation.completed",
  "tenantId": "tn_...",
  "data": {
    "activity": "kitesurfing",
    "regionCenter": { "lat": 36.01, "lng": -5.6 },
    "radiusKm": 50, "topK": 5,
    "results": [
      { "rank": 1, "spotSlug": "kitesurfing-spot-tarifa-balneario",
        "effectiveScore": 87, "verdict": "favorable" },
      { "rank": 2, "spotSlug": "kitesurfing-spot-tarifa-valdevaqueros",
        "effectiveScore": 84, "verdict": "favorable" },
      { "rank": 3, "spotSlug": "kitesurfing-spot-tarifa-punta-paloma",
        "effectiveScore": 79, "verdict": "favorable" }
    ],
    "allGated": false, "latencyMs": 412
  }
}
08
Try it

Build with it today