1. Documentation
  2. Data Types

Data Types

We don't want there to be any surprises when you're using our API, so we have defined the specific data formats you'll see across our API below. In general, you will be linked back here from elsewhere, so feel free to skip right to reading the full documentation for the API Endpoints.


Response objects contain a list of data results, as well as any extra aggregated data and some meta-data about the request. In general, this will be the response format for any list API endpoints (e.g. /elections), where the data list are the API request results. Also, if you request that some additional sub-queries be included with your results (e.g. include=contests), those includes will be contained within another Response object.

{
    "type": "response",
    "data": [...],
    "next": null,
    "extra": {},
    "timestamp": "2018-01-01T00:00:00+00:00",
    "url": "https://api.ballotapi.org/...",
}
Attribute Format Description Example
ObjectType This object's data type. Will always be "response". "response"
List(Election | Contest | Precinct) The actual response content for the API request. Will be a list of whatever particular endpoint object is being queried. [{"type": "election", ...}, ...]
URL or null If there are more data objects in the results, this will be a url to the next page of results. If there are no more results, this will be null. "https://api.ballotapi.org/..."
ExtraObject If an extra parameter was included in the api request, this object will contain the results of that extra parameter. If no extra parameter was given, this will be an empty object (i.e. {}). {"merge_geos": {"type": "MultiPolygon", ...}}
DateTime The datetime at which the results were generated. Since results are often cached, this timestamp won't necessarily be close to the current time, but we do invalidate caches when data changes, so you will always be receiving the latest available results. "2018-01-23T04:55:12+00:00"
URL The API request that was performed to produce the results. If you included extra request parameters that we didn't recognize, they will be ignored, so this is helpful to compare against to see if you got the parameters right for your API request. "https://api.ballotapi.org/..."
We may add additional attributes in the future, so be able to unknown attributes.

These are responses that are returned when something you requested raised an error. The most common case you will see these is when the query parameters you set in your request are malformed and you get back a 400 HTTP response code.

{
    "error": "invalid_param",
    "message": "You need to specify a timezone for each datetime in your 'dates' parameter.",
    "docs": "https://ballotapi.org/docs/data-types#datetime-range"
}
Attribute Format Description Example
String The error type raised. Usually something like invalid_param, but could be any string. "missing_param"
String A human-readable error message describing what caused the error. We try to make our error messages clear so you know exactly what went wrong. Please feel free to reach out to us if you think an error message is confusing! "Your 'coords' parameter doesn't look like coordinates (e.g. '12.2928,-84.7573')"
URL or null A link to the documentation where you can find more information. We try to include links to docs for each error, but sometimes we haven't set that link yet, so this attribute may be null. "https://ballotapi.org/docs/api/elections/list#include"

The Extra object is an object in Response objects that contain attributes requested via extra parameters. The data in this object are usually aggregated from the results. For example, if you specify extra=merge_geos in a request, the Extra object will contain the merge_geos attribute with the merged geography of the results in the Response data attribute.

{
    "merge_geos", {
        "type": "MultiPolygon",
        ...
    },
    ...
}
Attribute Format Description Example
Extra object attributes can be any value that is defined in the extra request parameters for the various API Endpoints.

For complex data objects returned by the API, there is a defined object type value that lets you know what kind of object it is.

Value Format Description
String Will be the object type for Response objects.
String Will be the object type for Election objects.
String Will be the object type for Precinct objects.
String Will be the object type for Contest objects.
String Will be the object type for Choice objects (these are included in Contest objects).
We may add additional object types in the future, so be able to unknown object type values.

These are Open Civic Data Identifiers (OCD-ID), which is an open standard for giving unique identifiers for civic information, such as localities, elected officials, or jurisdictions. When available, we include the OCD-ID in our API so you can map our data to other civic database that also use OCD-ID.

"ocd-jurisdiction/country:us/state:ex/place:example/legislature"

These are arbitrary strings of text. In API responses, they are encoded in UTF-8 . In URL parameters, they are percent encoded .

"ὁ ἄνθρωπος φύσει πολιτικὸν ζῷον —Aristotle"
"Man%20is%20by%20nature%20a%20political%20animal%20%E2%80%94Aristotle"

This is a URL that points to somewhere on the API. We do not link to external resources.

"https://api.ballotapi.org/v1/elections?dates=now,future"

This is a ISO-8601 date (e.g. YYYY-MM-DD). There is no timezone associated with dates, so if timezone is important, use DateTime.

"2018-01-23"

This is a ISO-8601 combined date and time with timezone (e.g. YYYY-MM-DDTHH:MM:SS+00:00). All API response datetimes have a timezone. If you provide a datetime in a request parameter, be sure to specify the timezone offset (so we can know how to compare it to other datetimes).

"2018-01-23T22:55:12-08:00"

This is a timespan between two DateTimes or special values, separated by a comma (,). There are also special formats that allow you to easily build dynamic ranges you can re-use without having to build new datetimes.

Formats accepted:

  • YYYY-MM-DDTHH:MM:SS+00:00 - ISO 8601 DateTime
  • now - the current time
  • future - anytime after the current time
  • past - anytime before the current time
  • +{N}d - a number of days (24 hours) after the current time (e.g. +30d)
  • -{N}d - a number of days (24 hours) before the current time (e.g. -365d)
Valid:
"2018-01-01T00:00:00-08:00,2019-01-01T00:00:00-08:00" (all of 2018 in PST Timezone)
"now,future"                    (everything going forward)
"past,now"                      (everything prior to now)
"-365d,+30d"                    (everything in the past year and in the next 30 days)
"2016-11-08T00:00:00-05:00,now" (everything since Nov 8, 2016 EST up to now)

Invalid:
"2018-01-01,2019-01-01"         (dates without timezones aren't allowed)
"365d,now"                      (day values need to have a "+" or "-")
"now,"                          (need two values in the range, if you need open ended, use "past" and "future")

These are a single point or area of geographic coordinates . Single coordinates are a comma separated latitude, longitude pair (e.g. "{lat},{lon}"). Areas are semicolon separated single coordinates (e.g. "{lat},{lon};{lat},{lon};..."), where the area is the polygon created by the list of single coords (the first and last coords are assumed to connect, so you don't have to copy the first the coord at the end).

(Ferry Building, San Francisco, CA)
"37.795508,-122.393478"

(Treasure Island, CA)
"37.832225,-122.373404;37.830429,-122.377653;37.826768,-122.379198;37.815751,-122.371687;37.818632,-122.364521;37.820565,-122.363705;37.819785,-122.360444;37.820124,-122.360444;37.820870,-122.363491;37.822565,-122.362890;37.831073,-122.368597"

If you don't have coordinates, but instead have addresses, you will need to use a geocoding service to convert the addresses into coordinates. Geocoding is not built into BallotAPI by default because it is quite complex, and we don't want to have to spend all of our time maintaining a geocoding service when our focus is ballot data. Also, there are already many services that do geocoding quite well, so we don't feel the need to re-invent the wheel or try to figure out how to include a geocoding service as part of a public-domain project.

Here are some free geocoding resources:

Here are some paid geocoding services:


These are GeoJSON : objects. You will see mostly Polygon and Multipolygon objects that outline district or precinct boundaries.

Treasure Island, CA:

{
    "type": "Polygon",
    "coordinates": [
        [
            [-122.37340450,37.83222583],
            [-122.37765312,37.83042938],
            [-122.37919807,37.82676854],
            [-122.37168788,37.81575104],
            [-122.36452102,37.81863270],
            [-122.36370563,37.82056504],
            [-122.36044406,37.81978533],
            [-122.36044406,37.82012433],
            [-122.36349105,37.82087014],
            [-122.36289024,37.82256513],
            [-122.36859798,37.83107340],
            [-122.37340450,37.83222583]
        ]
    ]
}

Did we miss a data type? Please open an issue or pull request