Congress.gov API in Python#

By Sebastian Shirk and Avery Fernandez

The Congress.gov API provides programmatic access to a wide range of U.S. federal legislative information, including bills, amendments, committee reports, and member data.

Please see the following resources for more information on API usage:

NOTE: The Congress.gov API limits requests to a maximum of 5,000 per hour.

These recipe examples were tested on May 7, 2025.

Setup#

Import Libraries#

The following external libraries need to be installed into your enviornment to run the code examples in this tutorial:

We import the libraries used in this tutorial below:

import requests
from time import sleep
import os
from dotenv import load_dotenv

Import API Key#

An API key is required to access the Congress.gov API. You can sign up for one at the Congress.gov API Key Signup page.

We keep our API key in a separate file, a .env file, and use the dotenv library to access it. If you use this method, create a file named .env in the same directory as this notebook and add the following line to it:

CONGRESS_API_KEY=PUT_YOUR_API_KEY_HERE
load_dotenv()
try:
    API_KEY = os.environ["CONGRESS_API_KEY"]
except KeyError:
    print("API key not found. Please set 'CONGRESS_API_KEY' in your .env file.")
else:
    print("Environment and API key successfully loaded.")
Environment and API key successfully loaded.

1. Retrieving Bill Data#

Get Recent Bills#

Get a list of recent bills as well as their provided information.

BASE_URL = 'https://api.congress.gov/v3/'

# Define the endpoint for retrieving bill data
endpoint = 'bill'

# Set the parameters for the API request
params = {
    "api_key": API_KEY,
    "format": "json",
    "limit": 2  # Limit the number of bills retrieved to 2
}

try:
    # Make a GET request to the Congress.gov API to retrieve bill data
    response = requests.get(f"{BASE_URL}{endpoint}", params=params)
    # Raise an exception if the request was unsuccessful
    response.raise_for_status()
    # Parse the JSON response into a Python dictionary
    data = response.json()
    # Extract the list of bills from the response data
    bills = data.get('bills', [])
    
    # Iterate through each bill in the list
    for bill in bills:
        # Get the title of the bill, or use a default message if the title is not available
        title = bill.get('title', 'No title available')
        # Print the title, truncating it if it exceeds 80 characters
        if len(title) > 80:
            print(f"Title: {title[:77]}...")
        else:
            print(f"Title: {title}")
        
        # Print additional details about the bill
        print(f"Text: {bill['latestAction']['text']}")
        print(f"Origin Chamber: {bill['originChamber']}") 
        print(f"Action Date: {bill['latestAction']['actionDate']}")
        print(f"Update Date: {bill['updateDate']}")
        print(f"Number: {bill['number']}")
        print(f"Bill Type: {bill['type']}") 
        print()

# Handle any exceptions that occur during the API request
except requests.exceptions.RequestException as e:
    # Print an error message if the request fails
    print(f"Error fetching data: {e}")
Title: Providing for congressional disapproval under chapter 8 of title 5, United St...
Text: Presented to President.
Origin Chamber: House
Action Date: 2025-05-06
Update Date: 2025-05-07
Number: 75
Bill Type: HJRES

Title: Providing for congressional disapproval under chapter 8 of title 5, United St...
Text: Presented to President.
Origin Chamber: House
Action Date: 2025-05-06
Update Date: 2025-05-07
Number: 42
Bill Type: HJRES

Get Number of Bills in a Specified Time Frame#

Gather the number of bills that were introduced in a specified time frame as well as how many became public law.

This may take a while to run when spanning over certain months, so be prepared to wait if you run this block.

endpoint = 'bill'

max_number_of_bills = 10000
params = {
    "api_key": API_KEY,
    "format": "json",
    "limit": 250,
    "offset": 0,
    "fromDateTime": "2023-01-01T00:00:00Z",
    "toDateTime": "2023-02-28T23:59:59Z"
}

print(f"Fetching bills for {params['fromDateTime']} to {params['toDateTime']}...")

# Initialize an empty list to store all fetched bills
all_bills = []

# Continue fetching bills until the maximum number of bills is reached
while len(all_bills) < max_number_of_bills:
    try:
        response = requests.get(f"{BASE_URL}{endpoint}", params=params)
        sleep(1)
        response.raise_for_status()
        data = response.json()
        
        # Extract the list of bills from the response data
        bills = data.get('bills', [])
        
        # Add the fetched bills to the list of all bills
        all_bills.extend(bills)
        
        # If fewer bills are returned than the limit, all available bills have been fetched
        if len(bills) < params['limit']:
            print(f"Fetched all available bills. Total fetched: {len(all_bills)}")
            break
        
        # Update the offset parameter to fetch the next set of bills
        params['offset'] += params['limit']
    except requests.exceptions.RequestException as e:
        print(f"Error fetching data: {e}")
        break
    
    # Print the current count of fetched bills
    print(f"Fetched {len(all_bills)} bills...")
Fetching bills for 2023-01-01T00:00:00Z to 2023-02-28T23:59:59Z...
Fetched all available bills. Total fetched: 141
filtered_bills = []
for bill in all_bills:
    action_text = bill.get('latestAction', {}).get('text', '').lower()
    if 'became public law' in action_text:
        filtered_bills.append(bill)

print(f"{len(filtered_bills)} of {len(all_bills)} bills became public law.")
110 of 141 bills became public law.

Get Summaries of Recent Bills#

Get all information on given bills as well as their summaries. Summaries are given in HTML format.

endpoint = 'summaries'
params = {
    "api_key": API_KEY,
    "format": "json",
    "limit": 2
}

try:
    response = requests.get(f"{BASE_URL}{endpoint}", params=params)
    response.raise_for_status()
    data = response.json()
    # Extract the list of summaries from the response data
    summaries = data.get('summaries', [])
    
    # Iterate through each summary in the list
    for summary in summaries:
        # Print the title of the bill associated with the summary
        print(f"Title: {summary['bill']['title']}")
        
        # Print the action date of the summary
        print(f"Action Date: {summary['actionDate']}")
        
        # Get the summary text or use a default message if not available
        summary_text = summary.get('text', 'No summary available')
        
        # Print the summary text, truncating it if it exceeds 80 characters
        if len(summary_text) > 80:
            print(f"Summary: {summary_text[:77]}...")
        else:
            print(f"Summary: {summary_text}")
        print()
except requests.exceptions.RequestException as e:
    print(f"Error fetching data: {e}")
Title: Gambling Addiction Recovery, Investment, and Treatment Act
Action Date: 2025-02-06
Summary: <p><strong>Gambling Addiction Recovery, Investment, and Treatment Act</strong...

Title: Homeowners’ Defense Act of 2025
Action Date: 2025-01-28
Summary: <p><strong>Homeowners' Defense Act of 2025 </strong></p><p>This bill allows t...

Get Recent Amemdments#

Get a list of recent amendments as well as their provided information.

endpoint = 'amendment'
params = {
    'api_key': API_KEY,
    'format': 'json',
    'limit': 4
}

print("Recent Amendments:")
try:
    response = requests.get(f"{BASE_URL}{endpoint}", params=params)
    response.raise_for_status()
    data = response.json()
    # Extract the list of amendments from the response data
    amendments = data.get('amendments', [])
    
    # Iterate through each amendment in the list
    for amendment in amendments:
        # Get the latest action details for the amendment
        lastest_action = amendment.get('latestAction', {})
        
        # Check if the latest action exists
        if lastest_action:
            # Print the action date of the amendment
            print(f"Action Date: {lastest_action['actionDate']}")
            
            # Get the action text and truncate it if it exceeds 80 characters
            action_text = lastest_action.get('text', 'N/A')
            if len(action_text) > 80:
                print(f"Action: {action_text[:77]}...")
            else:
                print(f"Action: {action_text}")
            
            # Get the purpose of the amendment and truncate it if it exceeds 80 characters
            purpose_text = amendment.get('purpose', 'N/A')
            if len(purpose_text) > 80:
                print(f"Purpose: {purpose_text[:77]}...")
            else:
                print(f"Purpose: {purpose_text}")
            
            # Print the amendment number
            print(f"Number: {amendment['number']}")
            
            # Print the type of the amendment
            print(f"Type: {amendment['type']}")
            print()
except requests.exceptions.RequestException as e:
    print(f"Error fetching data: {e}")
Recent Amendments:
Action Date: 2023-09-28
Action: On agreeing to the Tenney amendment (A043) Agreed to by recorded vote: 360 - ...
Purpose: N/A
Number: 478
Type: HAMDT

Action Date: 2023-09-28
Action: On agreeing to the Spartz amendment (A032) Failed by recorded vote: 188 - 242...
Purpose: N/A
Number: 467
Type: HAMDT

Action Date: 2023-09-28
Action: On agreeing to the Boebert amendment (A026) Failed by recorded vote: 191 - 23...
Purpose: N/A
Number: 461
Type: HAMDT

Action Date: 2023-09-28
Action: On agreeing to the Steube amendment (A046) Failed by recorded vote: 198 - 232...
Purpose: N/A
Number: 481
Type: HAMDT

2. Retrieving Treaty Data#

Get Recent Treaties#

Get a list of recent treaties as well as their provided information.

We’ll use the “Number” to get more information on a specific treaty in the next cell.

endpoint = 'treaty'
params = {
    'api_key': API_KEY,
    'format': 'json',
    'limit': 2
}


treaty_number_pairs = []
print("Recent Treaties:")
try:
    response = requests.get(f"{BASE_URL}{endpoint}", params=params)
    response.raise_for_status()
    data = response.json()
    # Extract the list of treaties from the response data
    treaties = data.get('treaties', [])
    
    # Iterate through each treaty in the list
    for treaty in treaties:
        # Print the topic of the treaty
        print(f"Topic: {treaty['topic']}")
        
        # Print the date the treaty was transmitted
        print(f"Transmitted Date: {treaty['transmittedDate']}")
        
        # Print the date the treaty was last updated
        print(f"Update Date: {treaty['updateDate']}")
        
        # Print the congress number when the treaty was received
        print(f"Congress Received: {treaty['congressReceived']}")
        
        # Print the congress number when the treaty was considered (if available)
        print(f"Congress Considered: {treaty['congressConsidered']}")
        
        # Print the treaty number
        print(f"Number: {treaty['number']}")
        print()
        
        # Append the treaty number and congress number to the list for further use
        treaty_number_pairs.append({
            'treaty number': treaty['number'],
            'congress number': treaty['congressReceived']
        })
except requests.exceptions.RequestException as e:
    print(f"Error fetching data: {e}")
Recent Treaties:
Topic: Mutual Legal Assistance
Transmitted Date: 2025-01-14T00:00:00Z
Update Date: 2025-01-15T00:18:16Z
Congress Received: 119
Congress Considered: None
Number: 1

Topic: International Law and Organization
Transmitted Date: 2024-12-18T00:00:00Z
Update Date: 2024-12-19T00:18:14Z
Congress Received: 118
Congress Considered: None
Number: 2

Get Detailed Information on Treaties#

Get detailed information on a specific treaty by using the treaty “Number” from the previous cell and the “Congress Received” number.

Requires a specific treaty number and a specific congress number.

endpoint = f'treaty'
params = {
    'api_key': API_KEY,
    'format': 'json',
}

for pair in treaty_number_pairs:
    try:
        response = requests.get(
            f"{BASE_URL}{endpoint}/{pair['congress number']}/{pair['treaty number']}",
            params=params
        )
        response.raise_for_status()
        data = response.json()
        # Extract the treaty data from the response
        treaty = data.get('treaty', {})
        
        # Get the title of the treaty, or use 'N/A' if not available
        title_text = treaty.get('titles', [{}])[0].get('title', 'N/A')
        
        # Print the title, truncating it if it exceeds 80 characters
        if len(title_text) > 80:
            print(f"Title: {title_text[:77]}...'")
        else:
            print(f"Title: {title_text}")
        
        # Print the topic of the treaty
        print(f"Topic: {treaty.get('topic', 'N/A')}")
        
        # Print the congress number and treaty number
        print(f"Congress: {pair['congress number']}")
        print(f"Treaty Number: {pair['treaty number']}")
        
        # Extract and print the index terms associated with the treaty
        index_terms = treaty.get('indexTerms', [])
        index_terms = [term.get('name', 'N/A') for term in index_terms]
        print(f"Index Terms: {index_terms}")
        
        # Print the transmitted date and update date of the treaty
        print(f"Transmitted Date: {treaty.get('transmittedDate', 'N/A')}")
        print(f"Update Date: {treaty.get('updateDate', 'N/A')}")
        print()
    except requests.exceptions.RequestException as e:
        print(f"Error fetching treaty data: {e}")
Title: Treaty between the Government of the United States of America and the Governm...'
Topic: Mutual Legal Assistance
Congress: 119
Treaty Number: 1
Index Terms: ['119-1', 'Criminal', 'Mutual Legal Assistance', 'T. Doc. 119-1', 'United Arab Emirates']
Transmitted Date: 2025-01-14T00:00:00Z
Update Date: 2025-01-15T00:18:16Z

Title: Agreement Under the United Nations Convention on the Law of the Sea on the Co...'
Topic: International Law and Organization
Congress: 118
Treaty Number: 2
Index Terms: ['Conservation', 'Law of the Sea', 'TD 118-2', 'Treaty Doc. 118-2', 'United Nations Convention']
Transmitted Date: 2024-12-18T00:00:00Z
Update Date: 2024-12-19T00:18:14Z

3. Retrieving Data on Members of Congress#

Get Members of Congress#

Get a list of members of congress as well as their provided information.

endpoint = 'member'
params = {
    'api_key': API_KEY,
    'format': 'json',
    'limit': 2
}

print("Recent Members of Congress:")
try:
    response = requests.get(f"{BASE_URL}{endpoint}", params=params)
    response.raise_for_status()
    data = response.json()
    # Extract the list of members from the response data
    members = data.get('members', [])
    
    # Iterate through each member in the list
    for member in members:
        # Print the name of the member
        print(f"Name: {member['name']}")
        
        # Print the chamber of Congress the member belongs to
        print(f"Congress: {member['terms']['item'][0]['chamber']}")
        
        # Print the political party of the member
        print(f"Party: {member['partyName']}")
        
        # Print the state the member represents
        print(f"State: {member['state']}")
        
        # Print the unique Bioguide ID of the member
        print(f"Bioguide ID: {member['bioguideId']}")
        print()
except requests.exceptions.RequestException as e:
    print(f"Error fetching data: {e}")
Recent Members of Congress:
Name: Moody, Ashley
Congress: Senate
Party: Republican
State: Florida
Bioguide ID: M001244

Name: McMillan, J. Alex
Congress: House of Representatives
Party: Republican
State: North Carolina
Bioguide ID: M000566

Get Members of Congress by State#

Get a list of members of congress by state as well as their provided information.

Requires a specific state abbreviation and a “True” or “False” to determine whether to get current or all members of that state.

state_code = 'AL'

endpoint = 'member'
params = {
    'api_key': API_KEY,
    'format': 'json',
    'limit': 250,
    'currentMember': True, # Only current members
}

print(f"Members of Congress from {state_code}:")
try:
    response = requests.get(f"{BASE_URL}{endpoint}/{state_code}", params=params)
    response.raise_for_status()
    data = response.json()
    # Extract the list of members from the response data
    members = data.get('members', [])
    
    # Iterate through each member in the list
    for member in members:
        # Print the name of the member
        print(f"Name: {member['name']}")
        
        # Print the chamber of Congress the member belongs to
        print(f"Chamber: {member['terms']['item'][0]['chamber']}")
        
        # Print the political party of the member
        print(f"Party: {member['partyName']}")
        
        # Print the district the member represents
        print(f"District: {member.get('district', 'N/A')}")
        
        # Print the unique Bioguide ID of the member
        print(f"Bioguide ID: {member['bioguideId']}")
        print()
except requests.exceptions.RequestException as e:
    print(f"Error fetching data: {e}")
Members of Congress from AL:
Name: Strong, Dale W.
Chamber: House of Representatives
Party: Republican
District: 5
Bioguide ID: S001220

Name: Palmer, Gary J.
Chamber: House of Representatives
Party: Republican
District: 6
Bioguide ID: P000609

Name: Sewell, Terri A.
Chamber: House of Representatives
Party: Democratic
District: 7
Bioguide ID: S001185

Name: Aderholt, Robert B.
Chamber: House of Representatives
Party: Republican
District: 4
Bioguide ID: A000055

Name: Figures, Shomari
Chamber: House of Representatives
Party: Democratic
District: 2
Bioguide ID: F000481

Name: Moore, Barry
Chamber: House of Representatives
Party: Republican
District: 1
Bioguide ID: M001212

Name: Rogers, Mike D.
Chamber: House of Representatives
Party: Republican
District: 3
Bioguide ID: R000575

Name: Britt, Katie Boyd
Chamber: Senate
Party: Republican
District: N/A
Bioguide ID: B001319

Name: Tuberville, Tommy
Chamber: Senate
Party: Republican
District: N/A
Bioguide ID: T000278

Get Legislation Sponsored and Cosponsored by a Member of Congress#

Get a list of legislation sponsored and cosponsored by a member of congress as well as their provided information.

Requires a specific congress number, a state abbreviation, and a specific member’s bioguide ID.

congress_number = '118'
state_code = 'AL'
district_number = '4'

endpoint = 'member/congress'
params = {
    'api_key': API_KEY,
    'format': 'json',
    'limit': 2,
}


bioguide_id = None
print("Members by State and District:")
try:
    response = requests.get(
        f"{BASE_URL}{endpoint}/{congress_number}/{state_code}/{district_number}",
        params=params
    )
    response.raise_for_status()
    data = response.json()
    # Extract the list of members from the response data
    members = data.get('members', [])
    
    # Iterate through each member in the list
    for member in members:
        # Print the name of the member
        print(f"Name: {member['name']}")
        
        # Print the chamber of Congress the member belongs to
        print(f"Chamber: {member['terms']['item'][0]['chamber']}")
        
        # Print the political party of the member
        print(f"Party: {member['partyName']}")
        
        # Print the district the member represents
        print(f"District: {member.get('district', 'N/A')}")
        
        # Print the unique Bioguide ID of the member
        print(f"Bioguide ID: {member['bioguideId']}")
        print()
        
        # Store the Bioguide ID of the member for further use
        bioguide_id = member['bioguideId']
except requests.exceptions.RequestException as e:
    print(f"Error fetching data: {e}")
Members by State and District:
Name: Aderholt, Robert B.
Chamber: House of Representatives
Party: Republican
District: 4
Bioguide ID: A000055
endpoint = 'member'
params = {
    'api_key': API_KEY,
    'format': 'json',
    'limit': 2,
}

print(f"Legislation by Member ID: {bioguide_id}")
try:
    response = requests.get(
        f"{BASE_URL}{endpoint}/{bioguide_id}/sponsored-legislation",
        params=params
    )
    response.raise_for_status()
    data = response.json()
    # Extract the list of sponsored legislation from the response data
    bills = data.get('sponsoredLegislation', [])
    
    # Iterate through each bill in the list
    for bill in bills:
        # Print the title of the bill
        print(f"Title: {bill['title']}")
        
        # Print the bill number
        print(f"Bill Number: {bill['number']}")
        
        # Print the type of the bill
        print(f"Bill Type: {bill['type']}")
        
        # Print the date the bill was introduced
        print(f"Introduced Date: {bill['introducedDate']}")
        
        # Get the latest action text for the bill, or use 'N/A' if not available
        latest_action_text = bill.get('latestAction', {}).get('text', 'N/A')
        
        # Print the latest action text, truncating it if it exceeds 80 characters
        if len(latest_action_text) > 80:
            print(f"Latest Action: {latest_action_text[:77]}...")
        else:
            print(f"Latest Action: {latest_action_text}")
        print()
except requests.exceptions.RequestException as e:
    print(f"Error fetching data: {e}")
Legislation by Member ID: A000055
Title: Deliver for Democracy Act
Bill Number: 2098
Bill Type: HR
Introduced Date: 2025-03-14
Latest Action: Referred to the House Committee on Oversight and Government Reform.

Title: Designation of English as the Official Language of the United States Act of 2025
Bill Number: 1772
Bill Type: HR
Introduced Date: 2025-03-03
Latest Action: Referred to the Committee on Education and Workforce, and in addition to the ...
endpoint = 'member'
params = {
    'api_key': API_KEY,
    'format': 'json',
    'limit': 2,
}

print(f"Cosponsored Legislation by Member ID: {bioguide_id}")
try:
    response = requests.get(
        f"{BASE_URL}{endpoint}/{bioguide_id}/cosponsored-legislation",
        params=params
    )
    response.raise_for_status()
    data = response.json()
    # Extract the list of cosponsored legislation from the response data
    bills = data.get('cosponsoredLegislation', [])
    
    # Iterate through each bill in the list
    for bill in bills:
        # Get the title of the bill, or use a default message if not available
        title_text = bill.get('title', 'No title available')
        
        # Print the title, truncating it if it exceeds 80 characters
        if len(title_text) > 80:
            print(f"Title: {title_text[:77]}...")
        else:
            print(f"Title: {title_text}")
        
        # Print the action date of the bill
        print(f"Action Date: {bill['latestAction']['actionDate']}")
        
        # Print the latest action text of the bill
        print(f"Latest Action: {bill['latestAction']['text']}")
        
        # Print the bill number
        print(f"Bill Number: {bill['number']}")
        print()
except requests.exceptions.RequestException as e:
    print(f"Error fetching data: {e}")
Cosponsored Legislation by Member ID: A000055
Title: Expressing support for the designation of May as "National Bladder Cancer Awa...
Action Date: 2025-05-06
Latest Action: Referred to the House Committee on Energy and Commerce.
Bill Number: 392

Title: To direct the Secretary of Defense to carry out a pilot program to assist cer...
Action Date: 2025-05-01
Latest Action: Referred to the House Committee on Armed Services.
Bill Number: 3148