Skip to main content

Documentation Index

Fetch the complete documentation index at: https://dev.1st.app/llms.txt

Use this file to discover all available pages before exploring further.

Key format

Every API key looks like this:
1st_sk_abcdefghijklmnop.qrstuvwxyz23456789abcdefghijklmn
       └────── 16 ──────┘ └─────────── 32 ─────────────┘
            key_id                  secret
  • key_id is the public identifier — stable, lookup-able server-side.
  • secret is the actual credential — only ever stored as an HMAC on our side, and shown to you ONCE at mint time.

Use the key

Every request needs an Authorization: Bearer <full_key> header:
curl -H "Authorization: Bearer 1st_sk_abcdefghijklmnop.qrstuvwxyz23456789abcdefghijklmn" \
  "https://api.1st.app/v1/sensors"

Treat it like a password

API keys grant read access to every sensor reading in your team. Same blast radius as a leaked dashboard password.
AI tools — including Claude, ChatGPT, Cursor — frequently end up with pasted API keys in chat history. We can’t prevent this; you should proactively revoke any key you suspect has been seen by any system you don’t fully control.
The fix-it pattern:
  1. Notice the key may have leaked (committed to a public repo, pasted in chat, sent to a contractor who left).
  2. Open Integrations → API access.
  3. Click Revoke on the affected key. It stops working within seconds.
  4. Mint a fresh key. Update your integration’s ST_API_KEY env var.
Revoking does not break the audit log — past usage of the revoked key stays visible in the admin panel for forensic review.

Where to store the key

  • Env var, always. ST_API_KEY is the convention in our examples.
  • A secret manager for production integrations (AWS Secrets Manager, Doppler, Vercel encrypted env, GitHub Actions secrets).
  • Never commit it to a repo, paste it into a Notion doc, or share it in Slack.

Expiry

Keys can optionally carry an expires_at set at mint time (90 days, 1 year, or never). Once the date passes the middleware rejects every request from the key with api_key_expired. The expiry column is visible on the API keys list so you can rotate before it bites.

Rotation (no-downtime)

To rotate without an outage:
  1. Mint the new key under Integrations → API access.
  2. Update your integration to use the new key.
  3. Verify a successful request lands (GET /v1/team).
  4. Revoke the old key.
Steps 1 and 4 are near-instantaneous, so the integration is never offline.

Scopes

Two scopes in V1:
  • read — list sensors, current conditions, time-series readings, CSV export. Default for new keys.
  • read_write — everything read does, plus PATCH /v1/sensors/{id} to update display names and metadata.
Pick the smaller scope when in doubt. See the Scopes page for the full breakdown.

How verification works

The server stores HMAC-SHA-256(server_secret, secret) for each key — never the plaintext. When you make a request, we look up your key_id, compute the HMAC over the secret you sent, and constant-time compare against the stored hash. This means even an attacker with a database dump cannot derive a usable key, because the server-side HMAC pepper is held outside the database.

Errors

If authentication or authorization fails, you’ll get one of these codes:
CodeCauseFix
api_key_missingNo Authorization header.Add the header.
api_key_invalidHeader malformed, key prefix doesn’t match, or secret wrong.Re-copy the key from the app.
api_key_revokedKey was revoked.Mint a new key.
api_key_expiredKey passed its expiry date.Mint a new key, optionally with longer expiry.
insufficient_scopeKey doesn’t have write scope but called PATCH.Mint a read_write key.