Changelog

What changed in the API, newest first. New fields and parameters are added without notice, so ignore fields you don’t know. Anything that could break a client is marked Changed or Removed.

November 13, 2026

  • Election results: every contest has a result once a source publishes one (status, total votes, precincts, the source and its URL, ranked-choice rounds, write-ins), and every choice has result with its votes, vote_pct and winner. In GET /v1/contests, GET /v1/contests/{id}, the election export (JSON, and new result columns at the end of the CSV), GET /v1/candidates and GET /v1/candidates/{id}. See Election results.
  • has_result and result_statuses on GET /v1/contests, and result_count on GET /v1/elections.
  • Past elections, starting with the November 5, 2024 general election, with their results: details.historical marks them.
  • Contests: office (the office, normalized across states, with its level and branch of government), race_type (regular, special, recall or retention), partisan, and topics on measures. New offices and topics filters on GET /v1/contests, and GET /v1/measure-topics lists the topics.
  • Candidates: name in parts (given, middle, family, suffix, nickname), ids (FEC and Congress bioguide ids for federal candidates), contact (website and social accounts from Wikidata, the campaign committee’s FEC mailing address, and what the campaign publishes on its own site, each with its source), and finance (FEC totals) on GET /v1/candidates/{id}.
  • Choices: endorsement_count, how many endorsers back each candidate or each Yes and No answer.
  • Endorsements: stage (general, primary or runoff).

November 12, 2026

  • Candidate issue positions: where candidates stand on common issues (abortion, guns, immigration, schools, the safety net, taxes, tariffs and more), each with a neutral summary, their own words where we have them, and the links it came from. GET /v1/issues lists the issues, GET /v1/issue-positions lists positions by issue, stance, candidate, contest, election or state, and GET /v1/candidates/{id} has a new issue_positions field.
  • Changed: request rate limits are back. Each account has a per-minute limit and a daily cap (UTC) shared by its keys, and a number of open streams, set by its plan: 600 a minute and 200,000 a day for every purchase. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (and X-Daily-Limit / X-Daily-Remaining); over a limit is a 429 with Retry-After. The client libraries wait and retry for you. See keys, limits and errors.

November 11, 2026

  • Measures: ballot_text (the wording as printed on the ballot), full_text_url, and vote_meaning on each Yes and No choice.
  • Candidates: incumbent on each choice (true, false, or null where we don’t know yet), in the API and in Endorsement Stream events.
  • Contests: unopposed, and party_lines_unverified and question_wording in details.
  • GET /v1/endorsements/{id}/history: every change to an endorsement, with the values before and after, including its deletion.
  • changed_since on GET /v1/endorsements, to sync only what’s new.
  • GET /v1/changes: every endorsement added, changed or deleted since a time, with the values before and after.
  • GET /v1/candidates and GET /v1/candidates/{id}: search candidates, and every endorsement each one received.
  • GET /v1/elections/{slug}/export: a whole election in one download, as JSON or CSV.
  • added_by on every endorsement (automatic, staff or data_load), and endorsement_id on each pick in GET /v1/contests/{id}.
  • Endorsement Stream: endorsement.updated events carry changed and previous (the values before the change), and every event carries endorsement.added_by.
  • min_endorsements on GET /v1/endorsers, and endorsement_count on GET /v1/endorsers/{slug}.
  • Changed: an endorser’s endorsement_count now counts contests, so a ranked-choice order or a vote-for-N slate counts once, as on endorsedby.org. It used to count each pick.

October 28, 2026

  • Every parameter is described with an example, and each reference entry has a sample using every parameter.

October 26, 2026

October 24, 2026

  • Changed: GET /v1/endorsements lists the basics of each endorsement; GET /v1/endorsements/{id} has the full record.
  • No request rate limits.

October 22, 2026

  • Removed: the combined per-contest view. GET /v1/contests/{id} has every endorser’s position in a contest.
  • Keys and the stream read only what the account bought; asking for a state outside it is a 403 outside_purchase.
  • Every error carries a request_id, also sent as the X-Request-Id header.

October 20, 2026

  • The API moved to api.ballotdata.ai.

October 16, 2026

  • Removed: address, ZIP, district and representative lookups. Choose contests by state, election or id.

October 15, 2026

  • First release: elections, contests, endorsers, endorsements, officeholders, coverage, Spanish ballot text and the Endorsement Stream.
Changelog · BallotData API