Iowa Funnel
The Iowa Funnel API
A free, read-only JSON API for the same public records the site shows: bills, votes, legislators, committees, counties, cities and school districts, elections, campaign money totals and the state budget. For spreadsheets, every dataset is also a CSV download.
Get a free key
Keys are free. Sign in (no password needed) to make one.
Sign in to get a keyHow it works
- A free key. Send it in the
X-Api-Keyheader (or as?api_key=, which is easier to try but ends up in logs and browser history). - 1,000 requests an hour per key. Each response says how many are left (
X-RateLimit-Remaining) and when the count starts over (X-RateLimit-Reset). Past the limit you get status 429. - Read-only, GET only. Any website may call it from the browser (CORS is open). Responses are cached for five minutes, so data can be a few minutes behind the site.
- Every response has
data, andmetawith thesource,as_of(when that source last loaded), and for listspage,per_page(up to 500),totaland thenextpage’s address. - What’s left out: anything about the people who use Iowa Funnel (accounts, follows, saved addresses, emails), admin data, individual donors, payments to individuals, school administrators’ contacts and private court cases.
- Terms: free; please credit “Iowa Funnel” and link to the page; no guarantee it’s complete, current or always up. See the terms.
Try it
curl -H "X-Api-Key: YOUR_KEY" "https://iowafunnel.com/api/v1/bills?ga=91&per_page=5"const res = await fetch("https://iowafunnel.com/api/v1/bills?ga=91&per_page=5", { headers: { "X-Api-Key": "YOUR_KEY" } });
const { data, meta } = await res.json();
console.log(meta.total, data[0].number, data[0].title);{
"data": [{ "ga": 91, "number": "HF 2", "title": "...", "status": "...", "page": "https://iowafunnel.com/bills/91/HF2" }],
"meta": { "source": { "name": "Iowa Legislature", "url": "https://www.legis.iowa.gov" },
"as_of": "2026-11-13T19:03:41Z", "page": 1, "per_page": 5, "total": 2210,
"next": "/api/v1/bills?ga=91&page=2&per_page=5" },
"attribution": "Iowa Funnel (iowafunnel.com), from public records"
}Endpoints
All start with https://iowafunnel.com/api/v1.
GET /billsBills in a session or General Assembly, newest first. Options: ga, session, topic, status, page, per_page.GET /bills/:ga/:numberOne bill: its title, status, committee and dates.GET /bills/:ga/:number/actionsEvery step in a bill’s history.GET /bills/:ga/:number/votesA bill’s House and Senate floor votes.GET /votesFloor votes in a session, newest first. Options: ga, session, chamber, page, per_page.GET /votes/:idOne floor vote, with how each member voted.GET /legislatorsMembers now serving (or, with elect=1, the members-elect). Options: chamber, elect.GET /legislators/:idOne legislator: seats held by Assembly, and committees.GET /committeesHouse, Senate and joint committees.GET /committees/:idOne committee and its members.GET /places/:typeCounties, cities or school districts (type: counties, cities, schools), each with its newest money figures. Options: page, per_page.GET /places/:type/:keyOne county (by slug, like polk), city (by state code, like 77G021) or school district (by code, like 1737), every figure by year.GET /electionsElection dates, newest first, with how many races each had.GET /elections/:date/racesEvery federal, statewide, legislative and judicial race on a date, with candidates and votes. Options: page, per_page.GET /races/:idOne race (or ballot question) and its results.GET /campaign-moneyMoney raised, spent and on hand by candidates for Congress and statewide office (totals only).GET /campaign-money/pacsEach PAC’s money raised, spent and given to other committees in a year. Options: year, page, per_page.GET /budgetGeneral Fund budget lines by year (actual, enacted, estimated or the Governor’s). Options: fy, area, page, per_page.
Errors
Errors come back as { "error": { "status": 401, "message": "..." } }: 401 for a missing or revoked key, 404 when nothing’s at that address, 429 past the hourly limit, and 503 when the database is busy (try again shortly).