API docs
Send your key in the Authorization header. It never goes in the URL. In every example RALLYBASE_KEY stands for your key.
Quickstart
Look up a county's officials by FIPS code
A county is a five-digit FIPS code, and it answers the county officials only: a county has no single point, so for federal, state and city officials send an address or coordinates. Set RALLYBASE_KEY in your environment; run this on a server, because a key does not belong in a browser.
# -i prints the status and headers: on a 429, Retry-After says how long to wait. Do not loop or retry blindly. curl --fail-with-body -sS -i "https://rallybase.org/api/v2/lookup?county=48453" \ -H "Authorization: Bearer $RALLYBASE_KEY"
Look up who represents a street address
Every level for one address: federal, state, county, city and school. The address is URL-encoded and sent in the x-geocode-address header, never in the URL: a URL is cached and logged. We resolve it to a point and do not store it. Coordinates work the same way in the x-rb-lat and x-rb-lng headers. The address below is a placeholder.
# -i prints the status and headers: on a 429, Retry-After says how long to wait. Do not loop or retry blindly. curl --fail-with-body -sS -i "https://rallybase.org/api/v2/lookup" \ -H "Authorization: Bearer $RALLYBASE_KEY" \ -H "x-geocode-address: 1600%20Example%20St%2C%20Austin%2C%20TX"
Contact your representatives: find who, then how their office publishes ways to reach them
Step one is the address lookup. Step two prints each official with the office phone, email and website their office publishes, for federal and state officials, and on each row the page it was read from and the day it was read. County, city and school rows carry no contact in this API: their contact details are on the source page. The recipe does not send anything on anyone's behalf.
# Step 1: who holds office at this address, at each level. Federal and state rows carry phone, email and website; on each row, # source_url is the page the row was read from. # -i prints the status and headers: on a 429, Retry-After says how long to wait. Do not loop or retry blindly. curl --fail-with-body -sS -i "https://rallybase.org/api/v2/lookup" \ -H "Authorization: Bearer $RALLYBASE_KEY" \ -H "x-geocode-address: 1600%20Example%20St%2C%20Austin%2C%20TX"
The lookup
GET /api/v2/lookup takes a street address, URL-encoded, in the x-geocode-address header, or coordinates in the x-rb-lat and x-rb-lng headers, and answers every level for that point. A five-digit FIPS code in county answers the county officials only. The names, ids and pages in this answer are placeholders.
curl "https://rallybase.org/api/v2/lookup" \
-H "Authorization: Bearer $RALLYBASE_KEY" \
-H "x-geocode-address: 1600%20Example%20St%2C%20Austin%2C%20TX"
{
"license": "Data licensed under the Rallybase API Terms: use, display and analysis in your own product or research; no resale or redistribution as a dataset or competing service; attribution with source links when shown publicly.",
"snapshot": {
"id": "snap-example",
"built_at": "2026-10-28T06:00:00.000Z"
},
"freshness": "weekly snapshot",
"county": {
"fips": "48453",
"name": "Travis",
"state": "TX"
},
"officials": [
{
"id": "federal-rep-X000001",
"level": "federal",
"office": null,
"office_label": "U.S. Representative, TX-37",
"name": "Alex Example",
"jurisdiction": "U.S. House of Representatives",
"ocd_id": "ocd-division/country:us/state:tx/cd:37",
"district_key": null,
"party": "Example Party",
"phone": "202-555-0100",
"email": null,
"website": "https://example.house.gov",
"source_url": "https://www.example.gov/members",
"read_at": null,
"read_basis": "not held — officials.last_synced is a sync or load time, not a read date (see recorded)",
"recorded_on": "2026-10-27",
"attribution": null
},
{
"id": "state-ocd-person/00000000-0000-0000-0000-000000000000",
"level": "state",
"office": null,
"office_label": "State Senator, District 14",
"name": "Sam Example",
"jurisdiction": "TX Senate",
"ocd_id": "ocd-division/country:us/state:tx/sldu:14",
"district_key": null,
"party": "Example Party",
"phone": "512-555-0100",
"email": "sam.example@example.gov",
"website": "https://www.example.gov/senate/14",
"source_url": "https://www.example.gov/senate",
"read_at": null,
"read_basis": "not held — officials.last_synced is a sync or load time, not a read date (see recorded)",
"recorded_on": "2026-10-27",
"attribution": null
},
{
"id": "county-official-48453-county_judge",
"level": "county",
"office": "county_judge",
"office_label": "County Judge",
"name": "Jane Example",
"jurisdiction": "Travis County, TX",
"ocd_id": "ocd-division/country:us/state:tx/county:travis",
"district_key": null,
"party": null,
"phone": null,
"email": null,
"website": null,
"source_url": "https://www.example.gov/county-judge",
"read_at": "2026-10-20",
"read_basis": "rb.county_official.fetched_at",
"recorded_on": null,
"attribution": null
},
{
"id": "place-official-4805000-mayor-citywide-pat-example",
"level": "place",
"office": null,
"office_label": "Mayor",
"name": "Pat Example",
"jurisdiction": "Austin City Council",
"ocd_id": null,
"district_key": "place_geoid:4805000",
"party": null,
"phone": null,
"email": null,
"website": null,
"source_url": "https://www.example.gov/council",
"read_at": "2026-10-21",
"read_basis": "last_verified_on: a person re-read the city page",
"recorded_on": null,
"attribution": null
}
],
"point": {
"read_at": "2026-10-28T14:03:11.000Z",
"districts": [
{
"name": "Congressional District 37",
"level": "federal",
"state": "TX",
"census_geoid": "4837"
},
{
"name": "State Senate District 14",
"level": "state",
"state": "TX",
"census_geoid": "48014"
}
],
"bodies": [
{
"body_name": "Commissioners Court",
"body_kind": "county_commission",
"seats": 5,
"composition": "A county judge elected countywide and four commissioners elected by precinct.",
"election_method": "mixed",
"citation": "Tex. Const. art. V, § 18",
"source_url": "https://www.example.gov/constitution",
"verified_on": "2026-09-01",
"applies_as": "state_default"
}
],
"place_rosters": [
{
"place_geoid": "4805000",
"place_name": "Austin",
"state": "TX",
"status": "rostered",
"count": 11,
"reason": null,
"checked_at": "2026-09-17"
}
]
},
"coverage": {
"county": "held",
"levels": {
"federal": "served",
"state": "served",
"place": "served",
"school": "none held",
"local": "none held"
},
"held_not_redistributed": 0,
"note": "No row held for this lookup was withheld by the licence filter or the row text rules."
}
}Each official carries a stable id, source_url, the public page the row was read from, and read_at, the day it was read, or null with read_basis saying why. Federal and state rows carry the office’s published phone, email and website; county, city and school rows carry none in this API. A level with no rows is explained in coverage.levels: “none held”, “could not check” and “held, not redistributed” are different findings, and none says a government has no officials.
How accurate the rows were on re-check
360 of 363 rows matched their source on re-check (99.2%; 95% interval 97.6–99.7%), November 2026.
Method: a random sample of 395 served county and city officer rows, stratified by how the source page is shared and leaving out board seats, each re-read from its own source page; a row matched when that page printed the stored name (beside the office title in 334 of the 360). The 32 rows whose page could not be read are not in the rate. It measures what we stored against what the page printed that day, not whether the page itself was current. Re-measured quarterly. Where our data comes from has the sources.
Errors
Every answer that is not a 200 is JSON with an error code and a message in plain words. Check the status first, then the code.
| Status | error | When | What to do |
|---|---|---|---|
| 400 | key_in_query | A key is in the URL. | Send it in the Authorization header. A URL is written to access logs. |
| 400 | address_in_query | An address query parameter was sent. | Send the address, URL-encoded, in the x-geocode-address header. |
| 400 | coordinates_in_query | A lat or lng query parameter was sent. | Send coordinates in the x-rb-lat and x-rb-lng headers. |
| 400 | bad_county | county is not exactly five digits. | Send a five-digit FIPS code, for example 48453. |
| 400 | bad_coordinates | One coordinate header is missing, blank, not a number or out of range. | Send both headers with valid coordinates. |
| 400 | bad_address | The address header cannot be decoded, or is not 4 to 200 characters. | URL-encode the address and keep it within that length. |
| 400 | missing_query | No county, address or coordinates were sent. | Send one of the three. |
| 401 | invalid_key | The key is missing, malformed, unknown or revoked. | Check the Authorization header. A revoked key is replaced in the console. |
| 404 | address_not_found | The address could not be matched. Not counted toward the monthly allowance. | Check the address. Coordinates skip the matching step. |
| 404 | point_not_found | The coordinates are not inside a US county we hold. Not counted toward the monthly allowance. | Check the coordinates and their order: latitude, then longitude. |
| 404 | not_found | The route under /api/v2 does not exist, or the API is switched off. | Check the path. The lookup is GET /api/v2/lookup. |
| 405 | method_not_allowed | The request was not a GET. | Use GET. |
| 429 | rate_limited | A limit was reached. The limit field of the body names which. | Wait the number of seconds in Retry-After before calling again. |
| 502 | geocoder_unavailable | The address could not be resolved just now. Not counted toward the monthly allowance. | Try again shortly, or send coordinates. |
| 503 | unavailable | The API failed internally. Nothing was counted past the failing step. | Wait the number of seconds in Retry-After, then try again. |
| 503 | snapshot_unavailable | No snapshot has been built yet. Not counted toward the monthly allowance. | Wait the number of seconds in Retry-After, then try again. |
An answer that is not counted toward the monthly allowance still counts toward the per-minute and per-day limits.
The limit field of a 429
per_minutethe key’s lookups in the clock minuteper_daythe key’s lookups in the UTC daystacked_dailythe lower daily limit for free keys that share a network with several othersfree_ip_dailyfree lookups from one network address in a dayfree_asn_dailyfree lookups from one network provider in a dayfree_budgetthe day’s total of free lookups across every free keygeocoder_budgetaddress matching across every key in the minutemonthlythe key’s monthly allowance
The free lookup the site uses
The site’s own pages call GET /api/v1/officials/at-point, which takes no key. It stays open for the site. A program calling it, rather than a browser, is held to 10 requests a minute per network, and every answer carries an X-Rallybase-API header pointing here. For programs, use the keyed lookup above: it returns the same officials with snapshot ids, a licence and a monthly allowance.
Limits
These are the Open key’s limits.
- An Open key can make 10 lookups in a clock minute (the minute on the clock, not the 60 seconds after your last call) and 300 in a UTC day.
- A lookup by address counts as 3 of the minute, so 3 address lookups fit in a minute and the next is refused. A lookup by county counts as 1.
- Because the minute is a clock minute, a burst that straddles the turn of a minute can pass up to twice the limit: 10 at the end of one minute and 10 at the start of the next.
- The monthly allowance is 500 lookups per calendar month (UTC).
- Only a request that returns 200 with at least one official counts toward the monthly allowance.
- Past a limit the API answers 429 with a Retry-After header, in seconds, and a body whose limit field names which limit was reached (for example per_minute, per_day or monthly).
By plan
| Plan | In a clock minute | In a UTC day | In a calendar month |
|---|---|---|---|
| Open | 10 | 300 | 500 |
| Builder | 60 | No daily limit | 50,000 |
| Pro | 300 | No daily limit | 1,000,000 |
The API page says which plans can be bought today.
Connect Claude
Rallybase is also a connector for Claude. It reads federal, state, county and city officials, saved bills and the elections held for a state. It takes no address: the address lookup is the keyed API above.
Rallybase is in Claude’s connector directory. Add Rallybase to Claude.
- In Claude, open Settings, then Connectors, and choose Add custom connector.
- Paste https://rallybase.org/mcp as the address.
- Claude sends you to the Rallybase Connect page. Log in and choose Allow.
https://rallybase.org/mcp
- It can read
- County officers; a state’s federal and state officials, with their offices’ published phone, email and website; a city’s officials; saved bills; and the elections held for a state.
- It cannot
- It can only read. It cannot change anything on your account or on Rallybase.
- What you need
- A connection needs a Rallybase account with a key. The free key is enough.
- Your allowance
- Its lookups count toward your account's monthly allowance. In one day a connection can use up to a tenth of it.
- To end it
- You can end this link at any time by signing out of all devices, changing your password or revoking your API key.
What Claude can call
lookup_officialsLook up county officersget_officialGet one county officeget_countyGet one county by FIPS codeget_coverageSee what is heldsearch_billsSearch saved billsget_ballotGet upcoming elections for a stateget_state_officialsGet a state's federal and state officialslookup_cityLook up a city's officials
Moving from the Google Civic Information API
Google retired its two Representatives methods, representativeInfoByAddress and representativeInfoByDivision, on 2025-04-30. Source: developers.google.com/civic-information/docs/v2, read 2026-11-08: the page footer reads "Last updated 2025-04-30 UTC", and the Representatives method pages (representatives/representativeInfoByAddress and representatives/representativeInfoByDivision) answer HTTP 404. We could not retrieve the text of Google’s own notice on that day, so the shutdown date is the page’s last-updated date and the date we recorded earlier, not a quotation.
Read this first: the replacement covers federal, state, county, city and school officials for an address, but it is not a drop-in for the Google responses. Office contact is served for federal and state officials only, and the last list below says what else it leaves out.
| Rallybase | Note | |
|---|---|---|
representativeInfoByAddress (address in the query string, key in the query string) | GET /api/v2/lookup with the address in the x-geocode-address header and the key in Authorization: Bearer | Federal, state, county, city and school officials for the address. A key or an address in the URL is refused with 400. |
representativeInfoByDivision (an OCD division id in the path) | GET /api/v2/lookup?county=<5-digit FIPS>, or coordinates in the x-rb-lat and x-rb-lng headers | We take a county FIPS code or a point, not an OCD id: we do not look up by OCD id. Each row carries its ocd_id where the published list has one. A county code answers the county level only. |
| Google field | Rallybase field | Note |
|---|---|---|
officials[].name | officials[].name | The holder's name as served. |
offices[].name | officials[].office_label (and officials[].office, a stable key) | The office as the county page prints it, with the holder's name taken out. |
offices[].divisionId | officials[].ocd_id (and officials[].district_key, officials[].jurisdiction) | The Open Civic Data id where the published list carries the division, else null; district_key names a city or school district OCD does not type. |
offices[].levels, offices[].roles | officials[].level | One of federal, state, county, place (a city or town), school or local (any other local government). |
officials[].phones, officials[].emails | officials[].phone, officials[].email | The office's published phone and email, for federal and state officials only; null on county, city and school rows. |
officials[].urls | officials[].website and officials[].source_url | website is the office's own site (federal and state). source_url is a different thing: the public page our row was read from, on each row. |
officials[].party | officials[].party | As the source gives it, or null. County rosters publish none. |
officials[].id (none in Google) | officials[].id | A stable id that stays the same across lookups, and is the one the site uses. |
normalizedInput | none | We do not echo or store the address. |
What we hold that Google never did
- A source page on each row (source_url) and the day it was read (read_at). Google's responses carried neither.
- A finding for every level (coverage.levels): "none held", "could not check" and "held, not redistributed" are different findings, and none says a government has no officials.
- The districts that contain the point and the governing bodies with their seat counts, read from charter or statute (point.districts, point.bodies).
- The snapshot the answer came from (snapshot.id, snapshot.built_at) and the licence that applies to the data (license).
- A credit the source requires you to show, when one is owed (attribution).
What we do not hold
- Phone numbers, email addresses and websites for county, city and school officials. Federal and state offices' published contact is served; for the rest, the contact details are on the source page.
- Mailing addresses, photographs and social media channels, for any official. The fields Google returned for these (address, photoUrl, channels) have no equivalent here.
- Lookup by OCD division id. Rows carry the id; the lookup takes an address, a point or a county FIPS code.
- Complete local coverage. A county we have not read is reported as "not yet read", and a city whose roster we do not hold is listed in point.place_rosters as not_yet.
The OpenAPI description of the lookup is a JSON file you can load into a client generator.