Nodds API
The Nodds API gives your app device connection and grounded AI querying
over a user's health data — wearables (sleep, recovery, HRV, heart rate, steps,
activity) and lab/blood results — with one key. Nodds does the data retrieval and
grounding; you get clean, structured answers and never invent numbers.
- Base URL:
https://nodds.ai/api/nodds/v1
- Auth:
Authorization: Bearer <NODDS_API_KEY>
- Content type:
application/json (except uploads, which are multipart/form-data)
Keep your key server-side. The Nodds API key is a server-to-server
credential. Call Nodds from your backend, never from a browser.
Identity: reference_id
Every user is identified by a reference_id — an id you choose and own (a UUID
per user works well). All of a user's device connections and lab reports group
under their reference_id, and every call is scoped by it. Generate one per user,
store it, and reuse it.
Connect a device
Start a provider OAuth flow. Redirect the user to the returned connect_url; the
provider sends them back to your success_url / failure_url when done.
POST /connect
Authorization: Bearer <NODDS_API_KEY>
Content-Type: application/json
{
"resource": "GARMIN",
"reference_id": "user-123",
"success_url": "https://yourapp.com/connected",
"failure_url": "https://yourapp.com/connect?error=1"
}
{ "connect_url": "https://.../widget/session/...", "user_id": "…" }
On return, success_url is called with ?status=success&resource=GARMIN&user_id=…
(store nothing extra — the connection is already keyed to the reference_id).
List the providers you can offer with GET /integrations → { providers: [{ name, provider, icon, types }] }. Icons are served from Nodds' domain.
Check a user's connections
GET /users/user-123
Authorization: Bearer <NODDS_API_KEY>
{ "reference_id": "user-123", "connections": [{ "provider": "GARMIN", "user_id": "…" }] }
Grounded chat = your model + Nodds' context layer
There is no managed chat endpoint: Nodds sells the context layer. Your app
runs its own model (any provider) and grounds every answer with /context
below, drilling into exact records via the MCP when needed — the starter
template's lib/agent.js is a complete working implementation of the loop.
Sample-data fallback: if a reference_id has no data at all (no connected
devices, no lab reports), context comes from a realistic shared sample
profile instead — clearly flagged — so your app works before a user connects
anything. The moment they connect a device or upload labs, answers switch to
their own data automatically.
Grounded context (the primary endpoint)
If you'd rather run your own model, POST /context returns the structured health
context Nodds would ground on — feed it straight into your prompt.
POST /context
Authorization: Bearer <NODDS_API_KEY>
Content-Type: application/json
{ "reference_id": "user-123", "query": "how is my recovery trending?" }
{ "reference_id": "user-123", "sample": false, "context": "…structured signals, evidence, insights…" }
context is null when there's nothing to ground on — never fabricate around it.
sample: true means the reference had no data of its own, so the context comes
from the shared sample profile — tell your model (and your user) accordingly.
The Nodds MCP — raw-data drill-down (and coding agents)
<base>/mcp is a Model Context Protocol server (Streamable HTTP, stateless).
Attach it to your agent alongside /context for questions that need exact
records or custom aggregations, or plug it straight into a coding agent:
Claude Code
claude mcp add --transport http plane https://nodds.ai/api/nodds/v1/mcp \
--header "Authorization: Bearer $NODDS_API_KEY"
Codex (~/.codex/config.toml)
[mcp_servers.plane]
url = "https://nodds.ai/api/nodds/v1/mcp"
http_headers = { "Authorization" = "Bearer <NODDS_API_KEY>" }
Tools (every one takes reference_id):
| Tool | What it does |
|---|
get_health_context | The primary tool — grounded structured context for a natural-language question (same engine as /context) |
query_health_data | Raw records or aggregations for one data type (fields/select/group_by/where) |
describe_health_fields | The valid queryable fields for a data type — call before query_health_data |
list_sources | The user's connected sources (+ whether results are sample data) |
get_lab_results | Uploaded lab reports with extracted biomarkers |
get_environment | Weather history + forecast (temperature, humidity, precipitation, UV, wind) — defaults to the account's saved Weather location; pass a place name to override |
get_air_quality | Current AQI, pollutants, and health recommendations (+ up to 30 days of daily history) — defaults to the saved Weather location |
get_pollen | Grass/tree/weed pollen forecast up to 5 days — defaults to the saved Weather location |
get_calendar_events | Events from the Google Calendar connected to your Nodds account (Connect page) — relate schedule load to health data |
Same sample-data fallback as /context: references with no data ground on the
shared sample profile, clearly flagged. The starter's lib/agent.js shows the
full pattern (context + MCP + your own model).
Account-level connectors (current limitation): the environment tools'
saved-location default and the Google Calendar grant belong to the Nodds
account that owns the API key — not to your end users. For multi-user apps,
pass each user's location explicitly to get_environment / get_air_quality
/ get_pollen; get_calendar_events currently reads only the key owner's
connected calendar (per-user calendar connect is planned).
Lab / blood reports
POST /lab-reports # multipart: file=<PDF/image>, reference_id=user-123
GET /lab-reports?reference_id=user-123
Authorization: Bearer <NODDS_API_KEY>
GET returns { sessions: [{ session_id, current_status, results_count, uploaded_at }] }.
Reports process asynchronously; poll status. Uploaded biomarkers are automatically
available to /context and the MCP's get_lab_results.
Free tier & credits
Every account includes a free tier — 1 device connection, 25 grounded
context calls, and 50 data queries per month — enough to build and demo an
app. Past it, requests draw on a prepaid balance: each billable request
debits its price, and requests halt with 402 when the balance hits zero
until you reload. Per-request pricing: grounded context $0.01, data query
$0.005 — so a $20 reload is roughly 2,000 context calls. Reload and check
your balance on the Nodds dashboard (/billing). Integrations listing and lab
uploads are never charged. (The hosted Nodds chat at the consumer site has its
own free allowance and per-question pricing, shown in-app.)
Errors
| Status | Meaning |
|---|
400 | Missing/invalid parameters |
401 | Missing or invalid Nodds API key |
402 | Free tier exhausted and no credits remain — add credits on the Nodds dashboard (/billing) |
403 | Reference belongs to another account's key, or asset host not allowed |
502 | Upstream data platform error |
503 | Nodds API not configured on the server |
Notes
- Data figures always come from real signals; when data is missing, Nodds says so
rather than inventing values.
- The only step that currently leaves Nodds' domain is the provider-consent page
during
/connect (hosted by the data platform). Everything else — data, chat,
context, assets — is served through Nodds.