CivicStream Public API · v1

Developer documentation

One key, one base URL, structured JSON for live government meetings, elections, the congressional schedule, politician profiles, and civic news.

Base URL https://civicstream.tv/wp-json/cstv/public/v1
Auth header X-CivicStream-Key
Format application/json
Versioning /public/v1

Quickstart

Three steps to your first response. The free tier needs no card and the key takes effect the moment it's created.

  1. 1

    Create an account & pick a plan

    Sign up on the pricing page. Free works for personal projects; paid tiers unlock higher quotas and more keys.

  2. 2

    Generate a key

    Go to Settings → API and click Create key. The full secret is shown once — copy it immediately, we only store a hash.

  3. 3

    Make your first call

    curl https://civicstream.tv/wp-json/cstv/public/v1/whoami \
      -H "X-CivicStream-Key: csk_live_..."

    You should get back your plan name, current monthly usage, and the key prefix.

Rate limits

Each account has two budgets: a monthly quota and a per-minute burst cap. All keys on an account share those budgets. Hit either and you'll get a 429 Too Many Requests with a Retry-After header (seconds).

PlanMonthly requestsPer-minute burstKeys
Free10,00030 / min1
Starter250,000120 / min1
Pro2,000,000600 / min5
Business10,000,0002,000 / min25
EnterpriseCustomCustomUnlimited

Every response carries headers so you can self-pace:

  • X-RateLimit-Limit — monthly cap on this account
  • X-RateLimit-Remaining — requests left this month
  • X-RateLimit-Reset — UNIX timestamp when the month rolls over
  • X-RateLimit-Minute-Remaining — left in the current minute window

Every tier hard-stops at its monthly cap. Contact us before a launch if you need a custom quota rather than relying on an unexpected overage.

Caching

Caching is required, not optional. Every response includes an ETag and a Cache-Control: public, max-age=N. Send back If-None-Match on subsequent requests and you'll get a 304 Not Modified — which does not count against your quota.

# First call — full response + ETag
curl -i https://civicstream.tv/wp-json/cstv/public/v1/streams/live \
  -H "X-CivicStream-Key: csk_live_..."

# HTTP/1.1 200 OK
# ETag: "ab12cd34"
# Cache-Control: public, max-age=30

# Subsequent call — send ETag back
curl -i https://civicstream.tv/wp-json/cstv/public/v1/streams/live \
  -H "X-CivicStream-Key: csk_live_..." \
  -H "If-None-Match: \"ab12cd34\""

# HTTP/1.1 304 Not Modified  ← free request

Typical max-ages: /streams/live 60s, /news/recent 120s, /schedule/today 300s, /elections/upcoming 1,800s. Cache-friendly clients commonly cut their billable requests by 80–95%.

Errors

Errors are JSON, with a consistent shape. Status code tells you the category; code is a machine code, message is a sentence you can show to a developer (not an end-user).

{
    "code": "rate_limited",
    "message": "Per-minute rate limit exceeded. Slow down and retry in 60 seconds.",
    "data": { "status": 429 }
}
StatusError codeWhat happened
400invalid_requestBad parameter (e.g. limit=abc).
401missing_api_keyNo X-CivicStream-Key header.
401invalid_api_keyKey doesn't match any active record.
403plan_requiredEndpoint requires a higher plan.
401revoked_api_keyKey was revoked — create a new one.
404not_foundResource ID doesn't exist.
429rate_limitedMonthly or per-minute cap hit.
5xxserver_errorOur problem. Retry with exponential backoff.

Endpoints

Data endpoints return JSON and live under https://civicstream.tv/wp-json/cstv/public/v1. Core civic records stay on Free. Badges below identify paid enrichments.

GET /streams/live

Currently live government streams — federal floor, committees, statehouses, city councils. Updated every ~30s. Returns metadata and live status only; stream URLs are not exposed via the API (watch on civicstream.tv).

Example response
{
    "data": [
        {
            "id": 4821,
            "title": "U.S. Senate — Floor",
            "scope": "federal",
            "state": null,
            "started_at": "2026-06-08T14:02:11Z",
            "is_live": true,
            "thumbnail": "https://civicstream.tv/thumbs/4821.jpg"
        }
    ],
    "meta": { "count": 18 }
}
GET /news/recent

Recent civic-news headlines. Use /news for category, search, and pagination.

GET /schedule/today

Today's federal schedule — House, Senate, committees, White House — with start times in UTC.

GET /elections/upcoming

Compact upcoming races. Use /elections for state, office, year, date, and search filters.

GET /elections/calendar

Date-bucketed election calendar. days accepts 1–30.

GET /whoami

Confirms your key. Returns plan, key prefix, monthly usage, and reset timestamp. Free of charge — does not count against quota.

ResourceEndpointFree accessPaid enrichment
Location/location/resolve, /representativesDistricts and public officialsPro: district geometry; Starter: /local/overview
Politicians/politicians, /politicians/{scope}/{id}Directory, search, and public profilesPro: campaign finance and race history
Bills/bills, /bills/{jurisdiction}/{id}Metadata, status, and official linksPro: available bill text
Elections/elections, /elections/{id}Current races and candidatesStarter: result detail; Pro: historical races
Schedules/schedule, /schedule/calendarToday and nearby datesStarter: extended dates; Pro: daily recaps
Streams/streams, /streams/liveDirectory and live statusStarter: incremental sync and larger pages
Committees/committees, /committees/{chamber}/{slug}Committee directory and metadataStarter: membership
News/news, /news/{id}Searchable civic newsStarter: larger pages and unified /search
Integrations/webhooks, /changes, /bulk/{dataset}Starter webhooks; Pro changes; Business bulk

Free responses are capped at 25 records. Starter and Pro allow 100; Business allows 500. The machine-readable contract is at /openapi.json.

Code examples

Same call, three languages. Swap in your real key.

curl https://civicstream.tv/wp-json/cstv/public/v1/streams/live \
  -H "X-CivicStream-Key: $CIVICSTREAM_KEY" \
  -H "Accept: application/json"
const res = await fetch(
  'https://civicstream.tv/wp-json/cstv/public/v1/streams/live',
  { headers: { 'X-CivicStream-Key': process.env.CIVICSTREAM_KEY } }
);
if (!res.ok) throw new Error(`API ${res.status}`);
const { data } = await res.json();
console.log(`${data.length} streams live`);
import os, requests

r = requests.get(
    "https://civicstream.tv/wp-json/cstv/public/v1/streams/live",
    headers={"X-CivicStream-Key": os.environ["CIVICSTREAM_KEY"]},
    timeout=10,
)
r.raise_for_status()
print(len(r.json()["data"]), "streams live")

Rules of the road

Plain-English terms. By using the API you agree to these — the formal version is in the Terms of Service.

  1. One API key per environment. Send it as X-CivicStream-Key on every request.
  2. Quotas are shared by all keys on an account, reset each calendar month, and include a per-minute burst cap. 429 includes Retry-After.
  3. Caching is mandatory. Honour ETag / If-None-Match — 304 responses don't count against quota.
  4. Attribution required on display: “Data via CivicStream” with a link, on any screen that renders the data. Waivable at Enterprise.
  5. Free, Starter, and Pro may not mirror more than 25% of a dataset. Business bulk exports remain subject to the commercial data licence and may not be republished as a competing API.
  6. Stream URLs are not exposed via the API — /streams/live returns metadata and live status only. Viewing happens on civicstream.tv. Scraping or republishing the underlying HLS/MP4 is a bannable offence and a copyright issue.
  7. No PII or engagement endpoints. Comments, chat, donor data, and user info are not exposed.
  8. Free tier is non-commercial — civic tech, journalists, students, hobbyists. Anything ad-supported, paywalled, or sold to clients needs Starter+.
  9. If you exhaust your quota, don't scrape the public site to make up the difference. The WAF will block you.
  10. Deprecations get 90 days' notice. Breaking changes ship under a new version path.
  11. Keys can be revoked without refund for ToS violations. Voter-suppression or harassment use cases are explicitly disallowed.
  12. Uptime: best-effort on Free/Starter, 99.5% on Pro, 99.9% on Business (with credits).

Versioning & changelog

The current version is v1, mounted at /wp-json/cstv/public/v1. Backwards-incompatible changes ship under /v2; v1 stays online for at least 12 months after a successor is released.

  • 2026-07-14 — Added representatives, politicians, bills, committees, stream discovery, full election and schedule queries, news search, webhooks, change feeds, bulk exports, and OpenAPI discovery.
  • 2026-06-08v1 launched: streams, news, schedule, elections, whoami.
Questions or breaking changes you should know about? Email api@civicstream.tv or open a ticket. Paying customers get a reply within 1 business day.
About this civic dataset

About the API documentation

Developer documentation for the Civic Stream public API — authentication, rate limits, endpoints, and request examples for streams, politicians, bills, elections, and news data.

The documentation covers authentication, rate limits, request patterns, response fields, and the endpoints available to each plan.