API reference

U.S. ballots, endorsers and endorsements, and a live stream of endorsement changes.

Base URL
https://api.ballotdata.net
Authentication
Authorization: Bearer ebk_… on every request (or X-API-Key: ebk_…). Keys come from the console; keep them on your servers.
Format
JSON over HTTPS. Dates are YYYY-MM-DD; times are ISO 8601 in UTC.
OpenAPI
openapi.json (OpenAPI 3.1.0, version 1.1.0): import it into Postman, Insomnia or a client generator.

Paging

Lists return { "data": [...], "next_cursor": "…" }. Pass cursor=<next_cursor> for the next page; null means you have them all. limit sets the page size.

Filters

List parameters take comma-separated values, and any of them matches: states=CA,NV. Different parameters combine with AND.

Errors and limits

Errors carry a code you can branch on, a message, and a request_id to quote when you write to us. Every response says where you stand on your plan’s limits in RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (and X-Daily-Limit / X-Daily-Remaining). Over a limit you get 429 with Retry-After. See keys, limits and errors.

Example responses are illustrative: the shapes are exact, the people and picks are made up.

Authenticate
curl "https://api.ballotdata.net/v1/endorsements?states=CA&categories=labor" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Page through results
curl "https://api.ballotdata.net/v1/endorsements?elections=ca-2026-11-03-general&cursor=aTo5MDIxMQ" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Error429
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Your plan allows 60 requests a minute.",
    "request_id": "8c1f2a4e-6b7d-4c3e-9f10-2a3b4c5d6e7f"
  }
}

Elections

States, elections and coverage: what there is to ask about.

List states

GET /v1/states

Every state, D.C. and territory, with its USPS and FIPS codes. Use the codes in states= filters.

Returns

200 Every state.

  • dataarray of State

    Every item.

    3 fields
    • codestring

      USPS state code.

    • fipsstring

      Two-digit FIPS code.

    • namestring

      Full name.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/states
curl "https://api.ballotdata.net/v1/states" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "code": "AK",
      "fips": "02",
      "name": "Alaska"
    },
    {
      "code": "AL",
      "fips": "01",
      "name": "Alabama"
    },
    {
      "code": "AR",
      "fips": "05",
      "name": "Arkansas"
    }
  ]
}

List elections

GET /v1/elections

Elections, with their voting rules in details (all-mail, ranked choice, fusion, runoff dates) and how many contests and endorsements each has. Use an election’s slug to ask for its contests or endorsements.

Query parameters

  • statescomma-separated strings

    USPS codes.

    Example CA
  • typescomma-separated strings

    Kinds of election.

    One of general, primary, special, special_primary, runoff, consolidated.Example general
  • upcomingboolean

    Only elections from yesterday on.

    Default false.
  • fromstring (date)

    Elections on or after this date.

    Example 2026-11-01
  • tostring (date)

    Elections on or before this date.

    Example 2026-12-31
  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.
  • limitinteger

    Results per page, 1–500.

    Default 100.1 to 500.
  • cursorstring

    The next_cursor from the previous page.

Returns

200 A page of elections, by id.

  • dataarray of ElectionSummary

    This page.

    12 fields
    • idinteger

      Election id.

    • slugstring

      Election slug, used in elections= filters: <state>-<date>-<type>.

    • namestring

      Election name.

    • short_namestring or null

      Shorter name.

    • datestring (date)

      Election day.

    • statestring or null

      State; null for a multi-state election.

    • typestring

      Kind of election.

      One of general, primary, special, special_primary, runoff, consolidated.
    • primary_systemstring or null

      How the state runs primaries.

      One of none, closed, semi_closed, open, top_two, nonpartisan.
    • info_urlstring (uri) or null

      Official election page.

    • detailsobject

      Voting rules for the election. Only keys that apply are present.

      11 fields
      • all_mailboolean

        Every voter is mailed a ballot.

      • ranked_choiceboolean

        Some contests in this election use ranked choice voting.

      • fusion_votingboolean

        Candidates can appear on more than one party’s line (New York, Connecticut).

      • partisan_primaryboolean

        A party primary.

      • primarystring

        Which primary, where a state holds several.

      • consolidated_withstring

        Elections held on the same ballot.

      • runoff_datestring (date)

        Date of a runoff, if one is needed.

      • runoff_election_datestring (date)

        Date of the runoff election.

      • top_two_primary_datestring (date)

        Date of the top-two primary that chose these candidates.

      • louisiana_open_primaryboolean

        Louisiana’s open (jungle) primary.

      • notestring

        Anything else voters should know.

    • contest_countinteger

      Contests on the ballot.

    • endorsement_countinteger

      Endorsements in those contests.

  • next_cursorstring or null

    Pass as cursor= for the next page; null on the last page.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/elections
curl "https://api.ballotdata.net/v1/elections?states=CA&upcoming=true" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "id": 3,
      "slug": "ca-2026-11-03-general",
      "name": "California General Election",
      "short_name": "General Election",
      "date": "2026-11-03",
      "state": "CA",
      "type": "general",
      "primary_system": "top_two",
      "info_url": "https://www.sos.ca.gov/elections/upcoming-elections",
      "details": {
        "all_mail": true
      },
      "contest_count": 1184,
      "endorsement_count": 9632
    }
  ],
  "next_cursor": "aToz"
}

Coverage by state

GET /v1/coverage

What the API has for each state: elections, contests, measures, endorsers and endorsements, and when they last changed. Handy for deciding what to sync.

Query parameters

  • upcomingboolean

    Count only upcoming elections.

    Default true.

Returns

200 One row per state.

  • dataarray of Coverage

    Every item.

    11 fields
    • statestring

      USPS state code.

    • namestring

      State name.

    • election_countinteger

      Elections.

    • contest_countinteger

      Contests.

    • measure_countinteger

      Of those, ballot measures.

    • endorser_countinteger

      Endorsers with endorsements here.

    • endorsement_countinteger

      Endorsements.

    • endorsed_contest_countinteger

      Contests with at least one endorsement.

    • first_electionstring (date) or null

      Earliest election.

    • last_electionstring (date) or null

      Latest election.

    • updated_atstring (date-time) or null

      When a contest or endorsement last changed.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/coverage
curl "https://api.ballotdata.net/v1/coverage" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "state": "CA",
      "name": "California",
      "election_count": 1,
      "contest_count": 1184,
      "measure_count": 402,
      "endorser_count": 611,
      "endorsement_count": 9632,
      "endorsed_contest_count": 730,
      "first_election": "2026-11-03",
      "last_election": "2026-11-03",
      "updated_at": "2026-10-21T14:02:11.408Z"
    }
  ]
}

Contests

The races on a ballot and their choices: candidates, or Yes/No for a measure. Contests carry their voting rules: vote for one, vote for N (votes_allowed), ranked choice (ranks_allowed), or yes/no.

List contests

GET /v1/contests

The races on the ballot, each with its district, its election, its voting rules and every choice in ballot order. Filter by election, state, level, kind or district. To see who endorsed whom, use GET /v1/contests/{id} or /v1/endorsements.

Query parameters

  • electionscomma-separated strings

    Election slugs.

    Example ca-2026-11-03-general
  • statescomma-separated strings

    States the contests are voted in (USPS codes).

    Example CA
  • levelscomma-separated strings

    District levels.

    One of federal, state, county, city, school, special.Example county,city
  • contest_kindscomma-separated strings

    Contest kinds.

    One of candidate, measure, retention.Example measure
  • districtscomma-separated strings

    OCD division ids of the districts.

    Example ocd-division/country:us/state:ca/county:san_francisco
  • upcomingboolean

    Only elections from yesterday on.

    Default false.
  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.
  • limitinteger

    Results per page, 1–200.

    Default 50.1 to 200.
  • cursorstring

    The next_cursor from the previous page.

Returns

200 A page of contests, by id.

  • dataarray of Contest

    This page.

    16 fields
    • idinteger

      Contest id.

    • titlestring

      Title as printed on the ballot.

    • short_titlestring or null

      Shorter title.

    • kindstring

      candidate (an office), measure (a proposition) or retention (keep a judge?).

      One of candidate, measure, retention.
    • vote_methodstring

      How votes are cast: plurality (vote for one), multi_seat (vote for up to votes_allowed), ranked_choice (rank up to ranks_allowed), approval, or yes_no.

      One of plurality, multi_seat, ranked_choice, approval, yes_no.
    • votes_allowedinteger or null

      How many choices a voter may mark (vote for N).

    • ranks_allowedinteger or null

      Ranked choice: how many choices a voter may rank.

    • measure_codestring or null

      The measure’s letter or number: “K”, “Prop 1”.

    • descriptionstring or null

      Measure text or question, where the ballot prints one.

    • ballot_orderinteger or null

      Position on the printed ballot.

    • partyParty or null

      For a party primary, the party.

      3 fields
      • slugstring

        Party slug.

      • namestring

        Party name.

      • abbreviationstring or null

        Short form as printed, e.g. DEM.

    • detailsobject

      Facts about the contest. Only keys that apply are present.

      16 fields
      • uncontestedboolean

        Only one candidate is running.

      • nonpartisanboolean

        Candidates appear without a party.

      • measure_typestring

        bond, charter_amendment, initiative, referendum, tax, …

      • vote_requiredstring

        Share of the vote needed to pass, e.g. "2/3" or "55%".

      • majority_requiredboolean

        A candidate needs a majority to win outright (else a runoff).

      • amountnumber

        Dollar amount of a bond or tax measure.

      • termstring

        Length of the term, e.g. "4 years".

      • short_termboolean

        The seat is for the remainder of an unexpired term.

      • justicestring

        The judge or justice a retention question is about.

      • runoff_datestring (date)

        Date of a runoff, if one is needed.

      • stagestring

        Stage of a multi-round contest.

      • elected_at_largeboolean

        Elected by the whole jurisdiction, not by district.

      • none_of_theseboolean

        The ballot offers “None of these candidates” (Nevada).

      • primary_nominatingboolean

        The primary nominates a party’s candidate.

      • winnersinteger

        Number of winners, where it differs from votes_allowed.

      • ref_typestring

        Kind of referendum.

    • source_urlstring (uri) or null

      The official source the contest was loaded from.

    • districtDistrict

      The district a contest is voted in.

      6 fields
      • idinteger

        District id. Matches an officeholder’s district_id.

      • ocd_idstring or null

        Open Civic Data division id, used in districts= filters.

      • namestring

        District name.

      • levelstring

        Level of government.

        One of federal, state, county, city, school, special.
      • typestring

        Kind of district: statewide, congressional, state_upper, state_lower, county, council, school, …

      • statestring or null

        USPS state code.

    • electionElection
      10 fields
      • idinteger

        Election id.

      • slugstring

        Election slug, used in elections= filters: <state>-<date>-<type>.

      • namestring

        Election name.

      • short_namestring or null

        Shorter name.

      • datestring (date)

        Election day.

      • statestring or null

        State; null for a multi-state election.

      • typestring

        Kind of election.

        One of general, primary, special, special_primary, runoff, consolidated.
      • primary_systemstring or null

        How the state runs primaries.

        One of none, closed, semi_closed, open, top_two, nonpartisan.
      • info_urlstring (uri) or null

        Official election page.

      • detailsobject

        Voting rules for the election. Only keys that apply are present.

        11 fields
        • all_mailboolean

          Every voter is mailed a ballot.

        • ranked_choiceboolean

          Some contests in this election use ranked choice voting.

        • fusion_votingboolean

          Candidates can appear on more than one party’s line (New York, Connecticut).

        • partisan_primaryboolean

          A party primary.

        • primarystring

          Which primary, where a state holds several.

        • consolidated_withstring

          Elections held on the same ballot.

        • runoff_datestring (date)

          Date of a runoff, if one is needed.

        • runoff_election_datestring (date)

          Date of the runoff election.

        • top_two_primary_datestring (date)

          Date of the top-two primary that chose these candidates.

        • louisiana_open_primaryboolean

          Louisiana’s open (jungle) primary.

        • notestring

          Anything else voters should know.

    • choicesarray of Choice

      Every choice, in ballot order.

      9 fields
      • idinteger

        Choice id: the choice_id endorsements refer to.

      • labelstring

        As printed: the candidate’s ballot name, or Yes / No.

      • measure_answerstring or null

        yes or no for a measure or retention question; null for a candidate.

        One of yes, no.
      • optionstring or null

        A special line: none_of_these (Nevada).

        One of none_of_these.
      • ballot_designationstring or null

        Occupation line printed under the name, e.g. “Transit Planner”.

      • withdrawnboolean

        The candidate withdrew but is still printed on the ballot.

      • candidateCandidate or null

        The candidate; null for a measure answer.

        4 fields
        • idinteger

          Candidate id.

        • full_namestring

          Full name.

        • website_urlstring (uri) or null

          Campaign website.

        • photo_urlstring (uri) or null

          Photo.

      • partyParty or null

        The party (or party preference) printed beside the name.

        3 fields
        • slugstring

          Party slug.

        • namestring

          Party name.

        • abbreviationstring or null

          Short form as printed, e.g. DEM.

      • party_labelstring or null

        The party text exactly as printed, where it differs (fusion lines, top-two preferences).

  • next_cursorstring or null

    Pass as cursor= for the next page; null on the last page.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/contests
curl "https://api.ballotdata.net/v1/contests?elections=ca-2026-11-03-general&levels=county&limit=20" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "id": 4410,
      "title": "Member, Board of Supervisors, District 8",
      "short_title": "Supervisor, D8",
      "kind": "candidate",
      "vote_method": "ranked_choice",
      "votes_allowed": 1,
      "ranks_allowed": 10,
      "measure_code": null,
      "description": null,
      "ballot_order": 41,
      "party": null,
      "details": {
        "nonpartisan": true
      },
      "source_url": "https://www.sf.gov/departments/department-elections",
      "district": {
        "id": 77,
        "ocd_id": "ocd-division/country:us/state:ca/county:san_francisco/council_district:8",
        "name": "San Francisco Supervisorial District 8",
        "level": "county",
        "type": "council",
        "state": "CA"
      },
      "election": {
        "id": 3,
        "slug": "ca-2026-11-03-general",
        "name": "California General Election",
        "short_name": "General Election",
        "date": "2026-11-03",
        "state": "CA",
        "type": "general",
        "primary_system": "top_two",
        "info_url": "https://www.sos.ca.gov/elections/upcoming-elections",
        "details": {
          "all_mail": true
        }
      },
      "choices": [
        {
          "id": 20931,
          "label": "Jane Doe",
          "measure_answer": null,
          "option": null,
          "ballot_designation": "Transit Planner",
          "withdrawn": false,
          "candidate": {
            "id": 8811,
            "full_name": "Jane Doe",
            "website_url": "https://example.com/janedoe",
            "photo_url": null
          },
          "party": null,
          "party_label": null
        },
        {
          "id": 20932,
          "label": "Sam Rivera",
          "measure_answer": null,
          "option": null,
          "ballot_designation": "Small Business Owner",
          "withdrawn": false,
          "candidate": {
            "id": 8812,
            "full_name": "Sam Rivera",
            "website_url": null,
            "photo_url": null
          },
          "party": null,
          "party_label": null
        }
      ]
    }
  ],
  "next_cursor": "aTo0NDEw"
}

Get a contest with endorsements

GET /v1/contests/{id}

One contest with its choices and every endorser’s position: one pick for vote-for-one, up to N picks for vote-for-N, ranked picks for ranked choice, Yes or No for a measure. Narrow the endorsers with categories, endorsers or endorser_states.

Path parameters

  • idintegerrequired

    Contest id.

    At least 1.Example 4410

Query parameters

  • categoriescomma-separated strings

    Only endorsers in these categories.

    Example labor,editorial
  • endorserscomma-separated strings

    Only these endorsers.

  • endorser_statescomma-separated strings

    Only endorsers based in these states, or national.

  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.

Returns

200 The contest.

  • dataContestDetail
    17 fields
    • idinteger

      Contest id.

    • titlestring

      Title as printed on the ballot.

    • short_titlestring or null

      Shorter title.

    • kindstring

      candidate (an office), measure (a proposition) or retention (keep a judge?).

      One of candidate, measure, retention.
    • vote_methodstring

      How votes are cast: plurality (vote for one), multi_seat (vote for up to votes_allowed), ranked_choice (rank up to ranks_allowed), approval, or yes_no.

      One of plurality, multi_seat, ranked_choice, approval, yes_no.
    • votes_allowedinteger or null

      How many choices a voter may mark (vote for N).

    • ranks_allowedinteger or null

      Ranked choice: how many choices a voter may rank.

    • measure_codestring or null

      The measure’s letter or number: “K”, “Prop 1”.

    • descriptionstring or null

      Measure text or question, where the ballot prints one.

    • ballot_orderinteger or null

      Position on the printed ballot.

    • partyParty or null

      For a party primary, the party.

      3 fields
      • slugstring

        Party slug.

      • namestring

        Party name.

      • abbreviationstring or null

        Short form as printed, e.g. DEM.

    • detailsobject

      Facts about the contest. Only keys that apply are present.

      16 fields
      • uncontestedboolean

        Only one candidate is running.

      • nonpartisanboolean

        Candidates appear without a party.

      • measure_typestring

        bond, charter_amendment, initiative, referendum, tax, …

      • vote_requiredstring

        Share of the vote needed to pass, e.g. "2/3" or "55%".

      • majority_requiredboolean

        A candidate needs a majority to win outright (else a runoff).

      • amountnumber

        Dollar amount of a bond or tax measure.

      • termstring

        Length of the term, e.g. "4 years".

      • short_termboolean

        The seat is for the remainder of an unexpired term.

      • justicestring

        The judge or justice a retention question is about.

      • runoff_datestring (date)

        Date of a runoff, if one is needed.

      • stagestring

        Stage of a multi-round contest.

      • elected_at_largeboolean

        Elected by the whole jurisdiction, not by district.

      • none_of_theseboolean

        The ballot offers “None of these candidates” (Nevada).

      • primary_nominatingboolean

        The primary nominates a party’s candidate.

      • winnersinteger

        Number of winners, where it differs from votes_allowed.

      • ref_typestring

        Kind of referendum.

    • source_urlstring (uri) or null

      The official source the contest was loaded from.

    • districtDistrict

      The district a contest is voted in.

      6 fields
      • idinteger

        District id. Matches an officeholder’s district_id.

      • ocd_idstring or null

        Open Civic Data division id, used in districts= filters.

      • namestring

        District name.

      • levelstring

        Level of government.

        One of federal, state, county, city, school, special.
      • typestring

        Kind of district: statewide, congressional, state_upper, state_lower, county, council, school, …

      • statestring or null

        USPS state code.

    • electionElection
      10 fields
      • idinteger

        Election id.

      • slugstring

        Election slug, used in elections= filters: <state>-<date>-<type>.

      • namestring

        Election name.

      • short_namestring or null

        Shorter name.

      • datestring (date)

        Election day.

      • statestring or null

        State; null for a multi-state election.

      • typestring

        Kind of election.

        One of general, primary, special, special_primary, runoff, consolidated.
      • primary_systemstring or null

        How the state runs primaries.

        One of none, closed, semi_closed, open, top_two, nonpartisan.
      • info_urlstring (uri) or null

        Official election page.

      • detailsobject

        Voting rules for the election. Only keys that apply are present.

        11 fields
        • all_mailboolean

          Every voter is mailed a ballot.

        • ranked_choiceboolean

          Some contests in this election use ranked choice voting.

        • fusion_votingboolean

          Candidates can appear on more than one party’s line (New York, Connecticut).

        • partisan_primaryboolean

          A party primary.

        • primarystring

          Which primary, where a state holds several.

        • consolidated_withstring

          Elections held on the same ballot.

        • runoff_datestring (date)

          Date of a runoff, if one is needed.

        • runoff_election_datestring (date)

          Date of the runoff election.

        • top_two_primary_datestring (date)

          Date of the top-two primary that chose these candidates.

        • louisiana_open_primaryboolean

          Louisiana’s open (jungle) primary.

        • notestring

          Anything else voters should know.

    • choicesarray of Choice

      Every choice, in ballot order.

      9 fields
      • idinteger

        Choice id: the choice_id endorsements refer to.

      • labelstring

        As printed: the candidate’s ballot name, or Yes / No.

      • measure_answerstring or null

        yes or no for a measure or retention question; null for a candidate.

        One of yes, no.
      • optionstring or null

        A special line: none_of_these (Nevada).

        One of none_of_these.
      • ballot_designationstring or null

        Occupation line printed under the name, e.g. “Transit Planner”.

      • withdrawnboolean

        The candidate withdrew but is still printed on the ballot.

      • candidateCandidate or null

        The candidate; null for a measure answer.

        4 fields
        • idinteger

          Candidate id.

        • full_namestring

          Full name.

        • website_urlstring (uri) or null

          Campaign website.

        • photo_urlstring (uri) or null

          Photo.

      • partyParty or null

        The party (or party preference) printed beside the name.

        3 fields
        • slugstring

          Party slug.

        • namestring

          Party name.

        • abbreviationstring or null

          Short form as printed, e.g. DEM.

      • party_labelstring or null

        The party text exactly as printed, where it differs (fusion lines, top-two preferences).

    • endorsementsarray of Position

      Every (matching) endorser’s position, by endorser name.

      2 fields
      • endorserEndorserRef

        Who made an endorsement.

        5 fields
        • idinteger

          Endorser id.

        • slugstring

          Endorser slug, used in endorsers= filters.

        • namestring

          Endorser name.

        • categoryCategory

          The kind of endorser.

          2 fields
          • slugstring

            Category slug, used in categories= filters.

          • namestring

            Display name.

        • statestring or null

          Home state; null for national endorsers.

      • picksarray of Pick

        One pick for vote-for-one, up to N for vote-for-N, the ranking for ranked choice, Yes or No for a measure.

        7 fields
        • choice_idinteger

          The Choice endorsed.

        • labelstring

          That choice’s label.

        • measure_answerstring or null

          yes or no for a measure.

          One of yes, no.
        • rankinteger or null

          Ranked choice: 1 for first choice, 2 for second, …; null otherwise.

        • statementstring or null

          What the endorser said about it.

        • source_urlstring (uri) or null

          Where the endorsement was published.

        • published_onstring (date) or null

          When it was published.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 404 Nothing has that id or slug.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/contests/{id}
curl "https://api.ballotdata.net/v1/contests/4410?categories=labor,editorial" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": {
    "id": 4410,
    "title": "Member, Board of Supervisors, District 8",
    "short_title": "Supervisor, D8",
    "kind": "candidate",
    "vote_method": "ranked_choice",
    "votes_allowed": 1,
    "ranks_allowed": 10,
    "measure_code": null,
    "description": null,
    "ballot_order": 41,
    "party": null,
    "details": {
      "nonpartisan": true
    },
    "source_url": "https://www.sf.gov/departments/department-elections",
    "district": {
      "id": 77,
      "ocd_id": "ocd-division/country:us/state:ca/county:san_francisco/council_district:8",
      "name": "San Francisco Supervisorial District 8",
      "level": "county",
      "type": "council",
      "state": "CA"
    },
    "election": {
      "id": 3,
      "slug": "ca-2026-11-03-general",
      "name": "California General Election",
      "short_name": "General Election",
      "date": "2026-11-03",
      "state": "CA",
      "type": "general",
      "primary_system": "top_two",
      "info_url": "https://www.sos.ca.gov/elections/upcoming-elections",
      "details": {
        "all_mail": true
      }
    },
    "choices": [
      {
        "id": 20931,
        "label": "Jane Doe",
        "measure_answer": null,
        "option": null,
        "ballot_designation": "Transit Planner",
        "withdrawn": false,
        "candidate": {
          "id": 8811,
          "full_name": "Jane Doe",
          "website_url": "https://example.com/janedoe",
          "photo_url": null
        },
        "party": null,
        "party_label": null
      },
      {
        "id": 20932,
        "label": "Sam Rivera",
        "measure_answer": null,
        "option": null,
        "ballot_designation": "Small Business Owner",
        "withdrawn": false,
        "candidate": {
          "id": 8812,
          "full_name": "Sam Rivera",
          "website_url": null,
          "photo_url": null
        },
        "party": null,
        "party_label": null
      }
    ],
    "endorsements": [
      {
        "endorser": {
          "id": 512,
          "slug": "sf-labor-council",
          "name": "San Francisco Labor Council",
          "category": {
            "slug": "labor",
            "name": "Labor"
          },
          "state": "CA"
        },
        "picks": [
          {
            "choice_id": 20931,
            "label": "Jane Doe",
            "measure_answer": null,
            "rank": 1,
            "statement": null,
            "source_url": "https://sflaborcouncil.org/endorsements",
            "published_on": "2026-09-18"
          },
          {
            "choice_id": 20932,
            "label": "Sam Rivera",
            "measure_answer": null,
            "rank": 2,
            "statement": null,
            "source_url": "https://sflaborcouncil.org/endorsements",
            "published_on": "2026-09-18"
          }
        ]
      },
      {
        "endorser": {
          "id": 88,
          "slug": "sf-chronicle",
          "name": "San Francisco Chronicle",
          "category": {
            "slug": "editorial",
            "name": "Voter guides & editorial boards"
          },
          "state": "CA"
        },
        "picks": [
          {
            "choice_id": 20932,
            "label": "Sam Rivera",
            "measure_answer": null,
            "rank": null,
            "statement": "Rivera has the clearer plan for the district’s corridors.",
            "source_url": "https://www.sfchronicle.com/opinion/endorsements",
            "published_on": "2026-10-02"
          }
        ]
      }
    ]
  }
}

Endorsers

Who endorses: unions, newspapers, parties, clubs, advocacy groups and officials, by category and home state.

List endorser categories

GET /v1/endorser-categories

The kinds of endorser (labor, editorial, environment, business, party, club, community, officials), with how many endorsers each has. Use the slugs in categories= filters.

Query parameters

  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.

Returns

200 Every category, in display order.

  • dataarray of EndorserCategory

    Every item.

    4 fields
    • slugstring

      Category slug, used in categories= filters.

    • namestring

      Display name (plural).

    • singular_namestring

      One of them: “Labor union”.

    • endorser_countinteger

      Endorsers in this category.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/endorser-categories
curl "https://api.ballotdata.net/v1/endorser-categories" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "slug": "editorial",
      "name": "Voter guides & editorial boards",
      "singular_name": "Voter guide",
      "endorser_count": 214
    },
    {
      "slug": "labor",
      "name": "Labor",
      "singular_name": "Labor union",
      "endorser_count": 391
    },
    {
      "slug": "environment",
      "name": "Environment & transportation",
      "singular_name": "Environmental group",
      "endorser_count": 167
    }
  ]
}

List endorsers

GET /v1/endorsers

Endorsers by category, home state, or the elections they’ve endorsed in, or search by name.

Query parameters

  • categoriescomma-separated strings

    Category slugs.

    Example labor
  • statescomma-separated strings

    Home states (USPS codes), or national.

    Example CA
  • electionscomma-separated strings

    Only endorsers with endorsements in these elections.

  • qstring

    Name contains (case-insensitive, up to 100 characters).

    Example labor council
  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.
  • limitinteger

    Results per page, 1–500.

    Default 100.1 to 500.
  • cursorstring

    The next_cursor from the previous page.

Returns

200 A page of endorsers, by id.

  • dataarray of Endorser

    This page.

    10 fields
    • idinteger

      Endorser id.

    • slugstring

      Endorser slug, used in endorsers= filters and GET /v1/endorsers/{slug}.

    • namestring

      Endorser name.

    • categoryCategory

      The kind of endorser.

      2 fields
      • slugstring

        Category slug, used in categories= filters.

      • namestring

        Display name.

    • descriptionstring or null

      About the endorser.

    • website_urlstring (uri) or null

      Endorser’s website.

    • logo_urlstring (uri) or null

      Logo image.

    • statestring or null

      Home state; null for national endorsers.

    • partyParty or null

      The party, for a party or party club.

      3 fields
      • slugstring

        Party slug.

      • namestring

        Party name.

      • abbreviationstring or null

        Short form as printed, e.g. DEM.

    • endorsement_countinteger

      Endorsements this endorser has made, in every election.

  • next_cursorstring or null

    Pass as cursor= for the next page; null on the last page.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/endorsers
curl "https://api.ballotdata.net/v1/endorsers?categories=labor&states=CA&q=labor+council" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "id": 512,
      "slug": "sf-labor-council",
      "name": "San Francisco Labor Council",
      "category": {
        "slug": "labor",
        "name": "Labor"
      },
      "description": "The central labor council for San Francisco, representing over 150 unions.",
      "website_url": "https://sflaborcouncil.org",
      "logo_url": null,
      "state": "CA",
      "party": null,
      "endorsement_count": 84
    }
  ],
  "next_cursor": "aTo1MTI"
}

Get an endorser

GET /v1/endorsers/{slug}

One endorser, with the elections they’ve endorsed in and how many contests in each.

Path parameters

  • slugstringrequired

    Endorser slug.

    Example sf-labor-council

Query parameters

  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.

Returns

200 The endorser.

  • dataEndorserDetail
    10 fields
    • idinteger

      Endorser id.

    • slugstring

      Endorser slug.

    • namestring

      Endorser name.

    • categoryCategory

      The kind of endorser.

      2 fields
      • slugstring

        Category slug, used in categories= filters.

      • namestring

        Display name.

    • descriptionstring or null

      About the endorser.

    • website_urlstring (uri) or null

      Endorser’s website.

    • logo_urlstring (uri) or null

      Logo image.

    • statestring or null

      Home state; null for national endorsers.

    • partyParty or null

      The party, for a party or party club.

      3 fields
      • slugstring

        Party slug.

      • namestring

        Party name.

      • abbreviationstring or null

        Short form as printed, e.g. DEM.

    • electionsarray of object

      Elections the endorser has endorsed in, newest first.

      4 fields
      • electionstring

        Election slug.

      • namestring

        Election name.

      • datestring (date)

        Election day.

      • contestsinteger

        Contests this endorser took a position in.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 404 Nothing has that id or slug.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/endorsers/{slug}
curl "https://api.ballotdata.net/v1/endorsers/sf-labor-council" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": {
    "id": 512,
    "slug": "sf-labor-council",
    "name": "San Francisco Labor Council",
    "category": {
      "slug": "labor",
      "name": "Labor"
    },
    "description": "The central labor council for San Francisco, representing over 150 unions.",
    "website_url": "https://sflaborcouncil.org",
    "logo_url": null,
    "state": "CA",
    "party": null,
    "elections": [
      {
        "election": "ca-2026-11-03-general",
        "name": "California General Election",
        "date": "2026-11-03",
        "contests": 61
      },
      {
        "election": "ca-2026-06-02-primary",
        "name": "California Primary Election",
        "date": "2026-06-02",
        "contests": 23
      }
    ]
  }
}

Endorsements

Who each endorser backs in each race.

List endorsements

GET /v1/endorsements

Endorsements, one per endorser and choice, each with its endorser, contest (with district and election) and choice. A ranked-choice endorsement of three candidates is three rows with ranks 1–3. This is the way to sync everything, or to catch up after the stream.

Query parameters

  • categoriescomma-separated strings

    Endorser category slugs (GET /v1/endorser-categories).

    Example labor
  • endorserscomma-separated strings

    Endorser slugs.

    Example sf-labor-council
  • endorser_statescomma-separated strings

    Endorsers’ home states (USPS codes), or national for endorsers with none.

    Example CA,national
  • electionscomma-separated strings

    Election slugs.

    Example ca-2026-11-03-general
  • statescomma-separated strings

    States the contests are voted in (USPS codes).

    Example CA
  • contest_kindscomma-separated strings

    Contest kinds.

    One of candidate, measure, retention.Example measure
  • levelscomma-separated strings

    District levels.

    One of federal, state, county, city, school, special.Example county,city
  • contestinteger

    Only this contest.

    At least 1.Example 4410
  • upcomingboolean

    Only elections from yesterday on.

    Default false.
  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.
  • limitinteger

    Results per page, 1–500.

    Default 100.1 to 500.
  • cursorstring

    The next_cursor from the previous page.

Returns

200 A page of endorsements, by id.

  • dataarray of Endorsement

    This page.

    8 fields
    • idinteger

      Endorsement id.

    • rankinteger or null

      Ranked choice: the rank the endorser gave; null otherwise.

    • statementstring or null

      What the endorser said.

    • source_urlstring (uri) or null

      Where it was published.

    • published_onstring (date) or null

      When it was published.

    • endorserEndorserRef

      Who made an endorsement.

      5 fields
      • idinteger

        Endorser id.

      • slugstring

        Endorser slug, used in endorsers= filters.

      • namestring

        Endorser name.

      • categoryCategory

        The kind of endorser.

        2 fields
        • slugstring

          Category slug, used in categories= filters.

        • namestring

          Display name.

      • statestring or null

        Home state; null for national endorsers.

    • contestContestBase
      15 fields
      • idinteger

        Contest id.

      • titlestring

        Title as printed on the ballot.

      • short_titlestring or null

        Shorter title.

      • kindstring

        candidate (an office), measure (a proposition) or retention (keep a judge?).

        One of candidate, measure, retention.
      • vote_methodstring

        How votes are cast: plurality (vote for one), multi_seat (vote for up to votes_allowed), ranked_choice (rank up to ranks_allowed), approval, or yes_no.

        One of plurality, multi_seat, ranked_choice, approval, yes_no.
      • votes_allowedinteger or null

        How many choices a voter may mark (vote for N).

      • ranks_allowedinteger or null

        Ranked choice: how many choices a voter may rank.

      • measure_codestring or null

        The measure’s letter or number: “K”, “Prop 1”.

      • descriptionstring or null

        Measure text or question, where the ballot prints one.

      • ballot_orderinteger or null

        Position on the printed ballot.

      • partyParty or null

        For a party primary, the party.

        3 fields
        • slugstring

          Party slug.

        • namestring

          Party name.

        • abbreviationstring or null

          Short form as printed, e.g. DEM.

      • detailsobject

        Facts about the contest. Only keys that apply are present.

        16 fields
        • uncontestedboolean

          Only one candidate is running.

        • nonpartisanboolean

          Candidates appear without a party.

        • measure_typestring

          bond, charter_amendment, initiative, referendum, tax, …

        • vote_requiredstring

          Share of the vote needed to pass, e.g. "2/3" or "55%".

        • majority_requiredboolean

          A candidate needs a majority to win outright (else a runoff).

        • amountnumber

          Dollar amount of a bond or tax measure.

        • termstring

          Length of the term, e.g. "4 years".

        • short_termboolean

          The seat is for the remainder of an unexpired term.

        • justicestring

          The judge or justice a retention question is about.

        • runoff_datestring (date)

          Date of a runoff, if one is needed.

        • stagestring

          Stage of a multi-round contest.

        • elected_at_largeboolean

          Elected by the whole jurisdiction, not by district.

        • none_of_theseboolean

          The ballot offers “None of these candidates” (Nevada).

        • primary_nominatingboolean

          The primary nominates a party’s candidate.

        • winnersinteger

          Number of winners, where it differs from votes_allowed.

        • ref_typestring

          Kind of referendum.

      • source_urlstring (uri) or null

        The official source the contest was loaded from.

      • districtDistrict

        The district a contest is voted in.

        6 fields
        • idinteger

          District id. Matches an officeholder’s district_id.

        • ocd_idstring or null

          Open Civic Data division id, used in districts= filters.

        • namestring

          District name.

        • levelstring

          Level of government.

          One of federal, state, county, city, school, special.
        • typestring

          Kind of district: statewide, congressional, state_upper, state_lower, county, council, school, …

        • statestring or null

          USPS state code.

      • electionElection
        10 fields
        • idinteger

          Election id.

        • slugstring

          Election slug, used in elections= filters: <state>-<date>-<type>.

        • namestring

          Election name.

        • short_namestring or null

          Shorter name.

        • datestring (date)

          Election day.

        • statestring or null

          State; null for a multi-state election.

        • typestring

          Kind of election.

          One of general, primary, special, special_primary, runoff, consolidated.
        • primary_systemstring or null

          How the state runs primaries.

          One of none, closed, semi_closed, open, top_two, nonpartisan.
        • info_urlstring (uri) or null

          Official election page.

        • detailsobject

          Voting rules for the election. Only keys that apply are present.

          11 fields
          • all_mailboolean

            Every voter is mailed a ballot.

          • ranked_choiceboolean

            Some contests in this election use ranked choice voting.

          • fusion_votingboolean

            Candidates can appear on more than one party’s line (New York, Connecticut).

          • partisan_primaryboolean

            A party primary.

          • primarystring

            Which primary, where a state holds several.

          • consolidated_withstring

            Elections held on the same ballot.

          • runoff_datestring (date)

            Date of a runoff, if one is needed.

          • runoff_election_datestring (date)

            Date of the runoff election.

          • top_two_primary_datestring (date)

            Date of the top-two primary that chose these candidates.

          • louisiana_open_primaryboolean

            Louisiana’s open (jungle) primary.

          • notestring

            Anything else voters should know.

    • choiceobject
      8 fields
      • idinteger

        Choice id.

      • labelstring

        As printed.

      • measure_answerstring or null

        yes or no for a measure.

        One of yes, no.
      • optionstring or null

        none_of_these, for that line.

        One of none_of_these.
      • withdrawnboolean

        The candidate withdrew.

      • candidateobject or null

        The candidate; null for a measure answer.

        2 fields
        • idinteger

          Candidate id.

        • full_namestring

          Full name.

      • partyParty or null

        Printed party.

        3 fields
        • slugstring

          Party slug.

        • namestring

          Party name.

        • abbreviationstring or null

          Short form as printed, e.g. DEM.

      • party_labelstring or null

        Party text as printed.

  • next_cursorstring or null

    Pass as cursor= for the next page; null on the last page.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/endorsements
curl "https://api.ballotdata.net/v1/endorsements?elections=ca-2026-11-03-general&categories=labor" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "id": 90211,
      "rank": 1,
      "statement": null,
      "source_url": "https://sflaborcouncil.org/endorsements",
      "published_on": "2026-09-18",
      "endorser": {
        "id": 512,
        "slug": "sf-labor-council",
        "name": "San Francisco Labor Council",
        "category": {
          "slug": "labor",
          "name": "Labor"
        },
        "state": "CA"
      },
      "contest": {
        "id": 4410,
        "title": "Member, Board of Supervisors, District 8",
        "short_title": "Supervisor, D8",
        "kind": "candidate",
        "vote_method": "ranked_choice",
        "votes_allowed": 1,
        "ranks_allowed": 10,
        "measure_code": null,
        "description": null,
        "ballot_order": 41,
        "party": null,
        "details": {
          "nonpartisan": true
        },
        "source_url": "https://www.sf.gov/departments/department-elections",
        "district": {
          "id": 77,
          "ocd_id": "ocd-division/country:us/state:ca/county:san_francisco/council_district:8",
          "name": "San Francisco Supervisorial District 8",
          "level": "county",
          "type": "council",
          "state": "CA"
        },
        "election": {
          "id": 3,
          "slug": "ca-2026-11-03-general",
          "name": "California General Election",
          "short_name": "General Election",
          "date": "2026-11-03",
          "state": "CA",
          "type": "general",
          "primary_system": "top_two",
          "info_url": "https://www.sos.ca.gov/elections/upcoming-elections",
          "details": {
            "all_mail": true
          }
        }
      },
      "choice": {
        "id": 20931,
        "label": "Jane Doe",
        "measure_answer": null,
        "option": null,
        "withdrawn": false,
        "candidate": {
          "id": 8811,
          "full_name": "Jane Doe"
        },
        "party": null,
        "party_label": null
      }
    }
  ],
  "next_cursor": "aTo5MDIxMQ"
}

Officeholders

Who holds each seat now, from Open States.

List officeholders

GET /v1/officeholders

People in office now, with party, term and contact details. Filter by state, office, level or seat (OCD id). Federal and state offices, and the D.C. Council.

Query parameters

  • statescomma-separated strings

    USPS codes.

    Example CA
  • officescomma-separated strings

    Offices.

    One of us_senator, us_representative, governor, lieutenant_governor, attorney_general, secretary_of_state, chief_election_officer, treasurer, auditor, state_senator, state_representative, state_legislator, city_council.Example us_senator,governor
  • levelscomma-separated strings

    Levels.

    One of federal, state, city.Example federal
  • districtscomma-separated strings

    OCD division ids of the seats.

    Example ocd-division/country:us/state:ca/sldl:17
  • qstring

    Name contains.

  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.
  • limitinteger

    Results per page, 1–500.

    Default 100.1 to 500.
  • cursorstring

    The next_cursor from the previous page.

Returns

200 A page of officeholders.

  • dataarray of Officeholder

    This page.

    23 fields
    • person_idstring (uuid)

      Open States person id; stays the same across terms and offices.

    • namestring

      Full name.

    • given_namestring or null

      Given name.

    • family_namestring or null

      Family name.

    • officestring

      The office.

      One of us_senator, us_representative, governor, lieutenant_governor, attorney_general, secretary_of_state, chief_election_officer, treasurer, auditor, state_senator, state_representative, state_legislator, city_council.
    • office_titlestring

      Title the state uses: “Assemblymember”, “Delegate”.

    • levelstring

      Level of government.

      One of federal, state, city.
    • statestring

      USPS state code.

    • districtstring or null

      District as the legislature names it: "12", "1A", "21st Middlesex".

    • district_ocd_idstring

      OCD division id of the seat.

    • district_idinteger or null

      The matching contest district id, where there is one.

    • partystring or null

      Party as published: “Democratic”, “Republican/Conservative”.

    • party_abbreviationstring or null

      Party abbreviation.

    • term_startstring (date) or null

      Start of the current term.

    • term_endstring (date) or null

      End of the current term.

    • emailstring (email) or null

      Office email.

    • phonestring or null

      Office phone (capitol office first).

    • website_urlstring (uri) or null

      Official page.

    • image_urlstring (uri) or null

      Official photo.

    • officesarray of object

      Offices with their addresses and phones.

      4 fields
      • classificationstring

        capitol, district, …

      • addressstring

        Mailing address.

      • voicestring

        Phone.

      • faxstring

        Fax.

    • socialobject

      Social accounts, where known.

      4 fields
      • twitterstring

        Handle.

      • facebookstring

        Handle.

      • instagramstring

        Handle.

      • youtubestring

        Handle.

    • source_urlsarray of string (uri)

      Where the data came from.

    • updated_atstring (date-time)

      Last refreshed.

  • next_cursorstring or null

    Pass as cursor= for the next page; null on the last page.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
  • 503 Not ready yet on this server. Wait Retry-After seconds.
GET /v1/officeholders
curl "https://api.ballotdata.net/v1/officeholders?states=CA&offices=state_representative" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "person_id": "4f6a2c1e-8b3d-4e5f-9a7b-1c2d3e4f5a6b",
      "name": "Alex Morgan",
      "given_name": "Alex",
      "family_name": "Morgan",
      "office": "state_representative",
      "office_title": "Assemblymember",
      "level": "state",
      "state": "CA",
      "district": "17",
      "district_ocd_id": "ocd-division/country:us/state:ca/sldl:17",
      "district_id": 1203,
      "party": "Democratic",
      "party_abbreviation": "DEM",
      "term_start": "2024-12-02",
      "term_end": "2026-11-30",
      "email": "assemblymember.morgan@example.gov",
      "phone": "916-555-0117",
      "website_url": "https://example.gov/morgan",
      "image_url": null,
      "offices": [
        {
          "classification": "capitol",
          "address": "1021 O Street, Sacramento, CA 95814",
          "voice": "916-555-0117"
        }
      ],
      "social": {
        "twitter": "AsmMorgan"
      },
      "source_urls": ["https://www.assembly.ca.gov/assemblymembers"],
      "updated_at": "2026-10-12T08:00:00Z"
    }
  ],
  "next_cursor": "aToxMjA0"
}

Get an officeholder

GET /v1/officeholders/{id}

One officeholder by person_id, with every seat they hold.

Path parameters

  • idstring (uuid)required

    The officeholder’s person_id.

    Example 4f6a2c1e-8b3d-4e5f-9a7b-1c2d3e4f5a6b

Query parameters

  • langstring

    es for Spanish ballot text (titles, choices, measure text, statements) where the state publishes it; English otherwise. Names are never translated.

    One of en, es.Default en.

Returns

200 The officeholder.

  • dataOfficeholderDetail
    24 fields
    • person_idstring (uuid)

      Open States person id; stays the same across terms and offices.

    • namestring

      Full name.

    • given_namestring or null

      Given name.

    • family_namestring or null

      Family name.

    • officestring

      The office.

      One of us_senator, us_representative, governor, lieutenant_governor, attorney_general, secretary_of_state, chief_election_officer, treasurer, auditor, state_senator, state_representative, state_legislator, city_council.
    • office_titlestring

      Title the state uses: “Assemblymember”, “Delegate”.

    • levelstring

      Level of government.

      One of federal, state, city.
    • statestring

      USPS state code.

    • districtstring or null

      District as the legislature names it: "12", "1A", "21st Middlesex".

    • district_ocd_idstring

      OCD division id of the seat.

    • district_idinteger or null

      The matching contest district id, where there is one.

    • partystring or null

      Party as published: “Democratic”, “Republican/Conservative”.

    • party_abbreviationstring or null

      Party abbreviation.

    • term_startstring (date) or null

      Start of the current term.

    • term_endstring (date) or null

      End of the current term.

    • emailstring (email) or null

      Office email.

    • phonestring or null

      Office phone (capitol office first).

    • website_urlstring (uri) or null

      Official page.

    • image_urlstring (uri) or null

      Official photo.

    • officesarray of object

      Offices with their addresses and phones.

      4 fields
      • classificationstring

        capitol, district, …

      • addressstring

        Mailing address.

      • voicestring

        Phone.

      • faxstring

        Fax.

    • socialobject

      Social accounts, where known.

      4 fields
      • twitterstring

        Handle.

      • facebookstring

        Handle.

      • instagramstring

        Handle.

      • youtubestring

        Handle.

    • source_urlsarray of string (uri)

      Where the data came from.

    • updated_atstring (date-time)

      Last refreshed.

    • seatsarray of Officeholder

      Every seat they hold (rarely more than one).

      23 fields
      • person_idstring (uuid)

        Open States person id; stays the same across terms and offices.

      • namestring

        Full name.

      • given_namestring or null

        Given name.

      • family_namestring or null

        Family name.

      • officestring

        The office.

        One of us_senator, us_representative, governor, lieutenant_governor, attorney_general, secretary_of_state, chief_election_officer, treasurer, auditor, state_senator, state_representative, state_legislator, city_council.
      • office_titlestring

        Title the state uses: “Assemblymember”, “Delegate”.

      • levelstring

        Level of government.

        One of federal, state, city.
      • statestring

        USPS state code.

      • districtstring or null

        District as the legislature names it: "12", "1A", "21st Middlesex".

      • district_ocd_idstring

        OCD division id of the seat.

      • district_idinteger or null

        The matching contest district id, where there is one.

      • partystring or null

        Party as published: “Democratic”, “Republican/Conservative”.

      • party_abbreviationstring or null

        Party abbreviation.

      • term_startstring (date) or null

        Start of the current term.

      • term_endstring (date) or null

        End of the current term.

      • emailstring (email) or null

        Office email.

      • phonestring or null

        Office phone (capitol office first).

      • website_urlstring (uri) or null

        Official page.

      • image_urlstring (uri) or null

        Official photo.

      • officesarray of object

        Offices with their addresses and phones.

        4 fields
        • classificationstring

          capitol, district, …

        • addressstring

          Mailing address.

        • voicestring

          Phone.

        • faxstring

          Fax.

      • socialobject

        Social accounts, where known.

        4 fields
        • twitterstring

          Handle.

        • facebookstring

          Handle.

        • instagramstring

          Handle.

        • youtubestring

          Handle.

      • source_urlsarray of string (uri)

        Where the data came from.

      • updated_atstring (date-time)

        Last refreshed.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 404 Nothing has that id or slug.
  • 429 Over a rate limit. Wait Retry-After seconds.
  • 503 Not ready yet on this server. Wait Retry-After seconds.
GET /v1/officeholders/{id}
curl "https://api.ballotdata.net/v1/officeholders/4f6a2c1e-8b3d-4e5f-9a7b-1c2d3e4f5a6b" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": {
    "person_id": "4f6a2c1e-8b3d-4e5f-9a7b-1c2d3e4f5a6b",
    "name": "Alex Morgan",
    "given_name": "Alex",
    "family_name": "Morgan",
    "office": "state_representative",
    "office_title": "Assemblymember",
    "level": "state",
    "state": "CA",
    "district": "17",
    "district_ocd_id": "ocd-division/country:us/state:ca/sldl:17",
    "district_id": 1203,
    "party": "Democratic",
    "party_abbreviation": "DEM",
    "term_start": "2024-12-02",
    "term_end": "2026-11-30",
    "email": "assemblymember.morgan@example.gov",
    "phone": "916-555-0117",
    "website_url": "https://example.gov/morgan",
    "image_url": null,
    "offices": [
      {
        "classification": "capitol",
        "address": "1021 O Street, Sacramento, CA 95814",
        "voice": "916-555-0117"
      }
    ],
    "social": {
      "twitter": "AsmMorgan"
    },
    "source_urls": ["https://www.assembly.ca.gov/assemblymembers"],
    "updated_at": "2026-10-12T08:00:00Z",
    "seats": [
      {
        "person_id": "4f6a2c1e-8b3d-4e5f-9a7b-1c2d3e4f5a6b",
        "name": "Alex Morgan",
        "given_name": "Alex",
        "family_name": "Morgan",
        "office": "state_representative",
        "office_title": "Assemblymember",
        "level": "state",
        "state": "CA",
        "district": "17",
        "district_ocd_id": "ocd-division/country:us/state:ca/sldl:17",
        "district_id": 1203,
        "party": "Democratic",
        "party_abbreviation": "DEM",
        "term_start": "2024-12-02",
        "term_end": "2026-11-30",
        "email": "assemblymember.morgan@example.gov",
        "phone": "916-555-0117",
        "website_url": "https://example.gov/morgan",
        "image_url": null,
        "offices": [
          {
            "classification": "capitol",
            "address": "1021 O Street, Sacramento, CA 95814",
            "voice": "916-555-0117"
          }
        ],
        "social": {
          "twitter": "AsmMorgan"
        },
        "source_urls": ["https://www.assembly.ca.gov/assemblymembers"],
        "updated_at": "2026-10-12T08:00:00Z"
      }
    ]
  }
}

Stream

Every endorsement added, changed or removed, as Server-Sent Events or by polling. Needs the stream:read scope and a plan that includes the stream.

Stream endorsement changes (SSE)

GET /v1/stream

Every endorsement change matching a subscription or inline filter, as Server-Sent Events, within seconds of it happening. Events: ready (first, with the subscription name), endorsement (an Event), checkpoint (moves your position past changes your filter skipped), reconnect (we end connections after an hour), and error (cursor_expired). A comment line arrives every 20 seconds.

Each event id is a cursor: reconnect with Last-Event-ID (EventSource does this itself) or ?cursor= to continue. Opening a stream counts as one request; your plan sets how many you can hold open.

Query parameters

  • subscriptionstring

    A saved subscription’s id or name, instead of filter parameters.

    Example CA labor
  • categoriescomma-separated strings

    Endorser category slugs (GET /v1/endorser-categories).

    Example labor
  • endorserscomma-separated strings

    Endorser slugs.

    Example sf-labor-council
  • endorser_statescomma-separated strings

    Endorsers’ home states (USPS codes), or national for endorsers with none.

    Example CA,national
  • statescomma-separated strings

    States the contests are voted in (USPS codes).

    Example CA
  • electionscomma-separated strings

    Election slugs.

    Example ca-2026-11-03-general
  • contest_kindscomma-separated strings

    Contest kinds.

    One of candidate, measure, retention.Example measure
  • levelscomma-separated strings

    District levels.

    One of federal, state, county, city, school, special.Example county,city
  • typescomma-separated strings

    Kinds of change.

    One of created, updated, deleted.Example created,updated
  • cursorstring

    Resume after this position: a next_cursor, or an SSE event id. Also read from the Last-Event-ID header.

  • fromstring

    Where to start without a cursor.

    One of latest, earliest.Default latest.
  • sincestring (date-time)

    Start at changes from this time, within the stream’s retention.

Returns

200 An open event stream.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 404 Nothing has that id or slug.
  • 410 The cursor is older than the stream keeps.
  • 429 Over a rate limit. Wait Retry-After seconds.
  • 503 Not ready yet on this server. Wait Retry-After seconds.
GET /v1/stream
curl -N "https://api.ballotdata.net/v1/stream?subscription=CA%20labor" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200text/event-stream
retry: 5000

id: c1.eyJzIjp7IjAiOiIxODM0MSJ9fQ
event: ready
data: {"subscription":"CA labor"}

id: c1.eyJzIjp7IjAiOiIxODM0MiJ9fQ
event: endorsement
data: {"id":"18342","type":"endorsement.created","occurred_at":"2026-10-14T21:07:33.512Z","endorsement":{"id":90211,"rank":1,"statement":null,"source_url":"https://sflaborcouncil.org/endorsements","published_on":"2026-09-18"},"endorser":{"id":512,"slug":"sf-labor-council","name":"San Francisco Labor Council","category":{"slug":"labor","name":"Labor"},"state":"CA"},"contest":{"id":4410,"title":"Member, Board of Supervisors, District 8","short_title":"Supervisor, D8","kind":"candidate","vote_method":"ranked_choice","votes_allowed":1,"ranks_allowed":10,"measure_code":null,"district":{"id":77,"name":"San Francisco Supervisorial District 8","level":"county","ocd_id":"ocd-division/country:us/state:ca/county:san_francisco/council_district:8","state":"CA"}},"election":{"id":3,"slug":"ca-2026-11-03-general","name":"California General Election","date":"2026-11-03","state":"CA","type":"general"},"choice":{"id":20931,"label":"Jane Doe","measure_answer":null,"candidate":{"id":8811,"full_name":"Jane Doe"},"party":null,"withdrawn":false}}

: ping

id: c1.eyJzIjp7IjAiOiIxODM1MCJ9fQ
event: checkpoint
data: {}

Poll endorsement changes

GET /v1/events

The same changes as the stream, a page at a time. Store next_cursor and send it next time; wait (up to 25 seconds) holds the request open until a matching change arrives. has_more means call again right away.

Query parameters

  • subscriptionstring

    A saved subscription’s id or name, instead of filter parameters.

    Example CA labor
  • categoriescomma-separated strings

    Endorser category slugs (GET /v1/endorser-categories).

    Example labor
  • endorserscomma-separated strings

    Endorser slugs.

    Example sf-labor-council
  • endorser_statescomma-separated strings

    Endorsers’ home states (USPS codes), or national for endorsers with none.

    Example CA,national
  • statescomma-separated strings

    States the contests are voted in (USPS codes).

    Example CA
  • electionscomma-separated strings

    Election slugs.

    Example ca-2026-11-03-general
  • contest_kindscomma-separated strings

    Contest kinds.

    One of candidate, measure, retention.Example measure
  • levelscomma-separated strings

    District levels.

    One of federal, state, county, city, school, special.Example county,city
  • typescomma-separated strings

    Kinds of change.

    One of created, updated, deleted.Example created,updated
  • cursorstring

    Resume after this position: a next_cursor, or an SSE event id. Also read from the Last-Event-ID header.

  • fromstring

    Where to start without a cursor.

    One of latest, earliest.Default latest.
  • sincestring (date-time)

    Start at changes from this time, within the stream’s retention.

  • limitinteger

    Events per page, 1–1000.

    Default 100.1 to 1000.
  • waitinteger

    Seconds to wait for a change (long polling).

    Default 0.0 to 25.Example 20

Returns

200 Events and the next cursor.

  • dataarray of Event

    Changes, oldest first.

    8 fields
    • idstring

      The change’s id: increasing and unique. Use it to drop repeats.

    • typestring

      What happened.

      One of endorsement.created, endorsement.updated, endorsement.deleted.
    • occurred_atstring (date-time)

      When the change was made.

    • endorsementobject
      5 fields
      • idinteger

        Endorsement id.

      • rankinteger or null

        Ranked choice rank.

      • statementstring or null

        What the endorser said.

      • source_urlstring or null

        Where it was published.

      • published_onstring (date) or null

        When.

    • endorserobject
      5 fields
      • idinteger

        Endorser id.

      • slugstring or null

        Endorser slug.

      • namestring or null

        Endorser name.

      • categoryCategory or null

        Category.

        2 fields
        • slugstring

          Category slug, used in categories= filters.

        • namestring

          Display name.

      • statestring or null

        Home state, or null for national.

    • contestobject
      9 fields
      • idinteger

        Contest id.

      • titlestring or null

        Title.

      • short_titlestring or null

        Short title.

      • kindstring or null

        candidate, measure or retention.

      • vote_methodstring or null

        Vote method.

      • votes_allowedinteger or null

        Vote for N.

      • ranks_allowedinteger or null

        Ranks allowed.

      • measure_codestring or null

        Measure code.

      • districtobject or null

        District.

        5 fields
        • idinteger

          District id.

        • namestring

          Name.

        • levelstring

          Level.

        • ocd_idstring or null

          OCD id.

        • statestring or null

          State.

    • electionobject or null

      Election.

      6 fields
      • idinteger

        Election id.

      • slugstring

        Slug.

      • namestring

        Name.

      • datestring (date)

        Date.

      • statestring or null

        State.

      • typestring

        Type.

    • choiceobject
      6 fields
      • idinteger

        Choice id.

      • labelstring or null

        As printed.

      • measure_answerstring or null

        yes or no.

        One of yes, no.
      • candidateobject or null

        Candidate.

        2 fields
        • idinteger

          Candidate id.

        • full_namestring

          Full name.

      • partyobject or null

        Party.

        2 fields
        • slugstring

          Slug.

        • namestring

          Name.

      • withdrawnboolean or null

        Withdrawn.

  • next_cursorstring

    Send as cursor= next time.

  • has_moreboolean

    More are waiting: call again now.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 404 Nothing has that id or slug.
  • 410 The cursor is older than the stream keeps.
  • 429 Over a rate limit. Wait Retry-After seconds.
  • 503 Not ready yet on this server. Wait Retry-After seconds.
GET /v1/events
curl "https://api.ballotdata.net/v1/events?subscription=CA+labor&cursor=c1.eyJzIjp7IjAiOiIxODM0MSJ9fQ&wait=20" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "id": "18342",
      "type": "endorsement.created",
      "occurred_at": "2026-10-14T21:07:33.512Z",
      "endorsement": {
        "id": 90211,
        "rank": 1,
        "statement": null,
        "source_url": "https://sflaborcouncil.org/endorsements",
        "published_on": "2026-09-18"
      },
      "endorser": {
        "id": 512,
        "slug": "sf-labor-council",
        "name": "San Francisco Labor Council",
        "category": {
          "slug": "labor",
          "name": "Labor"
        },
        "state": "CA"
      },
      "contest": {
        "id": 4410,
        "title": "Member, Board of Supervisors, District 8",
        "short_title": "Supervisor, D8",
        "kind": "candidate",
        "vote_method": "ranked_choice",
        "votes_allowed": 1,
        "ranks_allowed": 10,
        "measure_code": null,
        "district": {
          "id": 77,
          "name": "San Francisco Supervisorial District 8",
          "level": "county",
          "ocd_id": "ocd-division/country:us/state:ca/county:san_francisco/council_district:8",
          "state": "CA"
        }
      },
      "election": {
        "id": 3,
        "slug": "ca-2026-11-03-general",
        "name": "California General Election",
        "date": "2026-11-03",
        "state": "CA",
        "type": "general"
      },
      "choice": {
        "id": 20931,
        "label": "Jane Doe",
        "measure_answer": null,
        "candidate": {
          "id": 8811,
          "full_name": "Jane Doe"
        },
        "party": null,
        "withdrawn": false
      }
    }
  ],
  "next_cursor": "c1.eyJzIjp7IjAiOiIxODM0MiJ9fQ",
  "has_more": false
}

Subscriptions

Saved filters for the stream and events. Reading needs stream:read; changing needs subscriptions:write.

List subscriptions

GET /v1/subscriptions

Your account’s saved subscriptions, by name.

Returns

200 Every subscription.

  • dataarray of Subscription

    Every item.

    5 fields
    • idinteger

      Subscription id.

    • namestring

      Name, unique in your account.

    • filterFilter

      Which endorsements: fields combine with AND, values within a field with OR, and a missing field matches everything. Each field takes at most 500 values.

      8 fields
      • categoriesarray of string

        Endorser category slugs (GET /v1/endorser-categories).

      • endorsersarray of string

        Endorser slugs.

      • endorser_statesarray of string

        Endorsers’ home states (USPS codes), or "national".

      • statesarray of string

        States the contests are voted in.

      • electionsarray of string

        Election slugs.

      • contest_kindsarray of string

        Contest kinds.

        One of candidate, measure, retention.
      • levelsarray of string

        District levels.

        One of federal, state, county, city, school, special.
      • typesarray of string

        Stream only: kinds of change.

        One of created, updated, deleted.
    • created_atstring (date-time)

      Created.

    • updated_atstring (date-time)

      Last changed.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/subscriptions
curl "https://api.ballotdata.net/v1/subscriptions" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": [
    {
      "id": 7,
      "name": "CA labor",
      "filter": {
        "categories": ["labor"],
        "states": ["CA"]
      },
      "created_at": "2026-10-15T17:20:04.112Z",
      "updated_at": "2026-10-15T17:20:04.112Z"
    }
  ]
}

Create a subscription

POST /v1/subscriptions

Save a named filter. Use it as subscription=<id or name> on /v1/stream and /v1/events. An account can have up to 50.

Request body

JSON.

  • namestring

    1–100 letters, digits, spaces, dots, dashes or underscores.

  • filterFilter

    Which endorsements: fields combine with AND, values within a field with OR, and a missing field matches everything. Each field takes at most 500 values.

    8 fields
    • categoriesarray of string

      Endorser category slugs (GET /v1/endorser-categories).

    • endorsersarray of string

      Endorser slugs.

    • endorser_statesarray of string

      Endorsers’ home states (USPS codes), or "national".

    • statesarray of string

      States the contests are voted in.

    • electionsarray of string

      Election slugs.

    • contest_kindsarray of string

      Contest kinds.

      One of candidate, measure, retention.
    • levelsarray of string

      District levels.

      One of federal, state, county, city, school, special.
    • typesarray of string

      Stream only: kinds of change.

      One of created, updated, deleted.

Returns

201 Created.

  • dataSubscription
    5 fields
    • idinteger

      Subscription id.

    • namestring

      Name, unique in your account.

    • filterFilter

      Which endorsements: fields combine with AND, values within a field with OR, and a missing field matches everything. Each field takes at most 500 values.

      8 fields
      • categoriesarray of string

        Endorser category slugs (GET /v1/endorser-categories).

      • endorsersarray of string

        Endorser slugs.

      • endorser_statesarray of string

        Endorsers’ home states (USPS codes), or "national".

      • statesarray of string

        States the contests are voted in.

      • electionsarray of string

        Election slugs.

      • contest_kindsarray of string

        Contest kinds.

        One of candidate, measure, retention.
      • levelsarray of string

        District levels.

        One of federal, state, county, city, school, special.
      • typesarray of string

        Stream only: kinds of change.

        One of created, updated, deleted.
    • created_atstring (date-time)

      Created.

    • updated_atstring (date-time)

      Last changed.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 409 A subscription with that name already exists.
  • 429 Over a rate limit. Wait Retry-After seconds.
POST /v1/subscriptions
curl -X POST "https://api.ballotdata.net/v1/subscriptions" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"CA labor","filter":{"categories":["labor"],"states":["CA"]}}'
Response201application/json
{
  "data": {
    "id": 7,
    "name": "CA labor",
    "filter": {
      "categories": ["labor"],
      "states": ["CA"]
    },
    "created_at": "2026-10-15T17:20:04.112Z",
    "updated_at": "2026-10-15T17:20:04.112Z"
  }
}

Get a subscription

GET /v1/subscriptions/{id}

One saved subscription.

Path parameters

  • idintegerrequired

    Subscription id.

    Example 7

Returns

200 The subscription.

  • dataSubscription
    5 fields
    • idinteger

      Subscription id.

    • namestring

      Name, unique in your account.

    • filterFilter

      Which endorsements: fields combine with AND, values within a field with OR, and a missing field matches everything. Each field takes at most 500 values.

      8 fields
      • categoriesarray of string

        Endorser category slugs (GET /v1/endorser-categories).

      • endorsersarray of string

        Endorser slugs.

      • endorser_statesarray of string

        Endorsers’ home states (USPS codes), or "national".

      • statesarray of string

        States the contests are voted in.

      • electionsarray of string

        Election slugs.

      • contest_kindsarray of string

        Contest kinds.

        One of candidate, measure, retention.
      • levelsarray of string

        District levels.

        One of federal, state, county, city, school, special.
      • typesarray of string

        Stream only: kinds of change.

        One of created, updated, deleted.
    • created_atstring (date-time)

      Created.

    • updated_atstring (date-time)

      Last changed.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 404 Nothing has that id or slug.
  • 429 Over a rate limit. Wait Retry-After seconds.
GET /v1/subscriptions/{id}
curl "https://api.ballotdata.net/v1/subscriptions/7" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response200application/json
{
  "data": {
    "id": 7,
    "name": "CA labor",
    "filter": {
      "categories": ["labor"],
      "states": ["CA"]
    },
    "created_at": "2026-10-15T17:20:04.112Z",
    "updated_at": "2026-10-15T17:20:04.112Z"
  }
}

Replace a subscription

PUT /v1/subscriptions/{id}

Replace a subscription’s name and filter. Open streams using it keep their old filter until they reconnect.

Path parameters

  • idintegerrequired

    Subscription id.

    Example 7

Request body

JSON.

  • namestring

    1–100 letters, digits, spaces, dots, dashes or underscores.

  • filterFilter

    Which endorsements: fields combine with AND, values within a field with OR, and a missing field matches everything. Each field takes at most 500 values.

    8 fields
    • categoriesarray of string

      Endorser category slugs (GET /v1/endorser-categories).

    • endorsersarray of string

      Endorser slugs.

    • endorser_statesarray of string

      Endorsers’ home states (USPS codes), or "national".

    • statesarray of string

      States the contests are voted in.

    • electionsarray of string

      Election slugs.

    • contest_kindsarray of string

      Contest kinds.

      One of candidate, measure, retention.
    • levelsarray of string

      District levels.

      One of federal, state, county, city, school, special.
    • typesarray of string

      Stream only: kinds of change.

      One of created, updated, deleted.

Returns

200 Saved.

  • dataSubscription
    5 fields
    • idinteger

      Subscription id.

    • namestring

      Name, unique in your account.

    • filterFilter

      Which endorsements: fields combine with AND, values within a field with OR, and a missing field matches everything. Each field takes at most 500 values.

      8 fields
      • categoriesarray of string

        Endorser category slugs (GET /v1/endorser-categories).

      • endorsersarray of string

        Endorser slugs.

      • endorser_statesarray of string

        Endorsers’ home states (USPS codes), or "national".

      • statesarray of string

        States the contests are voted in.

      • electionsarray of string

        Election slugs.

      • contest_kindsarray of string

        Contest kinds.

        One of candidate, measure, retention.
      • levelsarray of string

        District levels.

        One of federal, state, county, city, school, special.
      • typesarray of string

        Stream only: kinds of change.

        One of created, updated, deleted.
    • created_atstring (date-time)

      Created.

    • updated_atstring (date-time)

      Last changed.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 404 Nothing has that id or slug.
  • 409 A subscription with that name already exists.
  • 429 Over a rate limit. Wait Retry-After seconds.
PUT /v1/subscriptions/{id}
curl -X PUT "https://api.ballotdata.net/v1/subscriptions/7" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"CA labor","filter":{"categories":["labor"],"states":["CA","NV"]}}'
Response200application/json
{
  "data": {
    "id": 7,
    "name": "CA labor",
    "filter": {
      "categories": ["labor"],
      "states": ["CA", "NV"]
    },
    "created_at": "2026-10-15T17:20:04.112Z",
    "updated_at": "2026-10-21T09:12:40.006Z"
  }
}

Delete a subscription

DELETE /v1/subscriptions/{id}

Delete a subscription.

Path parameters

  • idintegerrequired

    Subscription id.

    Example 7

Returns

204 Deleted. No body.

Errors

  • 400 A parameter is missing or not valid.
  • 401 No API key, or one that isn’t valid, was revoked or expired.
  • 403 The key can’t be used for this: a missing scope, an IP allowlist, an account not yet approved, or data the account hasn’t bought.
  • 404 Nothing has that id or slug.
  • 429 Over a rate limit. Wait Retry-After seconds.
DELETE /v1/subscriptions/{id}
curl -X DELETE "https://api.ballotdata.net/v1/subscriptions/7" \
  -H "Authorization: Bearer $BALLOTDATA_API_KEY"
Response204
(no body)