Ballotpedia APIballotpedia.org ↗
Access US state court structures and judicial data via the Ballotpedia Courts and Judges API. List states, courts, and current justices with party and appointment details.
What is the Ballotpedia API?
The Ballotpedia Courts and Judges API covers all 50 US states across 3 endpoints, returning court listings and individual justice records including party affiliation, date assumed office, and appointing authority. The list_justices endpoint returns structured objects for current judges on a named court, while list_courts maps the full court hierarchy for any given state.
No input parameters required.
curl -X GET 'https://api.parse.bot/scraper/1345c3bd-ecb3-416f-9f80-50c8bbb64646/list_states' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace ballotpedia-org-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
Ballotpedia Courts and Judges API Client
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Optional, Dict, List, Any
class ParseClient:
"""Client for the Ballotpedia Courts and Judges API."""
def __init__(self, api_key: Optional[str] = None):
"""
Initialize the Parse API client.
Args:
api_key: API key for authentication. If not provided, reads from PARSE_API_KEY env var.
"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "1345c3bd-ecb3-416f-9f80-50c8bbb64646"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError(
"API key not provided. Pass it as an argument or set PARSE_API_KEY environment variable."
)
def _call(self, endpoint: str, method: str = "POST", **params) -> Dict[str, Any]:
"""
Make a request to the Parse API.
Args:
endpoint: The API endpoint name
method: HTTP method (GET or POST)
**params: Query/body parameters
Returns:
Response JSON as a dictionary
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
if method == "GET":
response = requests.get(url, headers=headers, params=params)
elif method == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
def list_states(self) -> Dict[str, Any]:
"""
Get a list of all US states with court information available.
Returns:
Dictionary with 'states' (list of state names) and 'total' (count)
"""
return self._call("list_states", method="GET")
def list_courts(self, state: str) -> Dict[str, Any]:
"""
Get a list of court types for a given state.
Args:
state: US state name (e.g., 'Alabama', 'California', 'New York')
Returns:
Dictionary with 'state', 'courts' (list of court names), and 'total'
"""
return self._call("list_courts", method="GET", state=state)
def list_justices(self, state: str, court_name: str) -> Dict[str, Any]:
"""
Get a list of current justices/judges for a given court.
Args:
state: US state name
court_name: Full court name as returned by list_courts
Returns:
Dictionary with 'state', 'court_name', 'justices' (list of justice objects), and 'total'
"""
return self._call("list_justices", method="GET", state=state, court_name=court_name)
def main():
"""
Practical usage example: Research supreme court justices across multiple states.
"""
client = ParseClient()
print("=" * 70)
print("BALLOTPEDIA COURTS AND JUDGES API - RESEARCH WORKFLOW")
print("=" * 70)
# Step 1: Get all available states
print("\n[1/4] Fetching available states...")
states_response = client.list_states()
available_states = states_response["states"]
print(f"✓ Found {states_response['total']} states with court data")
# Step 2: Select a few states to research (California, Texas, New York)
states_to_research = ["California", "Texas", "New York"]
states_to_research = [s for s in states_to_research if s in available_states]
print(f"✓ Researching {len(states_to_research)} states: {', '.join(states_to_research)}")
# Step 3: For each state, get courts and then get justices for supreme courts
print("\n[2/4] Fetching courts for each state...")
supreme_court_data = []
for state in states_to_research:
courts_response = client.list_courts(state)
courts = courts_response["courts"]
print(f"\n {state}: {len(courts)} court types found")
# Find the supreme court
supreme_court = next((c for c in courts if "Supreme Court" in c), None)
if supreme_court:
print(f" └─ Located: {supreme_court}")
supreme_court_data.append((state, supreme_court))
# Step 4: Fetch justices for each supreme court and analyze
print("\n[3/4] Fetching justices for supreme courts...")
all_justices = []
for state, court_name in supreme_court_data:
justices_response = client.list_justices(state, court_name)
justices = justices_response["justices"]
print(f"\n {state} - {court_name}:")
print(f" Total justices: {len(justices)}")
if justices:
# Group by party
party_counts = {}
for justice in justices:
party = justice.get("party", "Unknown")
party_counts[party] = party_counts.get(party, 0) + 1
all_justices.append(
{
"state": state,
"court": court_name,
"name": justice.get("name"),
"party": party,
"assumed_office": justice.get("date_assumed_office"),
}
)
# Display party breakdown
for party, count in sorted(party_counts.items()):
print(f" • {party}: {count} justice(s)")
# Show a sample of justices
print(" Recent appointments:")
recent = [j for j in justices if j.get("date_assumed_office")][:2]
for justice in recent:
print(
f" - {justice.get('name')} ({justice.get('party')}) - {justice.get('date_assumed_office')}"
)
else:
print(" ⚠ No individual justice data available for this court")
# Step 5: Summary analysis
print("\n[4/4] Summary Analysis")
print("=" * 70)
if all_justices:
print(f"Total justices tracked: {len(all_justices)}")
party_totals = {}
for justice in all_justices:
party = justice["party"]
party_totals[party] = party_totals.get(party, 0) + 1
print("\nParty Breakdown (All States):")
for party, count in sorted(party_totals.items(), key=lambda x: x[1], reverse=True):
percentage = (count / len(all_justices)) * 100
print(f" • {party}: {count} ({percentage:.1f}%)")
# Show diversity across states
print("\nJustices by State:")
for state in states_to_research:
state_justices = [j for j in all_justices if j["state"] == state]
if state_justices:
print(f" • {state}: {len(state_justices)} justices")
print("\n" + "=" * 70)
print("✓ Research workflow completed successfully!")
if __name__ == "__main__":
main()Returns a list of all 50 US states that have court information available on Ballotpedia.
No input parameters required.
{
"type": "object",
"fields": {
"total": "integer",
"states": "array of state name strings"
},
"sample": {
"total": 50,
"states": [
"Alabama",
"Alaska",
"Arizona",
"Arkansas",
"California"
]
}
}About the Ballotpedia API
What the API covers
This API exposes structured judicial data sourced from Ballotpedia's Courts and Judges by State pages. It covers all 50 US states and returns court names and current justice records organized by state. The three endpoints form a lookup chain: start with list_states to get valid state names, pass one to list_courts to retrieve that state's court names, then pass both a state and court name to list_justices to get individual judge records.
Endpoints and response fields
list_courts takes a single required state parameter (e.g. 'Texas', 'New York') and returns a courts array of full court name strings alongside a total count. These court name strings are the exact values expected by list_justices as the court_name parameter — the inputs must match precisely.
list_justices returns a justices array where each object contains four fields: name (the judge's full name), party (political party affiliation), date_assumed_office (when the justice joined the court), and appointed_by (the appointing official or election reference). The total field gives the count of justices returned. Note that lower courts — such as circuit, district, and municipal courts — may return an empty justices array; detailed individual listings are most consistently available for state supreme courts and courts of appeal.
Coverage notes
All state names returned by list_states are valid inputs for list_courts. State names must be passed as full names (e.g. 'California', not 'CA'). Ballotpedia's coverage of individual justices varies by court tier, so applications should handle cases where total is 0 and justices is an empty array.
The Ballotpedia API is a managed, monitored endpoint for ballotpedia.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when ballotpedia.org changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official ballotpedia.org API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a judicial appointment tracker that maps
appointed_byvalues across all 50 states - Analyze party affiliation distribution across state supreme courts using the
partyfield - Generate a directory of current judges indexed by state and court type
- Research when sitting justices assumed office using
date_assumed_officeto identify upcoming vacancies - Compare court structure complexity across states by counting results from
list_courts - Power a civics education tool that presents each state's court hierarchy with sitting judges
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Ballotpedia have an official developer API?+
What does list_justices return for lower courts like district or municipal courts?+
justices array may be empty and total may be 0. Ballotpedia's individual justice listings are most complete for state supreme courts and intermediate appellate courts. Applications should check total before iterating the justices array.Does the API include federal judges or US Supreme Court justices?+
Can I filter justices by party affiliation or appointment year?+
list_justices endpoint returns all current justices for a given court without server-side filtering. The party and date_assumed_office fields are included in each justice object, so filtering can be applied client-side. You can fork this API on Parse and revise it to add filtered query parameters.