Keys, limits and errors

Keys

Your API account opens when you buy at ballotdata.ai. Sign in, create a key in the console and send it on every request:

curl -H "Authorization: Bearer ebk_…" "https://api.ballotdata.ai/v1/endorsements?states=CA&categories=labor"

The client libraries send it for you, from the BALLOTDATA_API_KEY environment variable.

Keep keys on servers, never in a browser or app. A key can be limited to some IP addresses and to some scopes: data:read (the data endpoints), stream:read (the stream) and subscriptions:write.

What a key can read

Scopes say what kind of request a key may make; what you bought says which part of the country it sees. Buy API access for a state or every state at ballotdata.ai. The purchase opens an API account for the email address you buy with, or is added to the account you already have with that address. Once the address is confirmed, every key on the account reads what was bought, until the purchase ends. Licenses last through December 31, 2027.

Lists come back limited to it. Asking for a state you didn’t buy (states=NY) or a contest outside it is refused with 403 outside_purchase; an account with nothing bought, or whose purchase has ended, gets 403 no_access. The stream and /v1/events carry only changes in the states and contests bought, for the endorser types the delivery chose. /v1/states, /v1/endorser-categories and /v1/coverage are open to every approved account. The console’s Usage page lists what your keys can read.

Rate limits

Each account has a per-minute limit and, on most plans, a daily cap (UTC days), shared by all its keys. Every response says where you are: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset (seconds), and X-Daily-Limit / X-Daily-Remaining. Over the limit you get 429 with Retry-After. Opening a stream counts as one request; the events on it don’t count. Every request needs a working key: there is no access without one.

PlanRequests a minuteRequests a day (UTC)Open streams
Standard (every purchase)600200,0005
Enterprise (by arrangement)3,000No daily cap25

Need more? Write to us and we can raise your account’s limits. The MCP server uses your account’s key, so an assistant’s requests count toward the same limits.

Errors

{ "error": { "code": "rate_limit_exceeded", "message": "Your plan allows 600 requests a minute.", "request_id": "…" } }

Codes include missing_api_key, invalid_api_key, revoked_api_key, account_pending, insufficient_scope, no_access, outside_purchase, invalid_parameter, not_found, rate_limit_exceeded, daily_limit_exceeded, too_many_streams, cursor_expired and internal_error. Quote the request_id when you write to us.

Pages

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

Keys, limits and errors · BallotData API