Integrators, data engineers
REST API
The base URL of this deployment, every partner endpoint with its parameters, the date rules, the response envelope field by field, examples in curl, Python and JavaScript, and the live OpenAPI reference.
Last reviewed
Base URL
This deployment's API is at https://coastal-intelligence.triskelionaisystems.com/api. Every path below is relative to it. Send the key as Authorization: Bearer <key> (or X-API-Key); see Authentication and keys. Responses are JSON (application/json) except the CSV export.
Endpoints
One GET route per tool, with the same checks, rate limit and audit as over MCP. Required query parameters are marked; the others are optional. Argument meanings are on the MCP server page, tool by tool.
| Route | Query parameters | Product needed | Tool |
|---|---|---|---|
GET /agency/bays | none | none | list_bays |
GET /agency/sites?bay= | bay (required) | none | list_sites |
GET /agency/signals?target=&kind=&from=&to= | target (required), kind, from, to | signals | get_signals |
GET /agency/events?bay=&from=&to= | bay (required), from, to | events | get_events |
GET /agency/skill?site=&variable= | site (required), variable | skill | get_skill |
GET /agency/timeseries?site=&variable=&product=&from=&to= | site (required), variable (required), product (required), from, to | the dataset key given as product | get_timeseries |
GET /agency/backtest?bay= | bay (required) | backtest | get_backtest |
GET /agency/risk-index?bay=&from=&to= | bay (required), from, to | risk_index | get_risk_index |
GET /agency/datasets | none | none | describe_datasets |
Other partner endpoints
| Route | Who may call it | Parameters | Documented responses |
|---|---|---|---|
GET /agency/tools | agency API key | none | 200 |
GET /bays/{bay_id}/risk-index | agency API key, or a signed-in administrator or co-op account | bay_id (path, required), from (query), to (query), format (query) | 200, 401, 403, 404, 422, 429 |
GET /exports/signing-key | none (public) | none | 200 |
GET /datasets | none (public) | none | 200 |
POST /sites/{site_id}/observations | the deployment's webhook key | site_id (path, required) | 201, 401, 422, 503 |
GET /agency/tools: the tool list with argument names and types, for REST clients that want to discover it at run time.GET /bays/{bay_id}/risk-index: the risk index as JSON or, withformat=csv, as a signed CSV file;GET /exports/signing-key: the public key that checks it. See Risk index and signed exports.GET /datasets: the public dataset registry with licences and attribution lines. See Data model and licences.POST /sites/{site_id}/observations: the observations webhook for loggers and gateways (a different key). See Observations webhook.
Date rules
fromandtoare UTC days,YYYY-MM-DD, inclusive, and must lie inside the key's approved range.- Omitted,
tois today plus the 10-day forecast horizon andfromis 30 days beforeto, both clipped to the approved range. - One call covers at most 366 days and returns at most 20,000 rows; above either limit the answer is
422. - Timestamps in rows (
ts,start,end) are ISO 8601 in UTC.
Response envelope
| Field | Type | Meaning |
|---|---|---|
tool | string | The tool that answered (get_signals, ...). |
scope | object | The key's approved scope: request_id, organisation, bays, products, aggregation, from, to. |
notice | string | The standing notice: read-only shared layers, indicators not food-safety advice, every call is logged. |
count | integer | Number of data rows (for get_timeseries: points across all series). |
rows | array | The data rows (every tool except get_timeseries). Each row carries the five source fields below. |
series | array | get_timeseries only: one series per source, product and depth, each with its points [{ts, value, lead_hours}]. |
licences | array | The licences used by this result: {id, name, provider, url}. |
attribution | array of strings | The exact attribution lines those licences require. Keep them when you publish. |
from, to | date | The UTC day window actually answered (tools with a date range). |
level, target | string | get_signals: bay or site, and the id answered for. |
as_of | date | get_skill, get_backtest: the day the figures stand at. |
method, min_sites | string, integer | get_risk_index: the method version and the suppression threshold. |
The five fields every data row carries
| Field | Meaning |
|---|---|
source | Where the value comes from: a provider source id for raw data, coastal-intel for values computed here, register for bays and sites. |
product | The dataset key or the derived product (signal:<kind>, signal:<kind>:bay, event:<kind>, hab_bulletin, backtest:bloom, risk_index:<peril>). |
scale | regional (model cell or bay aggregate), satellite, or site (a station or a site). |
lead_hours | null for observations and dated events, 0 for an analysis, above 0 for a forecast (hours ahead of issue). |
licence | The licence id (or several, comma-separated, for a derived value); the envelope's licences list names each one. |
Tool-specific row fields (for example value_max and worst_label for a bay signal aggregate; bias, rmse, mae for skill; index, level, suppressed for the risk index) are described in each tool's entry on the MCP server page and in the live reference below.
Example of the shape
Shape only. Every value below is a placeholder in angle brackets or a list of the allowed values; it is not a reading, and no example on this site shows measured data.
{
"tool": "get_signals",
"scope": {
"request_id": "<integer>",
"organisation": "<your organisation>",
"bays": [
"<bay id>"
],
"products": [
"signals",
"<...>"
],
"aggregation": "bay | site",
"from": "<YYYY-MM-DD>",
"to": "<YYYY-MM-DD>"
},
"notice": "<the standing notice>",
"level": "bay",
"target": "<bay id>",
"from": "<YYYY-MM-DD>",
"to": "<YYYY-MM-DD>",
"count": "<number of rows>",
"rows": [
{
"bay_id": "<bay id>",
"kind": "thermal | bloom | runoff | growth",
"ts": "<ISO 8601, UTC>",
"n_sites": "<integer>",
"n_series": "<integer>",
"value_max": "<number | null>",
"value_mean": "<number | null>",
"worst_label": "low | watch | stress | critical | null",
"labels": {
"<label>": "<count>"
},
"source": "coastal-intel",
"product": "signal:<kind>:bay",
"scale": "regional",
"lead_hours": "<integer | null>",
"licence": "<licence id>"
}
],
"licences": [
{
"id": "<licence id>",
"name": "<licence name>",
"provider": "<provider>",
"url": "<url>"
}
],
"attribution": [
"<attribution line>"
]
}Examples in curl, Python and JavaScript
Each example reads bay-level signals; replace the placeholders. The key comes from the AGENCY_KEY environment variable.
curl
curl -H "Authorization: Bearer $AGENCY_KEY" \ "https://coastal-intelligence.triskelionaisystems.com/api/agency/signals?target=<bay id>&from=<YYYY-MM-DD>&to=<YYYY-MM-DD>"
Python
import os
import requests # pip install requests
API = "https://coastal-intelligence.triskelionaisystems.com/api"
headers = {"Authorization": f"Bearer {os.environ['AGENCY_KEY']}"}
res = requests.get(
f"{API}/agency/signals",
params={"target": "<bay id>", "from": "<YYYY-MM-DD>", "to": "<YYYY-MM-DD>"},
headers=headers,
timeout=30,
)
if res.status_code == 429:
print("rate limited; retry after", res.headers.get("Retry-After"), "seconds")
res.raise_for_status()
data = res.json()
for row in data["rows"]:
print(row["ts"], row["kind"], row["worst_label"], row["licence"])
print(*data["attribution"], sep="\n") # cite these when you publishJavaScript
const API = "https://coastal-intelligence.triskelionaisystems.com/api";
const params = new URLSearchParams({ target: "<bay id>", from: "<YYYY-MM-DD>", to: "<YYYY-MM-DD>" });
const res = await fetch(`${API}/agency/signals?${params}`, {
headers: { Authorization: `Bearer ${process.env.AGENCY_KEY}` },
});
if (res.status === 429) throw new Error(`rate limited; retry after ${res.headers.get("Retry-After")} s`);
if (!res.ok) throw new Error((await res.json()).detail);
const data = await res.json();
for (const row of data.rows) console.log(row.ts, row.kind, row.worst_label, row.licence);
console.log(data.attribution.join("\n")); // cite these when you publishLive interactive reference
The API serves its own OpenAPI document at https://coastal-intelligence.triskelionaisystems.com/api/openapi.json (version 0.1.0) and an interactive reference at https://coastal-intelligence.triskelionaisystems.com/api/docs. It covers the whole API, including the routes the web app uses; the tags for partners are agency, data-reference, observations, risk-index. Routes under other tags need a signed-in web session and are not part of the partner API.
Related
Authentication and keys
The request and approval flow, the Authorization and X-API-Key headers, what a key's scope means, revocation, the exact meaning of 401, 403, 404, 422 and 429, and what the access log records.
Last reviewed 1 Nov 2026Analysts with an AI assistant, agent buildersMCP server
The Model Context Protocol server for AI assistants and agents: endpoint and transport, the auth header, every tool with its typed arguments, the tool-error shape, client configurations, the configuration checker and example prompts.
Last reviewed 1 Nov 2026Data engineers, legal and complianceData model and licences
The five provenance fields on every row, the three scales, what lead_hours means, the public dataset registry, the licence ids and the attribution line each one requires, and the product catalogue.
Last reviewed 1 Nov 2026