UTC --:--:--
Docs·SDKs·TypeScript

TypeScript SDK · @goable-io/sdk

A thin, fully-typed transport over the public API: one request method powers every call, and the types are generated from the versioned OpenAPI contract. It covers the public API surface, from scoring and recommend-spot to decision, counterfactual explain, intelligence, underwriting, observations and outcomes.

Install

npm install @goable-io/sdk
# pnpm add @goable-io/sdk · yarn add @goable-io/sdk

v0.5.0, MIT licensed, published to npm with provenance (verifiable build attestation via npm audit signatures). Isomorphic: the same package runs in Node, browsers, and edge runtimes off the global fetch; inject your own fetch implementation for older Node or test environments. Zero runtime dependencies. Source + the full method list: github.com/goable-io/sdk.

Quickstart

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

const goable = new GoableClient({ apiKey: process.env.GOABLE_API_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" },
})

Authentication

The constructor takes your key plus optional transport overrides. See Authentication for how keys work.

new GoableClient({
 apiKey: string, // required
 baseUrl?: string, // default https://api.goable.io
 fetch?: FetchLike, // inject for tests
 timeoutMs?: number, // default 30000; 0 disables
})

Methods

MethodEndpoint
score(req)POST /v1/score
scoreSeries(req)POST /v1/score/series
scoreMulti(req)POST /v1/score/multi
scorePortfolio(req)POST /v1/score/portfolio
scoreHistorical(req)POST /v1/score/historical
projections(req)POST /v1/projections
decision(req)POST /v1/decision
recommendSpot(req)POST /v1/recommend-spot
explainCounterfactual(req)POST /v1/score/explain-counterfactual
explain(req)POST /v1/intelligence/explain
briefing(req)POST /v1/intelligence/briefing
quote(req)POST /v1/underwriting/quote
bindPolicy(req)POST /v1/underwriting/policy/bind
submitOutcome(sessionId, req)POST /v1/score/:id/outcome
health()GET /v1/health

Try it

Pick an activity, a spot and the 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
expected response

Display-only — the real /v1/score request has no option to omit fields; this just trims what's shown here.

{
"score": 76,
"verdict": "favorable",
"confidence": 0.75,
"breakdown": {
"wind": {
"contribution": 0.323,
"score": 77,
"hasData": true
},
"wave": {
"contribution": 0.137,
"score": 76,
"hasData": true
},
"tide": {
"contribution": 0.085,
"score": 85,
"hasData": true
},
"thermal_breeze": {
"contribution": 0.094,
"score": 78,
"hasData": true
},
"sun": {
"contribution": 0.062,
"score": 78,
"hasData": true
},
"gust_factor": {
"contribution": 0.077,
"score": 77,
"hasData": true
}
},
"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"
],
"eco": {
"metarValidation": {
"sourceType": "in_situ_observation",
"stationId": "LE81",
"sourceDistanceKm": 3.2,
"observedAt": "2026-05-23T08:42:13.952Z",
"wind": {
"validated": true,
"observedMs": 8.8,
"forecastMs": 11.1,
"overridden": false
}
},
"cmemsWaveValidation": {
"sourceType": "satellite_observation",
"validated": true,
"observedHeightM": 1.87,
"forecastHeightM": 0.73,
"overridden": false,
"sourceDistanceKm": 15.9
},
"sstValidation": {
"sourceType": "satellite_observation",
"validated": true,
"observedC": 14.7,
"forecastC": 20.3,
"overridden": true,
"sourceDistanceKm": 17
},
"tideObserved": {
"sourceType": "in_situ_observation",
"observedLevelM": 0.11,
"datum": "station_zero",
"stationId": "ioc-cadiz",
"sourceDistanceKm": 23.1,
"staleMinutes": 21,
"trend": "falling",
"rateMPerH": -0.13,
"rangePosition": 0.05
},
"buoyValidation": {
"sourceType": "in_situ_observation",
"stationId": "6200025",
"sourceDistanceKm": 20.9,
"observedAt": "2026-05-23T08:00:00.000Z",
"wave": {
"validated": true,
"observedM": 0.69,
"forecastM": 1.4,
"overridden": true
},
"sst": {
"validated": true,
"observedC": 18,
"forecastC": 24,
"overridden": false
},
"wind": {
"validated": true,
"observedMs": 7,
"forecastMs": 13.1,
"overridden": false
},
"observedWavePeriodS": 8.2,
"observedWaveDirectionDeg": 32
}
},
"computed_at": "2026-05-23T09:00:00.000Z"
}

Errors

Non-2xx throws GoableApiError (with status, code, issues); transport failures throw GoableNetworkError. A few high-signal 422 codes are surfaced as dedicated subclasses, currently DriftActiveError for a refused underwriting bind. See Errors & rate limits.

import { GoableApiError } from "@goable-io/sdk"

try { await goable.score(req) } catch (err) {
 if (err instanceof GoableApiError)
 console.error(err.status, err.code)
}

Types

ScoreRequest, ScoreResponse and the rest are generated from the versioned OpenAPI 3.1 contract, so they track the contract they were built against rather than being hand-maintained. The SDK is released alongside the API versions it supports, and compatibility is covered by contract tests. Full endpoint reference: POST /v1/score.