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:
Documentation
Terms
Data Reuse
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