ALL SYSTEMS · 99.97%
UTC --:--:--
Docs·API reference·POST /v1/score

Score an activity at a place in a window

The core endpoint. One call returns a 0–100 score, a verdict, a per-dimension breakdown, the raw physical readings and an audit-ready provider chain.

POSThttps://api.goable.io/v1/score

The scoring engine is deterministic — given the same inputs and provider chain, the score is identical every time, and the audit log replays the call.

Overview

Send a location, an activity and a time window; get back a single suitability score with its full breakdown. The verdict is one of favorable, marginal, unfavorable or unsafe— and a universal hard gate (lightning ≥ 0.85 or hazardous AQI) forces unsafe regardless of the rest.

Authentication

Include a Bearer key in the Authorization header. See Authentication for key handling.

Request

locationrequired
object { lat, lng }
Spot coordinates in WGS-84 decimal degrees. Latitude -90 → +90, longitude -180 → +180. Resolved against the bathymetry catalog for marine activities and the spot catalog for regional calibration.
activityrequired
enum string
One of the 18 base profiles or a regional variant: kitesurfing, surfing, windsurfing, sailing, scuba, ski-touring, freeride, paragliding, trail-running, climbing, …
windowrequired
object { from, to }
ISO-8601 UTC instants. The engine scores the worst sub-window of duration ≥ the activity's min_session_minutes within the requested range. Max horizon: 168 h (7 d) on Pro, 240 h on Scale.
options
object
Optional flags: include_breakdown (per-dimension contributions), include_physics (raw values + units), language (response narration), ensemble (probabilistic distribution; Pro+).

Response

score
integer · 0–100
Suitability score, monotonic, deterministic. 78 in Tarifa for a kitesurfing window means: better than 78% of comparable windows for that spot.
verdict
enum string
favorable ≥ 75 · marginal 55–74 · unfavorable 30–54 · unsafe< 30 or hard gate triggered.
confidence
float · 0–1
Derived from forecast horizon, provider agreement, profile maturity, and (on Pro+) ensemble spread. See Confidence detail in the response for the full discriminated union.
breakdown
object
Per-dimension contributions to the score. Keys are profile-specific (kitesurfing: wind, wave, tide, thermal_breeze, sun, gust_factor). Values sum to ≤ 1.0.
physics
object
Raw physical readings with units. The numbers the score was computed from — wind in knots, wave height in meters, tide phase, CAPE, etc.
alerts
array · 0–N
Surfaced advisories: golden-hour windows, lightning proximity, AQI hazards, rip-current risk, freezing-level crossings, breaker classification (surf-family).
provider_chain
array<string>
Ordered list of providers that contributed to this response. Audit-logged. Reproducing the call with the same chain yields the same score.

Code samples

Same call, four languages. The TypeScript SDK is the most ergonomic; cURL works anywhere.

// npm install @goable-io/sdk
import { GoableClient } from "@goable-io/sdk"

const goable = new GoableClient({ apiKey: process.env.GOABLE_KEY! })

const { score, verdict, breakdown } = await goable.score({
location: { lat: 36.013, lng: -5.604 },
activity: "kitesurfing",
window: { from: "2026-05-23T09:00Z", to: "2026-05-23T18:00Z" },
})

if (verdict === "favorable") {
openBookingSlot(score)
}

Try it

Pick an activity, a spot and the option flags. Runs against the live engine (public demo tenant, 60 calls / hour / IP); falls back to a deterministic sample.

Try it · liveready
request
activity
spot
breakdown
language
expected response
{
"score": 76,
"verdict": "favorable",
"confidence": 0.75,
"breakdown": {
"wind": {
"contribution": 0.323,
"score": 77
},
"wave": {
"contribution": 0.137,
"score": 76
},
"tide": {
"contribution": 0.085,
"score": 85
},
"thermal_breeze": {
"contribution": 0.094,
"score": 78
}
},
"physics": {
"wind": {
"value": 28,
"unit": "knots"
},
"wave": {
"value": 2.4,
"unit": "meters"
},
"period": {
"value": 6.8,
"unit": "seconds"
},
"tide": {
"phase": "falling"
}
},
"alerts": [],
"provider_chain": [
"stormglass",
"openmeteo-marine",
"noaa"
],
"computed_at": "2026-05-23T09:00:00.000Z"
}

Errors

400 · INVALID_REQUEST
Zod validation
Payload failed schema validation. The extra field lists each failing path and reason.
401 · UNAUTHORIZED
missing / bad key
Bearer token absent, malformed, or hash mismatch. Rotate from the admin dashboard.
402 · PAYMENT_REQUIRED
plan gate
Endpoint requires a higher plan than the tenant currently holds. Ensemble + projections gated to Pro and Scale.
429 · RATE_LIMITED
daily window
Daily quota exhausted for the tenant. Free 100 · Starter 1k · Pro 10k · Scale ∞. Resets at 00:00 UTC.
503 · PROVIDER_DEGRADED
all providers down
Every provider in the chain failed within the timeout budget. Goable never serves a stale-cache score silently — degradation is explicit.