Authentication

Audience Mechanism
Device firmware Device key in /api/ingest/<deviceKey> (or X-Ingest-Key for MQTT bridge)
Pro integrations Bearer API key from Dashboard → Share
Browser dashboard Session cookie (not for third-party clients)
Share / inbound Opaque token in the URL path (+ optional HMAC on inbound)
Claim puck / Bay Buddy Companion session: Authorization: Bearer + X-SB-Refresh-Token (claim puck)

POST /api/ingest/<deviceKey>

Primary hardware path. Push JSON from ESP/Arduino or any HTTPS client. Sensor keys auto-import on first POST. Optional top-level battery / battery_pct and rssi update device health.

Limits: max ~64KB body; ~60 requests per minute per device key (per Worker isolate). Exceeding size → 413; exceeding rate → 429 with Retry-After when set.

curl -X POST "https://thermaltrace.dev/api/ingest/YOUR_DEVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"door1": true, "temp1": 42.5, "battery": 87, "rssi": -62}'

200 OK example:

{
  "ok": true,
  "readings": 2,
  "sensors_created": 2
}

Kinds include temperature, humidity, CO₂, pressure, PM2.5, VOC, water level, energy, door, power, flood, and motion. Sample sketches: sketches/ · Adding devices · Ingest & webhooks · JSON probe schema

POST /api/ingest/mqtt

MQTT→HTTPS bridge. Keep Mosquitto on the LAN; mirror topics with header X-Ingest-Key.

curl -X POST "https://thermaltrace.dev/api/ingest/mqtt" \
  -H "Content-Type: application/json" \
  -H "X-Ingest-Key: YOUR_DEVICE_KEY" \
  -d '{"topic":"home/garage/temp","message":{"temp1":42.5,"humidity":38}}'

Full recipe: MQTT bridge guide

Claim puck (/api/pucks + bay mood)

RP2040-Zero presence key. Companion session auth (same Bearer + X-SB-Refresh-Token headers as Bay Buddy). Product setup: /claim-puck.

Method Path Purpose
POST /api/pucks/register Store device id + HMAC secret for the signed-in household
POST /api/pucks/claim/start Issue a nonce for button-confirmed claim
POST /api/pucks/claim/finish Verify HMAC-SHA256(secret, nonce) and bind bay
GET /api/bays/<bay_id>/mood Bay Buddy mood from sensors (or PUT override)

Firmware + CLI: thermaltrace-claim-puck · Desktop claim UI: Bay Buddy

Common ingest errors

Status When Body shape
400 Missing key, invalid JSON, empty body, unusable payload { "error": "…" }
401 Unknown / invalid device key { "error": "Invalid device key" }
413 Body larger than ~64KB { "error": "Payload too large…" }
429 More than ~60 POSTs/min for that device key { "error": "Rate limit exceeded…" }
500 Server-side persistence failure { "error": "…" }

GET /api/v1/metrics

Prometheus text exposition (Pro). Create an API key under Dashboard → Share.

curl -sS "https://thermaltrace.dev/api/v1/metrics" \
  -H "Authorization: Bearer YOUR_API_KEY" | head

Related: GET/POST /api/v1/devices with the same Bearer key (list / create push devices). Grafana notes: developer docs ↗

POST /api/inbound/<token>

Pro inbound webhooks for Home Assistant / Zapier / Make: actions such as snooze, vacation, status. Create the token under Dashboard → Share. Optional HMAC via signing secret (X-ThermalTrace-Signature; legacy X-GarageTemp-Signature still accepted).

curl -X POST "https://thermaltrace.dev/api/inbound/YOUR_INBOUND_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"action":"snooze","hours":4}'

Invalid token → 401; bad signature → 401 { "error": "Invalid signature" }. Guide: Ingest & webhooks · HACS integration

GET /api/share/<token>/readings

Public JSON for share links. Free includes one family live link; Pro adds history/metrics scopes and never-expire options.

curl -sS "https://thermaltrace.dev/api/share/YOUR_SHARE_TOKEN/readings"

Session cookie routes (dashboard)

  • POST /api/user/pull-setup: save pull feeds and probe labels in one step (Devices → Pull feeds). Not for firmware; requires a signed-in browser session.
  • POST /api/devices/reveal-ingest-key: recover a push device’s ingest key when the deployment has INGEST_KEY_ENCRYPTION_SECRET configured (encrypted vault). Keys are shown briefly at create time; if you dismiss that callout, Reveal can decrypt the stored vault copy for owners/managers. Rate-limited (~10/hour/user) and written to household activity. Without the vault secret, rotate the key instead.

OpenAPI

Machine-readable contract for all paths above (plus MQTT bridge and devices CRUD). Prefer the downloaded YAML over any truncated preview.

Download openapi.yaml Open in browser

Guides & next steps

Frequently asked questions

Auth, limits, and where the full OpenAPI lives.

Where is the ThermalTrace OpenAPI spec?

Download openapi.yaml from /openapi.yaml on thermaltrace.dev (also mirrored on the GitHub Pages developer docs). The in-app page at /docs/api is the human quick reference with curl examples, rate limits, and error codes.

How do I authenticate to the HTTP API?

Device firmware uses a per-device ingest key in the URL (or X-Ingest-Key for the MQTT bridge). Pro integrations use a Bearer API key from Dashboard → Share. The browser dashboard uses session cookies, not for third-party clients. Share and inbound routes use opaque tokens in the path.

What are the ingest rate limits?

Push ingest accepts about 64KB max body and about 60 requests per minute per device key (per Worker isolate). Oversized bodies return 413; rate limit returns 429. Keep firmware under those ceilings: typical garage probes POST every 1–5 minutes.

What does “encrypted vault” mean for reveal-ingest-key?

When the deployment sets INGEST_KEY_ENCRYPTION_SECRET, new push keys are stored encrypted so owners can Reveal ingest key later from Devices (rate-limited and audited). On thermaltrace.dev this is enabled. If the vault secret is missing, create/rotate a key and copy it from the 30-minute callout, there is nothing to decrypt later.

Where do I find full request/response schemas?

openapi.yaml is the source of truth. Longer walkthroughs live at doodersrage.github.io/thermaltrace (ingest, Grafana, webhooks). Product how-tos: thermaltrace.dev/about/ingest-and-webhooks and /about/adding-devices.

What is the claim puck API?

Companion-session endpoints under /api/pucks (register, claim/start, claim/finish) plus GET/PUT /api/bays/{bay}/mood. Used by the RP2040-Zero claim puck and Bay Buddy. Setup: thermaltrace.dev/claim-puck. Details on /docs/api#claim-puck.