API Documentation
Free legislative data API. Every member, every bill, every vote in the 119th Congress. No auth, no signup, JSON responses.
Quick Start
No API key required. All endpoints return JSON. Try it now:
curl https://opengov.info/api/members?state=CA&party=D&limit=2{
"total": 54,
"total_senators": 4,
"total_reps": 50,
"members": [
{
"member_id": "S424",
"bioguide_id": "B001320",
"display_name": "Laphonza Butler",
"first_name": "Laphonza",
"last_name": "Butler",
"party": "D",
"state": "CA",
"chamber": "senate"
},
{
"member_id": "S413",
"bioguide_id": "P000145",
"display_name": "Alejandro Padilla",
"first_name": "Alejandro",
"last_name": "Padilla",
"party": "D",
"state": "CA",
"chamber": "senate"
}
],
"filters": {
"parties": ["D", "I", "R"],
"states": ["AK", "AL", "AR", "..."],
"chambers": ["senate", "house"]
}
}Core Endpoints
The essentials: members, bills, votes, sponsors, and comparisons.
/api/members
List members of Congress
Returns all members with optional filtering by state, party, and chamber. Supports pagination. Senators are sorted before representatives.
curl https://opengov.info/api/members?state=TX&party=R&chamber=senate{
"total": 2,
"total_senators": 2,
"total_reps": 0,
"members": [
{
"member_id": "S346",
"bioguide_id": "C001056",
"display_name": "John Cornyn",
"party": "R",
"state": "TX",
"chamber": "senate"
},
{
"member_id": "S380",
"bioguide_id": "C001098",
"display_name": "Ted Cruz",
"party": "R",
"state": "TX",
"chamber": "senate"
}
],
"filters": { "parties": ["D","I","R"], "states": ["AK","...","WY"], "chambers": ["senate","house"] }
}/api/member/{member_id}/profile
Full member profile with analysis
Returns member details, voting record, issue priorities, and legislative analysis. Uses the member_id from /api/members (e.g., S413), not the bioguide_id.
curl https://opengov.info/api/member/P000145/profile{
"senator": {
"bioguide_id": "P000145",
"display_name": "Alejandro Padilla",
"party": "D",
"state": "CA",
"member_id": "S413",
"website": "https://www.padilla.senate.gov"
},
"analysis": {
"record": {
"bills_sponsored": 178,
"total_votes": 1350,
"participation_rate": 95.6,
"yea_votes": 690,
"nay_votes": 600,
"missed_votes": 60
},
"issue_priorities": ["..."],
"voting_stances": {},
"report_card": {}
},
"recent_votes": ["..."]
}Note: The member_id field (e.g., S413) can be found in the /api/members response. The bioguide_id (e.g., P000145) also works for profile lookup.
Note: First request for an uncached profile may take 10-60 seconds. Subsequent requests return in under 1 second from cache.
/api/bill/{bill_id}
Bill detail with summary and text
Returns bill metadata, plain-English summary (one_liner), status, full text chunks, and citation data. Note: the URL uses /api/bill/ (singular), not /api/bills/.
curl https://opengov.info/api/bill/BILLS-119sjres88{
"bill_id": "BILLS-119sjres88",
"title": "Terminating the national emergency declared to impose global tariffs.",
"short_title": "Terminating the national emergency declared to impose global tariffs.",
"one_liner": "Ends the national emergency used to impose sweeping global tariffs on U.S. imports",
"description": "This joint resolution terminates the national emergency...",
"status": "es",
"congress": 119,
"chamber": "Senate",
"govtrack_url": "https://www.govtrack.us/congress/bills/119/sjres88",
"heat_breakdown": {},
"chunks": ["..."],
"citations_detail": ["..."]
}Note: Sponsor information is not included in this response. Use /api/bill/{bill_id}/sponsors instead.
Note: The one_liner field is AI-generated (Claude Haiku). The title and description fields are from official government sources.
/api/bill/{bill_id}/votes
Vote breakdown by party
Returns roll-call vote data including party-level breakdowns for yea, nay, not voting, and present.
curl https://opengov.info/api/bill/BILLS-119sjres88/votes[
{
"vote_id": "s600-119.2025",
"question": "On the Joint Resolution S.J.Res. 88",
"date": "2025-01-01T00:00:00.000000000+00:00",
"breakdown": {
"Yea": { "D": 45, "I": 2, "R": 4 },
"Nay": { "R": 47 },
"Not Voting": { "R": 2 },
"Present": {}
}
}
]Note: Party keys use short codes: D (Democrat), I (Independent), R (Republican). Legacy full-name keys may appear with value 0 -- ignore them and use the short codes only.
/api/bill/{bill_id}/sponsors
Sponsor and cosponsor list
Returns the primary sponsor and all cosponsors with contact information.
curl https://opengov.info/api/bill/BILLS-119sjres88/sponsors{
"sponsor": {
"member_id": "S247",
"name": "Ron Wyden",
"party": "D",
"state": "OR",
"office": "221 Dirksen Senate Office Building",
"phone": "202-224-5244",
"website": "https://www.wyden.senate.gov"
},
"cosponsor_count": 6,
"cosponsors": [
{
"member_id": "S362",
"name": "Timothy Kaine",
"party": "D",
"state": "VA",
"office": "231 Russell Senate Office Building",
"phone": "202-224-4024"
}
]
}/api/compare/{member_id_1}/{member_id_2}
Side-by-side member comparison
Compares two members' voting records, showing agreement rate, common votes, and priority differences. Requires internal member_id format (e.g., S413), not bioguide_id.
curl https://opengov.info/api/compare/S413/S427{
"senator_1": {
"display_name": "Alejandro Padilla",
"party": "D",
"state": "CA"
},
"senator_2": {
"display_name": "Adam Schiff",
"party": "D",
"state": "CA"
},
"agreement_rate": 0.93,
"agreements": 293,
"disagreements": 22,
"common_votes": 315,
"agreement_by_type": {
"cloture": { "agreement_rate": 0.95 },
"legislation": { "agreement_rate": 0.91 },
"nominations": { "agreement_rate": 0.94 }
},
"priorities_1": ["..."],
"priorities_2": ["..."]
}Note: The member_id (e.g., S413, S427) is found in the /api/members response. Passing bioguide_id here will return 404.
/api/browse
Browse bills by policy category
Paginated bill browsing filtered by CRS policy area category. The required parameter is "category" (not "topic").
curl 'https://opengov.info/api/browse?category=health&issue=healthcare&per_page=2'{
"category": "health",
"issue": "healthcare",
"total": 1800,
"page": 1,
"per_page": 2,
"total_pages": 900,
"enacted": false,
"query": "",
"bills": [
{
"bill_id": "BILLS-119hr1234",
"title": "To amend title XVIII of the Social Security Act...",
"short_title": "Medicare Access Act",
"one_liner": "Expands Medicare coverage for preventive services",
"congress": 119,
"status": "ih",
"status_label": "Introduced in House"
}
]
}Note: Using ?topic= instead of ?category= will return a 400 error. The category parameter is required.
Note: Category values are lowercase CRS policy area slugs: health, crime, defense, education, etc.
/api/health
Service health check
Returns the status of all backend services: Neo4j, PostgreSQL, and Redis.
curl https://opengov.info/api/health{
"status": "ok",
"services": {
"neo4j": "ok",
"postgres": "ok",
"redis": "ok"
}
}Graph-Native Endpoints
Built on Neo4j with vector embeddings. These endpoints answer questions that relational databases cannot: "What bills are semantically similar?" and "How are two unrelated bills connected through the legislative graph?"
/api/insights/similar-bills/{bill_id}
Find semantically similar bills
Uses 384-dimensional vector embeddings (all-MiniLM-L6-v2) to find bills with similar content, not just similar metadata. Returns cosine similarity scores.
curl https://opengov.info/api/insights/similar-bills/BILLS-119sjres88{
"query_bill": "BILLS-119sjres88",
"similar_bills": [
{
"bill_id": "BILLS-119hjres88",
"title": "Terminating the national emergency...",
"similarity_score": 0.94,
"congress": 119
},
{
"bill_id": "BILLS-119s1234",
"title": "To prohibit the use of emergency powers for tariffs...",
"similarity_score": 0.82,
"congress": 119
}
]
}Note: Similarity is computed using cosine distance between bill text embeddings in Neo4j's vector index. Higher scores indicate stronger semantic similarity.
/api/insights/bill-connection/{bill_id_1}/{bill_id_2}
How two bills are connected
Returns a human-readable path description explaining how two bills are connected through shared sponsors, issues, objectives, or voting patterns. Uses Neo4j's shortestPath algorithm.
curl https://opengov.info/api/insights/bill-connection/BILLS-119hr100/BILLS-119s500{
"connection_exists": true,
"path_length": 3,
"path_description": "HR 100 and S 500 are connected through shared sponsor Sen. Murray (D-WA) and the Healthcare issue area.",
"nodes": [
{ "type": "Bill", "id": "BILLS-119hr100" },
{ "type": "Member", "id": "S229", "name": "Patty Murray" },
{ "type": "Bill", "id": "BILLS-119s500" }
]
}Note: Returns { "connection_exists": false } with HTTP 404 if no connection can be found within the graph.
Rate Limits and Fair Use
Free for any non-commercial use. No authentication required. Please throttle requests to 60 requests per minute.
For higher volume, commercial use, or if you want to discuss integration, email [email protected].
Data Freshness
ID Formats
OpenGov uses two identifier systems. Understanding these prevents common mistakes when chaining API calls together.
| Entity | ID Format | Example | Where to Find It |
|---|---|---|---|
| Member | member_id | S413 | The member_id field in any /api/members response |
| Member (alt) | bioguide_id | P000145 | Library of Congress standard ID. Works for /profile, not for /compare |
| Bill | BILLS-{congress}{type}{number} | BILLS-119sjres88 | The bill_id field in any bill response. Types: hr, s, hjres, sjres, hres, sres, hconres, sconres |
Common pitfall: The /api/compare endpoint requires member_id (e.g., S413), not bioguide_id (e.g., P000145). Using bioguide_id will return 404. Get the member_id from the /api/members response first.
Response Format
Successful response
{
"members": [...],
"total": 54,
"filters": {...}
}Error response
{
"error": "Bill not found"
}
HTTP 404All responses use Content-Type: application/json. Errors include an error field with a human-readable message.
Source Code and Methodology
OpenGov is built with Flask, Neo4j, Next.js, and Redis. The API serves data from a graph database of 12,337 bills, 1,021 votes, and 548 members.
Data methodology, update frequency, and what's machine-generated vs raw are documented at /methodology.
Found a bug or have a question? Email [email protected] or open an issue on GitHub.