Making requests

Response format

Successful responses are JSON with data, meta, and links. Fields we add later appear without notice, so ignore fields you don't recognize.

Pagination

Lists return up to limit items (default 50, maximum 200). When there are more, meta.nextCursor and links.next are set; request links.next until it is missing. meta.total is the total number of matches.

async function getAll(url) {
  const items = [];
  while (url) {
    const res = await fetch(url, { headers: { Authorization: 'Bearer ' + process.env.CHICAGO_POLITICS_KEY } });
    if (!res.ok) throw new Error((await res.json()).detail);
    const body = await res.json();
    items.push(...body.data);
    url = body.links.next; // missing on the last page
  }
  return items;
}

const nays = await getAll('https://www.chicagopolitics.org/api/v1/members/12/votes?vote=nay&limit=200');
import os
import requests

session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['CHICAGO_POLITICS_KEY']}"

def get_all(url):
    items = []
    while url:
        r = session.get(url)
        r.raise_for_status()
        body = r.json()
        items += body["data"]
        url = body["links"].get("next")  # missing on the last page
    return items

nays = get_all("https://www.chicagopolitics.org/api/v1/members/12/votes?vote=nay&limit=200")

Caching and CORS

Responses send Cache-Control: private, max-age=60, and most data changes at most daily (see data sources), so cache responses on your side. CORS is open (Access-Control-Allow-Origin: *) and the rate-limit headers are exposed to browsers, but keep keys on a server.