Developer API · v1

The AI-regulation dataset, as a clean JSON API

Read-only, versioned access to every AI law and bill we track — US state & federal, the EU, and globally — with a changelog you can poll and HMAC-signed webhooks for changes. Get a free key in seconds.

Get a free keyOpenAPI 3.1 specPricing
Base URL https://ai-law-tracker.com/api/v1

Quick start

Every endpoint works anonymously at a low rate. Add your key to raise the limit and identify your app.

cURL
# List the 5 most recently updated records
curl "https://ai-law-tracker.com/api/v1/laws?limit=5&sort=updated_at&order=desc" \
  -H "X-API-Key: alt_free_9f3c…"
JavaScript (fetch)
const res = await fetch(
  "https://ai-law-tracker.com/api/v1/laws?scope=state&jurisdiction=colorado",
  { headers: { "X-API-Key": process.env.ALT_API_KEY } }
);
const { data, meta } = await res.json();

Authentication

Pass your key on every request in either header:

X-API-Key: alt_free_9f3c…
# or
Authorization: Bearer alt_free_9f3c…

A missing key is fine — you're served as anonymous at the per-IP cap. An invalid or revoked key returns 401/403. Keep keys server-side.

Get a free key

Enter your email — we'll mint a free-tier key and send it over. No card, no wait.

One active key per email. By requesting a key you agree to the Terms. Data is CC BY 4.0 — attribution required on the free tier.

Rate limits

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Over the limit returns 429 with Retry-After.

TierPer minutePer day
Anonymous (no key)20500
Free602,000
Developer1205,000
Pro30050,000
Business1,000500,000

Need more? See paid tiers →

Endpoints

GET/v1/health
Liveness + backend status
Example request
curl "https://ai-law-tracker.com/api/v1/health" \
  -H "X-API-Key: alt_free_9f3c…"
Example response
{
  "api_version": "v1",
  "status": "ok",
  "backend": "supabase",
  "records": 697
}
GET/v1/laws
List legal records (filter, sort, paginate)
ParamInTypeDescription
scopequerystate | federal | eu | globalFilter by scope.
jurisdictionquerystringExact jurisdiction slug (e.g. colorado, eu, us-federal, canada).
statusquerystringCase-insensitive substring match on status.
in_forcequerybooleanFilter by the in_force flag.
updated_sincequerystringOnly records updated at/after this ISO timestamp.
qquerystringSubstring search over title + summary.
sortqueryupdated_at | record_date | title
orderqueryasc | desc
limitqueryinteger
offsetqueryinteger
Example request
curl "https://ai-law-tracker.com/api/v1/laws?scope=state&jurisdiction=value" \
  -H "X-API-Key: alt_free_9f3c…"
Example response
{
  "api_version": "v1",
  "data": [
    {
      "id": "5f9c2b0a-1e34-4d21-9a77-0c1b2d3e4f56",
      "scope": "state",
      "jurisdiction": { "slug": "colorado", "name": "Colorado", "abbr": "CO" },
      "identifier": "SB 24-205",
      "title": "Consumer Protections for Artificial Intelligence",
      "record_type": "bill",
      "status": "Signed — effective 2026-02-01",
      "in_force": null,
      "record_date": "2024-05-17T00:00:00Z",
      "summary": "Requires developers and deployers of high-risk AI systems to use reasonable care to avoid algorithmic discrimination…",
      "source": "leg.colorado.gov",
      "official_url": "https://leg.colorado.gov/bills/sb24-205",
      "updated_at": "2026-07-05T14:02:11Z",
      "attribution": "Data by AI Law Tracker (CC BY 4.0) — https://ai-law-tracker.com"
    }
  ],
  "meta": { "total": 564, "count": 1, "limit": 20, "offset": 0 }
}
GET/v1/laws/{id}
Get one record by uuid
ParamInTypeDescription
id *pathstring
Example request
curl "https://ai-law-tracker.com/api/v1/laws/5f9c2b0a-…" \
  -H "X-API-Key: alt_free_9f3c…"
Example response
{
  "api_version": "v1",
  "data": {
    "id": "5f9c2b0a-1e34-4d21-9a77-0c1b2d3e4f56",
    "scope": "state",
    "jurisdiction": { "slug": "colorado", "name": "Colorado", "abbr": "CO" },
    "identifier": "SB 24-205",
    "title": "Consumer Protections for Artificial Intelligence",
    "status": "Signed — effective 2026-02-01",
    "official_url": "https://leg.colorado.gov/bills/sb24-205",
    "updated_at": "2026-07-05T14:02:11Z",
    "attribution": "Data by AI Law Tracker (CC BY 4.0) — https://ai-law-tracker.com"
  }
}
GET/v1/laws/{id}/history
Full change timeline for one record

Every snapshot of the record (ascending observed_at), each with change_kind, changed_fields and the record values as of that snapshot.

ParamInTypeDescription
id *pathstring
Example request
curl "https://ai-law-tracker.com/api/v1/laws/5f9c2b0a-…/history" \
  -H "X-API-Key: alt_free_9f3c…"
GET/v1/changes
Unified changelog (poll for what changed since X)

Time-ordered feed of every observed insert/update across the dataset, unioned from the append-only history of legal records and jurisdiction summaries. Poll with ?since=<meta.cursor>. Free-beta clamps the lookback window per tier (see meta.window).

ParamInTypeDescription
sincequerystringOnly changes observed after this ISO timestamp (pass the previous response meta.cursor to poll).
scopequerystate | federal | eu | globalFilter by scope.
jurisdictionquerystringExact jurisdiction slug.
entityquerylaw_record | jurisdictionRestrict to one dataset (default: both).
significantquerybooleanDrop internal metadata-only updates (keeps inserts + real field changes).
orderqueryasc | descOrder by observed_at.
limitqueryinteger
offsetqueryinteger
Example request
curl "https://ai-law-tracker.com/api/v1/changes?since=value&scope=state" \
  -H "X-API-Key: alt_free_9f3c…"
Example response
{
  "api_version": "v1",
  "data": [
    {
      "event_id": "a1b2c3d4-0000-4444-8888-abcdef012345",
      "entity": "law_record",
      "record_id": "5f9c2b0a-1e34-4d21-9a77-0c1b2d3e4f56",
      "scope": "state",
      "jurisdiction": { "slug": "washington", "name": "Washington", "abbr": "WA" },
      "identifier": "HB 1170",
      "change_kind": "update",
      "changed_fields": ["status"],
      "field_changes": [{ "field": "status", "from": "In committee", "to": "Passed House" }],
      "observed_at": "2026-07-07T09:15:44.512Z",
      "attribution": "Data by AI Law Tracker (CC BY 4.0) — https://ai-law-tracker.com"
    }
  ],
  "meta": {
    "count": 1, "limit": 50, "offset": 0, "order": "desc",
    "cursor": "2026-07-07T09:15:44.512Z",
    "window": { "tier": "free", "lookback_days": 90, "clamped": false }
  }
}
GET/v1/feed
Lean stream of recent significant changes

Convenience view over /changes with significant=true and no value diffs — the newest meaningful changes, human-scannable.

ParamInTypeDescription
sincequerystringOnly changes observed after this ISO timestamp (pass the previous response meta.cursor to poll).
scopequerystate | federal | eu | globalFilter by scope.
jurisdictionquerystringExact jurisdiction slug.
entityquerylaw_record | jurisdictionRestrict to one dataset (default: both).
limitqueryinteger
Example request
curl "https://ai-law-tracker.com/api/v1/feed?since=value&scope=state" \
  -H "X-API-Key: alt_free_9f3c…"
GET/v1/jurisdictions
List covered jurisdictions with record counts
ParamInTypeDescription
scopequerystate | federal | eu | global
Example request
curl "https://ai-law-tracker.com/api/v1/jurisdictions?scope=state" \
  -H "X-API-Key: alt_free_9f3c…"
Example response
{
  "api_version": "v1",
  "data": [
    { "slug": "california", "name": "California", "abbr": "CA", "scope": "state", "count": 55 },
    { "slug": "eu", "name": "European Union", "abbr": "EU", "scope": "eu", "count": 12 }
  ],
  "meta": { "count": 74 }
}
GET/v1/countries
National (global-scope) jurisdictions with record counts
Example request
curl "https://ai-law-tracker.com/api/v1/countries" \
  -H "X-API-Key: alt_free_9f3c…"
GET/v1/states
US state jurisdictions with record counts
Example request
curl "https://ai-law-tracker.com/api/v1/states" \
  -H "X-API-Key: alt_free_9f3c…"
GET/v1/categories
Dataset facets: record_type + scope distributions
Example request
curl "https://ai-law-tracker.com/api/v1/categories" \
  -H "X-API-Key: alt_free_9f3c…"
POST/v1/keys
Self-serve: issue a FREE API key by email

Submit an email to mint a free-tier key. The plaintext key is emailed to that address AND returned once in this response — it is never stored and cannot be recovered. One active free key per email; abusive request rates are throttled per IP.

Example request
curl "https://ai-law-tracker.com/api/v1/keys" \
  -X POST -H "Content-Type: application/json" \
  -d '{"email":"you@company.com"}'
Example response
{
  "api_version": "v1",
  "key": "alt_free_9f3c…  (shown once — store it now)",
  "key_prefix": "alt_free_9f3c",
  "id": "7c0d…",
  "tier": "free",
  "email": "you@company.com",
  "email_delivery": { "delivered": true },
  "note": "This key is shown only once and cannot be recovered."
}
POST/v1/webhooks
Subscribe to change events (requires an API key)

Create a webhook. When a matching legal record change is observed, an HMAC-SHA256-signed POST is delivered to target_url. The signing_secret is returned ONCE in this response. Verify each delivery (see x-webhooks).

🔑 Requires an API key
Example request
curl "https://ai-law-tracker.com/api/v1/webhooks" \
  -X POST \
  -H "X-API-Key: alt_pro_…" \
  -H "Content-Type: application/json" \
  -d '{"target_url":"https://your-app.com/hooks/alt"}'
Example response
{
  "api_version": "v1",
  "data": {
    "id": "b3c4…",
    "target_url": "https://your-app.com/hooks/alt",
    "events": ["law.created", "law.updated"],
    "active": true,
    "signing_secret": "whsec_… (shown once)",
    "created_at": "2026-07-08T12:00:00Z"
  }
}
GET/v1/webhooks
List this key's webhooks
🔑 Requires an API key
Example request
curl "https://ai-law-tracker.com/api/v1/webhooks" \
  -H "X-API-Key: alt_free_9f3c…"
Example response
{
  "api_version": "v1",
  "data": {
    "id": "b3c4…",
    "target_url": "https://your-app.com/hooks/alt",
    "events": ["law.created", "law.updated"],
    "active": true,
    "signing_secret": "whsec_… (shown once)",
    "created_at": "2026-07-08T12:00:00Z"
  }
}
GET/v1/webhooks/{id}
Get one subscription
🔑 Requires an API key
ParamInTypeDescription
id *pathstring
Example request
curl "https://ai-law-tracker.com/api/v1/webhooks/5f9c2b0a-…" \
  -H "X-API-Key: alt_free_9f3c…"
DELETE/v1/webhooks/{id}
Unsubscribe
🔑 Requires an API key
ParamInTypeDescription
id *pathstring
Example request
curl "https://ai-law-tracker.com/api/v1/webhooks/5f9c2b0a-…" \
  -X DELETE \
  -H "X-API-Key: alt_free_9f3c…"

Webhooks & signature verification

Subscribe with POST /v1/webhooks. Each change is delivered as an HMAC-SHA256-signed POST to your target_url. The signing_secret is returned once when you create the webhook.

HeaderMeaning
X-ALT-Signaturesha256=<hex HMAC-SHA256 of `${timestamp}.${rawBody}` under your signing_secret>
X-ALT-TimestampUnix seconds; folded into the signed content (reject if skew is large).
X-ALT-Eventlaw.created | law.updated
X-ALT-DeliveryDelivery uuid — use as an idempotency key.
X-ALT-Webhook-IdThe subscription uuid.

Verify each delivery before trusting it — recompute the signature over `${timestamp}.${rawBody}`:

Node.js — verify a delivery
const crypto = require('crypto');
function verify(req, secret) {
  const ts = req.headers['x-alt-timestamp'];
  const sig = (req.headers['x-alt-signature'] || '').replace(/^sha256=/, '');
  const expected = crypto.createHmac('sha256', secret).update(`${ts}.${req.rawBody}`).digest('hex');
  const a = Buffer.from(sig), b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Errors

Every error uses one uniform shape:

{
  "api_version": "v1",
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded for the minute window. Retry in 42s.",
    "docs": "https://ai-law-tracker.com/developers",
    "retry_after": 42
  }
}

Common codes: invalid_key (401), revoked_key (403), not_found (404), rate_limited (429), backend_unavailable (503).

License & attribution

Data is licensed CC BY 4.0 — free to use commercially with attribution. Attribution is mandatory on the free tier (a dofollow link to ai-law-tracker.com) and optional on paid tiers. Informational only — not legal advice. Verify against each record's official_url before relying on it.