shinnslist

api keys LIVE

Authentication for the shinnslist api: get a key, send it on every call, and read exactly what the server returns when something goes wrong. Everything below describes code that is actually deployed — anything still planned is marked DRAFT.

working reference. The endpoints, tiers, quotas, and error shapes on this page match the deployed functions code (functions/api/keys.js, functions/api/keys/usage.js, functions/lib/api-keys.js). Where the code has a seam for a future feature but no endpoint yet (rotation, revocation, pro issuance), the section says so — we don't document endpoints that don't exist.

getting a key — POST /api/keys

Keys are free and self-service. One request, no signup, no card:

curl -s -X POST "https://shinnslist.com/api/keys" | jq '{ok, tier, limits, note}'

A successful response looks like this (the raw key is shown exactly once — it is never stored in readable form, so save it now):

{
  "ok": true,
  "key": "sk_live_<43-char-secret>",
  "tier": "free",
  "limits": {
    "intel_per_day": 25,
    "requests_per_minute": 10,
    "v1_calls_per_month": 1000,
    "v1_price_per_call_usd": 0.003
  },
  "note": "This key is shown only once and is never stored in readable form. Send it as the x-api-key header, ?key=, or Authorization: Bearer. v1 signal APIs: POST /v1/signals/{signal}/evaluate."
}

Details, all verified in code:

sending the key

On /api/intel and the rest of the REST surface, send the key as the x-api-key header (preferred) or as the ?key= query parameter. The v1 signal APIs (POST /v1/signals/{signal}/evaluate) accept the same two plus Authorization: Bearer.

curl -s "https://shinnslist.com/api/intel?q=Richmond,VA" \
  -H "x-api-key: sk_live_YOUR_KEY_HERE" | jq '.signals | keys'

No key still works — you fall back to the anonymous tier (5 parcel queries/day per IP). A wrong key is rejected, not demoted: 401, see error responses.

tiers & quotas

tiersignalsintel / dayreq / minhow issued
anon (no key)all5 per IP2 per IPautomatic
freeall2510POST /api/keys
proall100060reserved — payments track only

Quota is the gate for free today: every key carries entitlements: ["*"], so any signal works up to the quota. v1 signal APIs have their own monthly seam: 1,000 calls/month free, then $0.003 per call with a hard cap — no surprise charges.

known limitation: the daily quota counter is not atomic (Cloudflare KV has no transactions), so bursts can overshoot the cap slightly. Acceptable for freemium gating; hard metering moves to a transactional store later.

checking usage — GET /api/keys/usage

Requires a valid key (x-api-key header or ?key=). Anonymous callers get 401 {"ok": false, "error": "api key required for /api/keys/usage"}. The response never reveals the key hash:

{
  "ok": true,
  "tier": "free",
  "entitlements": ["*"],
  "created": "2026-09-28T14:02:11.000Z",
  "quota": { "used": 3, "limit": 25, "remaining": 22, "resets_at": "2026-09-29T00:00:00.000Z" },
  "rate": { "per_minute": 10 },
  "v1_monthly": { "limit": 1000, "used": 41, "remaining": 959, "price_per_call_usd": 0.003 },
  "note": "metering seam: counters feed future metered billing; no charges today"
}

error responses

Every error is JSON with an ok: false envelope. These are the exact shapes the code returns — copied, not paraphrased.

key security

planned: key rotation DRAFT

There is no rotation endpoint today — no POST /api/keys/rotate, no DELETE /api/keys, no self-service revocation. If a key is compromised, the only honest move is to mint a new key via POST /api/keys and stop using the old one. Endpoint names and flows here are not final; the real rotation docs land on this page the day the endpoints ship.

planned: revocation DRAFT

The D1 key store already has a revoked_at column and lookups reject revoked keys — a revoked key behaves exactly like an invalid key (401). But there is no endpoint that sets it: revocation is currently an operator-side action, not self-service. Details and the real endpoint ship here when they exist.

planned: usage dashboard DRAFT

Until a dashboard ships, GET /api/keys/usage is the usage interface: poll it for quota.used / quota.remaining / v1_monthly. No dashboard page, no emailed quota alerts, and no usage history endpoint exist yet — all not final.

planned: pro tier issuance DRAFT

pro (1000 intel/day, 60 req/min) exists in the tier config but is marked reserved: true: POST /api/keys never issues it, and there is no other issuance path. Pro issuance ships with the payments track. The price-per-call seam ($0.003/call on v1) is the only paid-shaped number live today — and it's modeled as hard-capped free, not a charge.

next: getting started · api reference · docs hub