API
Last updated: 2026-11-07Everything on this page answers today, without a key, from the same code that renders the pages, so a number you read here is the number the page shows. There is no version in these paths yet and nothing here calls a race. If you build on it, read the sections on caching, rate limits and data use; they are the whole of the contract.
What answers
The table scrolls sideways to the cache and limit columns.
| Endpoint | What you get | Cache-Control | Limit per client |
|---|---|---|---|
/bill/<slug>/?format=json | One bill or resolution | public, max-age=300, s-maxage=3600 | none of its own |
/legislator/<bioguide>/?format=json | One member of Congress | public, max-age=300, s-maxage=3600 | none of its own |
/vote/<id>/?format=json | One roll-call vote | public, max-age=300, s-maxage=3600 | none of its own |
/floor/live.json | Both chambers now, plus the last 18 hours (and the Senate's Congressional Record votes since yesterday) | public, max-age=30, stale-while-revalidate=10 | 120 an hour |
/api/zip-lookup/<zip>/ | The House members and senators for a ZIP | public, max-age=900 | 60 an hour |
/elections/results.json | 2026 results from the state feeds | documented at /elections/api/ | |
All are GET, all return application/json, and all carry Access-Control-Allow-Origin: *, so a page on any other site can fetch them directly. Dates are YYYY-MM-DD; timestamps are ISO 8601 with an offset. On-site links come back as a site-relative path; prefix https://openamerica.io.
A bill
The slug is <congress>-<TYPE>-<number>, the same one in the page URL: 119-HR-1, 119-S-2296, 119-HCONRES-89. Types are HR, S, HRES, SRES, HJRES, SJRES, HCONRES and SCONRES.
curl -s 'https://openamerica.io/bill/119-HR-1/?format=json'
Abbreviated response, as the site returned it on 2026-09-25:
{
"type": "bill",
"url": "https://openamerica.io/bill/119-HR-1/",
"legislation_id": "119-HR-1",
"congress": 119,
"legislation_type": "HR",
"legislation_number": 1,
"title": "An act to provide for reconciliation pursuant to title II of H. Con. Res. 14.",
"origin_chamber": "House",
"policy_area": "Economics and Public Finance",
"subjects": ["Abortion", "Accounting and auditing", "Administrative law and regulatory procedures", "..."],
"date_introduced": "2025-05-20",
"latest_action": {"text": "Became Public Law No: 119-21.", "date": "2025-07-04"},
"lifecycle": "enacted",
"sponsor": {
"bioguide_id": "A000375",
"name": "Arrington, Jodey C.",
"state": "Texas",
"party": "Republican",
"image_url": "https://www.congress.gov/img/member/115_rp_tx_19_arrington_jodey_200.jpg",
"path": "/legislator/A000375/"
},
"cosponsor_count": 0,
"actions_preview": [
{"date": "2025-07-04", "text": "Became Public Law No: 119-21.", "type": "36000"},
{"date": "2025-07-04", "text": "Signed by President.", "type": "36000"},
"..."
],
"congress_gov_source": "https://api.congress.gov/v3/bill/119/hr/1?format=json",
"path": "/bill/119-HR-1/"
}
| Field | Type | Meaning |
|---|---|---|
type | string | Always bill. |
url | string | The absolute URL of the page this record belongs to. |
legislation_id | string | The slug. |
congress | integer | The Congress, for example 119. |
legislation_type | string | One of the eight types above. |
legislation_number | integer | The number within the type. |
title | string | The title as congress.gov gives it. |
origin_chamber | string or null | House or Senate. |
policy_area | string or null | The congress.gov policy area. |
subjects | array of strings | The congress.gov legislative subjects. Can be long, can be empty. |
date_introduced | date or null | When it was introduced. |
latest_action | object | text (string or null) and date (date or null): the newest action. |
lifecycle | string | One of active, enacted, agreed, vetoed, died. Our classification of where the bill stands, biased toward active when unsure; the methodology page explains it. |
sponsor | object or null | The sponsor's summary: bioguide_id, name, state, party, image_url, path. |
cosponsor_count | integer | How many cosponsors. The list itself is on the page. |
actions_preview | array | The newest 25 actions, newest first, each with date (date or null), text (string) and type (string, the congress.gov action code). |
congress_gov_source | string | The api.congress.gov record this was read from. |
path | string | The site-relative page path. |
Not included: bill text, the CRS or AI summary, the cosponsor list, amendments, related bills, committee referrals and roll-call votes. They are on the page.
A member of Congress
Keyed by the bioguide ID that congress.gov uses; upper case, and the same one in the page URL.
curl -s 'https://openamerica.io/legislator/A000370/?format=json'
The full response on 2026-09-25:
{
"type": "legislator",
"url": "https://openamerica.io/legislator/A000370/",
"bioguide_id": "A000370",
"name": "Adams, Alma S.",
"state": "North Carolina",
"party": "Democratic",
"image_url": "https://www.congress.gov/img/member/a000370_200.jpg",
"path": "/legislator/A000370/",
"first_name": "Alma",
"last_name": "Adams",
"current_member": true,
"official_website": "https://adams.house.gov",
"birth_year": 1946,
"totals": {"bills_sponsored": 183, "bills_cosponsored": 2420}
}
| Field | Type | Meaning |
|---|---|---|
type | string | Always legislator. |
url | string | The absolute URL of the member's page. |
bioguide_id | string | The congress.gov bioguide ID. |
name | string | Inverted, as the Clerk writes it: Last, First M. |
state | string | The full state name. |
party | string | Democratic, Republican or Independent. |
image_url | string or null | The congress.gov portrait. |
path | string | The site-relative page path. |
first_name, last_name | string | Present when we hold the member's full record, which is every current member. |
current_member | boolean | Whether the member serves in the current Congress. |
official_website | string or null | The member's official site. |
birth_year | integer or null | Birth year, when congress.gov gives it. |
totals | object | bills_sponsored and bills_cosponsored: career counts, amendments excluded, from the same source as the page. |
senate_class, next_election_year | string, integer | Senators only: the Senate class and the year that seat is next on the ballot. |
leadership | array | Only when the member holds a current leadership role: each entry has role (string), congress (integer) and current (boolean). |
Not included: the voting record, committee seats, party unity, missed votes, sponsored bills and contact details. They are on the page.
A roll-call vote
The id is Open America's own integer, the one in the page URL. Find them on the votes list, on a bill page, or in the senate_recent_votes of the floor feed below.
curl -s 'https://openamerica.io/vote/10782/?format=json'
The full response on 2026-09-25:
{
"type": "vote",
"url": "https://openamerica.io/vote/10782/",
"vote_id": 10782,
"congress": 119,
"chamber": "S",
"date": "2026-09-24T17:45:00+00:00",
"date_precision": "minute",
"source": "chamber_xml",
"question": "On the Concurrent Resolution H.Con.Res. 89",
"result": "rejected",
"bill": {
"legislation_id": "119-HCONRES-89",
"title": "Directing the President, pursuant to section 5(c) of the War Powers Resolution, to remove United States Armed Forces from hostilities with Iran.",
"path": "/bill/119-HCONRES-89/"
},
"breakdown": {"yea": 49, "not_voting": 1, "nay": 50}
}
| Field | Type | Meaning |
|---|---|---|
type | string | Always vote. |
url | string | The absolute URL of the vote's page. |
vote_id | integer | Open America's id for the vote. |
congress | integer | The Congress. |
chamber | string or null | H or S. |
date | timestamp or null | When the vote closed, with offset. When date_precision is day, only the day is known and the time reads noon Eastern. |
date_precision | string | minute when date is the time the vote closed; day when the source printed only the day. |
source | string | chamber_xml for a vote from clerk.house.gov or senate.gov; congressional_record for a Senate roll call read from the Congressional Record on govinfo.gov while senate.gov's own vote files are not available to us. Such a vote is replaced in place, under the same vote_id, once senate.gov's record is available. |
question | string | The question as the chamber recorded it. |
result | string | One of passed, failed, agreed_to, rejected, confirmed, not_confirmed, sustained, not_sustained, guilty, not_guilty, override_passed, override_failed, other. |
bill | object or null | The measure voted on, when it is a bill or resolution we hold: legislation_id, title, path. Null for nominations and for votes we could not link. |
breakdown | object | Members by position: yea, nay, present, not_voting. A position nobody took is absent. |
Per-member positions are not in the vote JSON yet; the page lists every member's position, and a versioned endpoint that carries them is on the list below. Party splits, the roll-call number and the session are also page-only for now.
The floor, live
The payload the floor page polls: both chambers' status right now, the House floor narrative from the last 18 hours and the Senate roll calls from the last 18 hours, plus, while senate.gov's vote files are not available to us, the Senate roll calls from the Congressional Record since 00:00 Eastern yesterday (the Record arrives the morning after a vote).
curl -s 'https://openamerica.io/floor/live.json'
The shape of a full response on a day neither chamber sat, so both lists are empty. The values are illustrative, not a captured response; the subline values are in the format described under Changes below.
{
"fetched_at": "2026-09-25T14:44:12.533761+00:00",
"house": {
"ok": true,
"in_session": false,
"is_pro_forma": false,
"subline": "Next session: Mon Sep 28, 12:00 PM ET",
"live_stream": "https://live.house.gov/",
"public_state": "not_in_session",
"public_label": "Not in session",
"state": "adjourned",
"state_label": "Not in session",
"confidence": "high",
"last_activity_at": "2026-09-24T18:33:35+00:00"
},
"senate": {
"ok": true,
"in_session": false,
"is_pro_forma": false,
"subline": "Next session: Mon Sep 28, 3:00 PM ET",
"live_stream": "https://www.senate.gov/isvp/stv.html?type=live&comm=stv&filename=stv092826",
"public_state": "not_in_session",
"public_label": "Not in session",
"state": "stale_data",
"state_label": "Data stale (18h)",
"confidence": "low",
"last_activity_at": "2026-09-24T17:45:00+00:00"
},
"recent_floor": [],
"senate_recent_votes": []
}
| Field | Type | Meaning |
|---|---|---|
fetched_at | timestamp | When this response was built. It moves on every response, so this endpoint has no ETag: poll on a timer. |
house, senate | object | One chamber, with the fields below. |
ok | boolean | The chamber's own status feed answered. |
in_session | boolean | The chamber is sitting now. |
is_pro_forma | boolean | Sitting, but pro forma: no business. |
subline | string | One line in the same format for both chambers: Convened at 10:02 AM ET while sitting or in recess (Convened Sat Sep 26, 10:02 AM ET for a sitting that began before midnight ET), Next session: Mon Sep 28, 3:00 PM ET otherwise. Empty when the next session is not known; for the House, the Clerk's own line when its date cannot be read. |
live_stream | string | Where to watch. |
public_state | string | One of active, pro_forma, scheduled, recessed, not_in_session. Build on this one. |
public_label | string | The label the page shows for public_state. |
state, state_label, confidence | string | The diagnostic detail behind public_state, including our own freshness doubts (stale_data, unreachable). The vocabulary is internal and can change; confidence is high, medium or low. |
last_activity_at | timestamp or null | The newest floor action or vote we hold for the chamber, among those with a known time (a roll call from the Congressional Record has none, so it never counts). |
recent_floor | array | House floor narrative from the last 18 hours, newest first, at most 40. Each item: id (integer, the Clerk's id for the action), time_iso (timestamp, Eastern offset), time_label (string, for example 5:18 PM EDT), action_item (string, the Clerk's item label such as H.R. 1, or empty), bill_slug (string, or empty), desc (string, the narrative). |
senate_recent_votes | array | Senate roll calls from the last 18 hours, and from the Congressional Record since 00:00 Eastern yesterday, newest first, at most 15. Each item: id (the vote id above), time_iso, time_label (for a roll call from the Congressional Record, which prints no time: time_iso is the date alone and time_label reads, for example, Sep 30, time not in the Record), roll_call (integer), question (cut at 180 characters), result and result_label, outcome_class (success, danger or empty), yea and nay (integers), bill_slug (string, or empty), detail_url (the vote's path). |
The site's own page polls this once a minute and holds a push stream between polls. Poll no faster than every 30 seconds: the limit is 120 requests an hour per client, which is exactly one every 30 seconds, and over IPv6 a client is the whole /64 network (see rate limits). The Senate has no minute-by-minute narrative feed; its side of this payload is roll calls and status.
Find your representatives by ZIP
The House members whose districts touch the ZIP, resolved through the House's own ziplook service and cached on our side for 30 days, plus the state's two senators.
curl -s 'https://openamerica.io/api/zip-lookup/78201/'
The full response on 2026-09-25:
{
"ok": true,
"zip": "78201",
"state": "TX",
"representatives": [
{"bioguide_id": "C001091", "name": "Castro, Joaquin", "party": "Democratic", "state": "Texas",
"image_url": "https://www.congress.gov/img/member/69d7f5b07304cef7a0c977b1_200.jpg", "detail_url": "/legislator/C001091/"},
{"bioguide_id": "C001131", "name": "Casar, Greg", "party": "Democratic", "state": "Texas",
"image_url": "https://www.congress.gov/img/member/c001131_200.jpg", "detail_url": "/legislator/C001131/"}
],
"senators": [
{"bioguide_id": "C001056", "name": "Cornyn, John", "party": "Republican", "state": "Texas",
"image_url": "https://www.congress.gov/img/member/c001056_200.jpg", "detail_url": "/legislator/C001056/"},
{"bioguide_id": "C001098", "name": "Cruz, Ted", "party": "Republican", "state": "Texas",
"image_url": "https://www.congress.gov/img/member/c001098_200.jpg", "detail_url": "/legislator/C001098/"}
]
}
| Field | Type | Meaning |
|---|---|---|
ok | boolean | true on a 200. On an error it is false, and a reason field says why: zip_not_found (a 404) when the ZIP cannot be resolved, or lookup_unavailable (a 503 with a Retry-After header) when the House's ziplook service does not answer. |
zip | string | The ZIP as looked up. |
state | string | The two-letter state code. |
representatives | array | One member, or several where the ZIP crosses district lines. |
senators | array | The state's two senators. |
| each member | object | bioguide_id, name (inverted), natural_name (the same name in reading order, Joaquin Castro), party, state (the full name), image_url (the congress.gov portrait; empty string when none), photo_url (the portrait as this site serves it: a /media/ path once we hold a copy, otherwise the congress.gov URL; empty string when none) and detail_url (the member's path). |
Election results
/elections/results.json (with ?year= and ?office=) and /elections/seat/<key>.json carry the 2026 results the district map draws, as the official state feeds report them, from November 3. They are keyless, they carry an ETag, and they call no race: any leader or call in them is the state feed's own. Their fields are documented at /elections/api/.
Caching and polling
The bill, member and vote JSON answer with Cache-Control: public, max-age=300, s-maxage=3600 and an ETag. The edge may hold a copy for up to an hour, so a change on the page can take that long to reach the JSON. Send If-None-Match with the ETag you last saw and you get a 304 with no body when nothing changed. A bill or a member changes a few times a day at most, and a vote never changes once it is recorded, so once an hour is plenty.
curl -s -D - 'https://openamerica.io/vote/10782/?format=json' -H 'If-None-Match: W/"14c8d570e3a6616b0f6943aec9af9ceb"'
HTTP/2 304
The floor feed answers with public, max-age=30, stale-while-revalidate=10 and no ETag; poll it on a timer, 30 seconds at the fastest. The ZIP lookup answers with public, max-age=900. The election JSON has its own, shorter times, on its own page.
Rate limits
| Endpoint | Limit |
|---|---|
/floor/live.json | 120 requests an hour per IPv4 address or IPv6 /64 network |
/api/zip-lookup/ | 60 requests an hour per IPv4 address or IPv6 /64 network, and 600 an hour per IPv6 /48 |
| bill, member and vote JSON | No limit of their own beyond the edge cache |
| everything, for crawlers on the slow list | 60 requests a minute site-wide, answered 429 with Retry-After |
A limit counts per client: an IPv4 address, or over IPv6 the /64 network the address is in, not the single address, because one home, office or server is handed a whole /64. Every machine behind one IPv6 connection therefore shares one allowance. A browser signed in to this site is counted by its account on the floor feed instead. Past a limit you get HTTP 429 with an HTML body and a Retry-After header giving the seconds until that limit's hour rolls over. The slow list is the set of crawlers that ignore the crawl delay in robots.txt. Ordinary scripts are not on it and need no special User-Agent.
Cross-origin requests
Every JSON response above carries Access-Control-Allow-Origin: *, on the 200 and on the 304, so a browser page on another domain can fetch() it with no proxy. The header is only ever added to a response produced for a request that carried no cookie, so send the request without credentials, which is the default. An HTML page never carries it.
Errors
A bill, member or vote that does not exist is a 404 with an HTML body, not JSON; check the status before parsing. The ZIP lookup's 404 is JSON, shown above. A request past a rate limit is a 429 with Retry-After.
What this is not
- No race calls. Nothing on this site names a winner; the election JSON repeats what the state feed says and says which state said it.
- No keys, no per-key quotas, no bulk export, no CSV, no list endpoints in JSON. The lists (bills, members, votes, lobbying filings, trades, discharge petitions) are pages.
- No version. These paths are unversioned and will keep answering as they do today. A versioned
/api/v1/is planned, and the policy we intend to publish with it is that within a version fields are only added, a field or endpoint is removed only in a new version with the old one kept running for twelve months after, and a change is noted on this page the day it is decided. - No per-member vote positions in JSON yet, and no lobbying, disclosure or trades JSON yet; those are pages for now.
- No AI summaries in JSON. Where a summary written by a model appears on a page it is labelled AI-generated, and if one is ever added to a JSON response it will carry the same label.
Freshness
While a chamber is in session, floor activity, roll-call votes and White House bill statements are re-checked every minute and new bills, committee meetings and hearings every five minutes; lobbying filings, House and Senate financial disclosures, committee rosters and FEC campaign totals refresh once a day, the Senate's daily floor record hourly through the evening, discharge petitions every six hours, and 2026 election results every five minutes from the state feeds.
How current the bill, vote, floor and Congressional Record feeds are right now is on the status page, which is itself refreshed every two minutes. The methodology page lists the sources behind the data and defines the main statistics.
Data use
The same statement appears on the methodology page, in the Terms of Service and in llms.txt.
Draft. This data-use statement is published for review and its wording may change before it is adopted.
Government records
Source records from congress.gov, the House Clerk (clerk.house.gov and disclosures-clerk.house.gov), senate.gov, lda.gov and whitehouse.gov are works of the United States government. Open America republishes them without any claim of copyright (17 U.S.C. 105) and adds no restriction of its own to them.
State election feeds
The election results on /elections/ come from official state election offices whose terms vary from state to state; at least one publishes its feed under a state copyright notice and marks its results unofficial. Those feeds are not part of any grant made here, and election results are never part of an export or bulk download.
What Open America adds
Open America's own derived fields (transactions parsed from PTR filings, lobbying-to-bill links, LD-203 honoree matches, bill lifecycle states, member statistics and AI summaries) may be used, quoted, republished and built on, for paid or unpaid work, with the attribution "Open America (openamerica.io)" and the date you retrieved the data, subject to the lobbying and disclosure notices below.
Lobbying data
Lobbying data comes from lda.gov, whose terms of service ask three things of anyone who reuses it: cite the date the data was retrieved; do not modify content and still cite it as LDA.gov; and state that "Senate Office of Public Records cannot vouch for the data or analyses derived from these data after the data have been retrieved from LDA.gov." Carry all three with any lobbying figure you take from this site.
Financial disclosures
Financial disclosure data (everything on /disclosures/ and /trades/, and anything derived from a House PTR filing) is subject to 5 U.S.C. 13107(c): a report may not be obtained or used for any commercial purpose other than by news and communications media for dissemination to the general public, to determine or establish anyone's credit rating, or in the solicitation of money for any political, charitable or other purpose, and the Attorney General may seek a penalty of up to $10,000 for a violation. Open America does not sell this data and it is not part of any paid plan.
Live feeds
Repackaging one of the live endpoints as your own API, or reselling the feed as it stands, needs a written agreement: write to [email protected]. There is no Creative Commons licence on the live endpoints; attribution and the notices here are the whole of the grant.
AI summaries
Summaries written by a model are labelled as AI-generated wherever they appear, on a page or in JSON, and where one disagrees with the bill, the bill is right.
References: 17 U.S.C. 105, lda.gov terms of service, 5 U.S.C. 13107.
Changes
This page carries its date at the top. When a field is added, it is added here the same day; a test fails the build when a field the code returns is missing from this page. Questions, or something you need that is not here: [email protected] or report a problem.
- 2026-11-07, vote JSON: two fields added,
sourceanddate_precision. While senate.gov's own vote files are not available to us, Senate roll calls come from the Congressional Record, which prints the day but not the time: such a vote hasdate_precisionday, itsdatereads noon Eastern, it stays in the floor feed'ssenate_recent_votesfrom its day until the end of the next, with atime_labelsuch asSep 30, time not in the Record, and it is not counted inlast_activity_at. No field was removed. - 2026-11-07, ZIP lookup: each member gains
natural_name(the name in reading order) andphoto_url(the portrait from this site's own copy when there is one).nameandimage_urlare unchanged. - 2026-10-27, rate limits: a request past a limit is answered 429 with a
Retry-Afterheader, where it was a 403 with no hint of when to retry. An IPv6 client is counted per /64 network rather than per address, the ZIP lookup also caps an IPv6 /48 at 600 requests an hour, and the floor feed counts a signed-in browser by its account. No field changed. - 2026-09-27,
floor/live.jsonsubline: the format changed. Both chambers now use one format,Convened at 10:02 AM ETorNext session: Mon Sep 28, 3:00 PM ET. Before, the House field carried the Clerk's line verbatim (Next Session: September 28th, 2026 at 12:00 PM) and the Senate's readConvenes at 3:00 p.m.with no day. No field was added or removed. Build onpublic_state, not on this text.