API

Programmatic access to the quotes archive. JSON over HTTPS, versioned at /v1.

Authentication

Every request requires your key in an X-API-Key header (an Authorization: Bearer <key> header also works). Contact us to be issued a key.

curl -H "X-API-Key: $KEY" https://onrecord.app/v1/quotes?speaker=zelensky

Tiers

The free tier is delayed: real-time access to what leaders said in the last four days is the paid upgrade.

Endpoints

GET /v1/quotes

Returns a paginated list of quotes. Query params:

GET /v1/quotes/<id>

Returns a single quote. Free-tier requests for a quote inside the 4-day real-time window return 403 freshness_gated.

GET /v1/leaders

Returns all tracked leaders with slug, name, country, and quote count.

GET /v1/leaders/<slug>

Returns one leader with quote count and earliest/latest quote dates.

GET /v1/tags

Returns all tags, optionally filtered by q.

Rate limits

Limits are per-key, per-minute (see Tiers). Over-limit responses return 429 with a Retry-After header. Every response carries RateLimit-Limit and RateLimit-Remaining.

Errors

Errors use a consistent envelope:

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit of 60 requests/min exceeded for the free tier.",
    "doc_url": "https://onrecord.app/api"
  }
}

Response shape

{
  "total": 24687,
  "page": 1,
  "per_page": 20,
  "tier": "free",
  "realtime": false,
  "quotes": [
    {
      "id": 42,
      "text": "...",
      "speaker": {
        "name": "Volodymyr Zelensky",
        "slug": "zelensky",
        "country": "Ukraine"
      },
      "source_type": "speech",
      "source_url": "https://...",
      "source_label": "President of Ukraine",
      "published_at": "2026-05-12T14:00:00",
      "collected_at": "2026-05-12T15:10:00",
      "tags": ["ukraine", "diplomacy"]
    }
  ]
}