Home/API

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:

Terminal
curl https://opengov.info/api/members?state=CA&party=D&limit=2
Response
{
  "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.

GET

/api/members

List members of Congress

Returns all members with optional filtering by state, party, and chamber. Supports pagination. Senators are sorted before representatives.

Parameters:
statestringTwo-letter state code (e.g., TX, CA)
partystringD, R, or I
chamberstringsenate or house
limitintMax results to return
offsetintSkip N results (for pagination)
Request
curl https://opengov.info/api/members?state=TX&party=R&chamber=senate
Response
{
  "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"] }
}
GET

/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.

Parameters:
congressintFilter to specific congress (default: all)
Request
curl https://opengov.info/api/member/P000145/profile
Response
{
  "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.

GET

/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/.

Request
curl https://opengov.info/api/bill/BILLS-119sjres88
Response
{
  "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.

GET

/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.

Request
curl https://opengov.info/api/bill/BILLS-119sjres88/votes
Response
[
  {
    "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.

GET

/api/bill/{bill_id}/sponsors

Sponsor and cosponsor list

Returns the primary sponsor and all cosponsors with contact information.

Request
curl https://opengov.info/api/bill/BILLS-119sjres88/sponsors
Response
{
  "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"
    }
  ]
}
GET

/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.

Request
curl https://opengov.info/api/compare/S413/S427
Response
{
  "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.

GET

/api/browse

Browse bills by policy category

Paginated bill browsing filtered by CRS policy area category. The required parameter is "category" (not "topic").

Parameters:
categorystringRequired. Lowercase CRS policy area slug (e.g., health, crime)
issuestringOptional issue taxonomy slug (e.g., healthcare, gun-rights)
congressintFilter to specific congress
qstringText search within bill titles
enactedboolFilter to enacted bills only
pageintPage number (default: 1)
per_pageintResults per page (default: 20, max: 50)
Request
curl 'https://opengov.info/api/browse?category=health&issue=healthcare&per_page=2'
Response
{
  "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.

GET

/api/health

Service health check

Returns the status of all backend services: Neo4j, PostgreSQL, and Redis.

Request
curl https://opengov.info/api/health
Response
{
  "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?"

GET

/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.

Parameters:
limitintMax results (default: 10)
Request
curl https://opengov.info/api/insights/similar-bills/BILLS-119sjres88
Response
{
  "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.

GET

/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.

Request
curl https://opengov.info/api/insights/bill-connection/BILLS-119hr100/BILLS-119s500
Response
{
  "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

Bills and votes
Synced daily at 6:00 UTC
Member profiles
Cached with 7-day TTL, recomputed weekly
Social media posts
Synced every 2-6 hours
Issue classification
New bills classified within 24 hours

ID Formats

OpenGov uses two identifier systems. Understanding these prevents common mistakes when chaining API calls together.

EntityID FormatExampleWhere to Find It
Membermember_idS413The member_id field in any /api/members response
Member (alt)bioguide_idP000145Library of Congress standard ID. Works for /profile, not for /compare
BillBILLS-{congress}{type}{number}BILLS-119sjres88The 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 404

All 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.