The Voter Poll is a survey of verified voters conducted by SSRS, Inc. for The Associated Press and major news organizations to tell the story behind voters' decisions. For more information, see Quick Start Guide to The Voter Poll.
The Voter Poll collection of API methods provides access to precomputed survey cross-tabulation ("crosstab" / "xtab") data in those elections where the survey takes place. Unlike a live query API, Voter Poll data is distributed as static files: your client application lists the available races for an event and then downloads the crosstab file for a specific race. Availability of survey results for a race is time-gated by its state's poll schedule.
Two Voter Poll API methods are available:
Race List. Lists available races for an event:
GET /v3/voterpoll/{electionDate}
File Download. Redirects to the presigned S3 URL to download the crosstab file for one race:
GET /v3/voterpoll/{electionDate}/download
Both methods return responses only in JSON format. If the format parameter is specified in the request, it is ignored.
Requests are authenticated with your AP Elections API key.
Access to The Voter Poll is controlled by an entitlement on your key. A key without the entitlement receives the error message 'Not entitled to this API.'
The entitlement provides access to one of the following:
All states
A list of specific states (by postal code)
Requesting a state you are not entitled to access returns the error message 'Not entitled to state: {state}.'
Lists races for an event. Returns one entry per available race, each with a contentLink to download the crosstab file for that race.
|
Header |
Description |
Example |
|
x-api-key |
Specifies the API key to authorize the request. |
apikey |
|
Accept-Encoding |
Compresses the response to the gzip format. |
gzip |
|
Method |
Request URI |
|
GET |
https://api.ap.org/{version}/voterpoll/{electionDate}?[{OptionalParameters}] |
|
Parameter |
Description |
Example |
|
version |
The API version. Currently, the only valid value is v3. |
v3 |
|
electionDate |
Date of the election in the YYYY-MM-DD format. |
2026-11-03 |
|
Parameter |
Description |
Example |
|
statePostal |
Limits the race list to a single state. A valid value is a two-character state postal code. |
AK |
|
officeID |
Limits the race list to a single office. A valid value is an office type ID; for example: S (U.S. Senate), H (U.S. House), G (Governor). |
S |
|
resultsType |
Indicates whether to return live or test data. Possible values are:
|
t |
|
Request |
Returns |
|
electionDate only |
Every office in every entitled state |
|
electionDate + statePostal |
Every office in the specified state |
|
electionDate + officeID |
The specified office across every entitled state |
|
electionDate + statePostal + officeID |
The specified single race |
Note: If your API key is limited to specific states, but the statePostal parameter is not specified in the request, the response includes only the states to which you are entitled.
GET /v3/voterpoll/2026-11-03?statepostal=AK&officeID=G
Headers:
x-api-key: <your_API_key>
Content-Type: application/json
{
"electionDate": "20261103",
"records": [
{
"statePostal": "AK",
"officeID": "G",
"weightingId": 20260909193108,
"contentLink": "https://<host>/v3/voterpoll/20261103/download?statepostal=AK&officeID=G"
}
]
}
|
Field |
Description |
|
electionDate |
The requested election date. |
|
records |
Contains one entry per available race. Empty when nothing is available (or entitled) for the request. |
|
statePostal |
Two-letter state postal code. |
|
officeID |
Office type ID for the race. |
|
weightingId |
Identifier of the latest data weighting for that race and version. Increases as new data is published. Use weightingID to detect updates: when the value increases for a race you have already retrieved, a newer crosstab file is available. |
|
contentLink |
A link to download the crosstab file for that race. |
Returns an HTTP redirect to a time-limited (presigned) URL for the crosstab file of a single race. Follow the redirect to retrieve the JSON payload.
|
Method |
Request URI |
|
GET |
https://api.ap.org/{version}/voterpoll/{electionDate}/download?statepostal={postalCode}&officeID={officeTypeID}[&resultsType={l|t}] |
|
Parameter |
Description |
Example |
|
version |
The API version. Currently, the only valid value is v3. |
v3 |
|
electionDate |
Date of the election in the YYYY-MM-DD format. |
2026-11-03 |
|
statePostal |
Specifies the state for the requested crosstab file. A valid value is a two-character state postal code. |
AK |
|
officeID |
Specifies the office for the requested crosstab file. A valid value is an office type ID; for example: S (U.S. Senate), H (U.S. House), G (Governor). |
G |
|
Parameter |
Description |
Example |
|
resultsType |
Indicates whether to return live data (resultsType=l) or test data (resultsType=t). The value must match the resultsType value from the Race List request; the correct value is already included in the contentLink in the Race List response. |
t |
GET /v3/voterpoll/2026-11-03/download?statepostal=AK&officeID=G
Headers:
x-api-key: <your_API_key>
Returns a standard 302 redirect with the presigned S3 URL in the Location header. Following that URL returns the crosstab JSON file for the race.
The presigned URL expires after one hour. Request a fresh download link when it expires rather than caching the presigned URL.
Voter Poll races become available on a per-state schedule tied to that state's poll hours. Each state resolves, at request time, to one of the following:
|
State Timing Status |
Race List Behavior |
Download Behavior |
|
Before the state's share time |
Race is omitted from the list |
404 No data available |
|
Share window open (before poll close) |
Listed with a preclose file |
Serves the preclose version |
|
After poll close |
Listed with a postclose file |
Serves the postclose version |
The two versions differ in what data is exposed:
preclose is released while the polls are still open. Candidate results are withheld: candidate rosters, candidate-level crosstab cells, and subgroup sample sizes are removed. Only marginal/total values remain.
postclose is released after the polls close. Candidate rosters are removed from the roster view, but crosstab cells and sample sizes are retained (fuller data).
The listing and download endpoints are always consistent: a race that appears in the listing can be downloaded, and the file you download is the latest available version for that state's current timing status. Within the resolved version, the API always serves the file with the highest weightingId.
The file is a complete xtab object: a top-level envelope with an array of Documents (one per office key / subset), plus filters and survey_questions metadata. Use weightingID to detect new releases: when it changes, fresh data is available.
The static files served by this API are version-trimmed cuts of this complete object. preclose and postclose strip some of the fields documented below (candidate rosters, candidate cells, raw sample sizes). See Fields Omitted from Each FIle Version. Fields marked (upstream) appear in the full upstream object but may be absent from the trimmed distribution file.
{
"status": "ok",
"eventID": "20261103",
"isEmbargo": false,
"userEmbargoAllowed": false,
"Documents": [
{
"eDate": 20261103,
"postingDateTime": "2026-08-17T14:56:53",
"snapshotDateTime": "2026-08-17T14:56:53",
"transSrc": "SSRS",
"seq": 20260817145653,
"weightingID": 20260817145653,
"key": {
"eDate": 20261103, "st": 47, "eType": "G",
"jType": "SW", "jCde": 0, "ofc": "S", "sub": 0
},
"st": 47,
"stateAbbv": "VA",
"stateLongName": "Virginia",
"jType": "SW",
"jCde": 0,
"eType": "G",
"ofc": "S",
"office_alias": null,
"APraceID": 47917,
"sub": 0,
"subShortName": "NOFLTR",
"resp": 1090,
"moe": 4.9,
"xpCall": 3,
"xpStage": 6,
"staticXtabValidation": [],
"cand": [
{
"cId": 20079320, "row": 1, "cPct": 58, "_cPct_raw": 57.99198180729002,
"label": "Democrat", "firstName": "Ghost", "lastName": "Democrat",
"name": "Ghost Democrat", "abbrev4": "Demo", "party": "Democratic",
"partyID": "DEM", "major_party_code_3": "DEM", "ap_cid": "178506",
"candidateOrder": 1
},
{
"cId": 20079321, "row": 2, "cPct": 41, "_cPct_raw": 41.0066320620273,
"label": "Republican", "firstName": "Ghost", "lastName": "Republican",
"name": "Ghost Republican", "abbrev4": "Repu", "party": "Republican",
"partyID": "REP", "major_party_code_3": "REP", "ap_cid": "178507",
"candidateOrder": 2
}
],
"q": [
{
"qType": 1,
"qSeq": 1,
"sampleSize": 1090,
"MxId": 11001,
"mxRow": [
{
"row_value": 1,
"row_short_name": "GENDER",
"row_label": "Male",
"row_n": 512,
"row_w_n": 529,
"total_n": 1090,
"total_w_n": 1149,
"marginal_percent": 46,
"suppress": false,
"cell": [
{ "cId": 0, "hPct": 46, "vPct": 46 },
{
"cId": 20079320, "name": "Ghost Democrat", "ap_cid": "178506",
"hPct": 53, "vPct": 42, "_hPct_raw": 52.647455591524746
},
{
"cId": 20079321, "name": "Ghost Republican", "ap_cid": "178507",
"hPct": 46, "vPct": 52, "_hPct_raw": 46.19693522581203
}
]
}
],
"cand_col": "SENVA26",
"cand": [ "...per-question candidate topline, same shape as top-level cand..." ],
"sampleSizeWeighted": 1149.4,
"is_demographic": "Y",
"questionnaire_source": "PRE",
"weight_column_used": "weight_official_pre"
}
],
"pastTrendRace": null,
"artifactS3Key": "v1/xtabs/static-xtabs-artifacts/eventid=20261103/st=47/etype=G/jtype=SW/jcde=0/ofc=S/wave=3/stage=6/20260817145653.json"
}
],
"filters": [
{
"sub": 5, "order": 1, "category": "Demo",
"subLongName": "White Voters", "subShortName": "WHT", "filter_string": "RACE=1"
}
],
"survey_questions": [
{
"mxId": 100272,
"shortMxLabel": "",
"fullMxLabel": "In today's election for U.S. Senate, did you just vote for:",
"isDemograph": "N",
"isDerivative": false,
"qSeq": 0,
"numRows": 5,
"mxRows": [
{ "rowLabel": "WARNER", "rowText": "Warner" }
]
}
],
"ipf_targets": {},
"pagination": {
"start_record": 1, "end_record": 1, "total_records": 1,
"records_per_page": 1, "records_this_page": 1,
"current_page": 1, "total_pages": 1
}
}
|
Field |
Description |
|
status |
Request status; for example, ok. |
|
eventID |
The event ID (election date). |
|
Documents |
Contains one or more crosstab documents for the race, one document per office key / subset. |
|
eDate |
Election date in the YYYYMMDD format; for example, 20251104. |
|
postingDateTime |
UTC timestamp (YYYY-MM-DDTHH:MM:SS) indicating when this document was published. Updates whenever the document is published, including when it is republished with the same weightingID. When a snapshot is re-keyed under a new weightingID, the publish time is either retained or updated to the re-key time, at the operator's discretion. |
|
snapshotDateTime |
UTC timestamp (YYYY-MM-DDTHH:MM:SS) indicating when the respondent snapshot used for this document was taken, normally at the same instant represented by weightingID. It remains unchanged when an existing snapshot is re-keyed under a new weightingID (Force New Weighting ID / Update Wave / Stage), so it can be earlier than the time represented by the weightingID. Never changes when the document is republished. |
|
weightingID |
Integer timestamp identifying the respondent snapshot (weighting wave / stage). Treat the highest weightingID as the latest. Republishing the same snapshot (for example, with revised weights) preserves the same weightingID, so also check postingDateTime or published_ts for a more recent publication. |
|
key |
Unique office key. Standard key: eDate, st, etype, jtype, jcde, ofc. |
|
eDate |
Election date in the YYYYMMDD format; for example, 20251104. |
|
st |
State ID; for example, 31. Corresponds to AP's stateID. |
|
eType |
Election type; for example, G (General). This matches AP’s raceTypeID except in the Florida and Ohio Senate vacancies where the AP has a raceTypeID of "W," and SSRS has eType "G." |
|
jType |
Jurisdiction type; for example, SW (statewide). |
|
jCode |
Seat number (such as a district number), from 0 to 999. Not applicable to statewide races, for which the value is 0. |
|
ofc |
Office type ID; for example, G (Governor). Corresponds to AP's officeID. |
|
st |
State ID. Corresponds to AP's stateID. |
|
stateAbbv |
State postal code. |
|
stateLongName |
Full state name. |
|
jType |
Jurisdiction type; for example, SW (statewide). |
|
jCode |
Seat number (such as a district number), from 0 to 999. Not applicable to statewide races, for which it has the value of 0. |
|
eType |
Election type; for example, G (General). |
|
ofc |
Office type ID. Corresponds to AP's officeID. |
|
office_alias |
Display alias for the office in this xtab (for example, "Senate"). |
|
APraceID |
AP-designated race identifier (raceID) from the Elections API method; for example, 47225. Use it to join this race to AP results feeds. Null until AP stages the election and the ID is synchronized. |
|
sub |
Subset ID (for example, 5). |
|
resp |
Number of respondents. |
|
moe |
Margin of error at the 95% confidence level for the full sample (the NOFLTR document), expressed in percentage points and rounded to one decimal place; for example, 4.9. It reflects the effective sample size of respondents who provided a valid answer to the how-voted question for this office (Omit and No Vote excluded) under the crosstab's weights. Null for filtered subsets and embargoed artifacts. |
|
xpStage |
Survey weighting stage; for example, 10. |
|
sampleSizeWeighted |
Weighted sample size. |
|
cand |
Top-level candidate vote shares (the topline); one object per candidate. The fields for each object are documented in the indented rows below. The same structure is repeated for each question under q[].cand. |
|
cId |
Candidate ID. Does not match AP candidate IDs: use ap_cid to join to AP results. A cId value of 0 identifies the Total column in crosstab cells, not a candidate. |
|
row |
Row ID. |
|
cPct |
Estimated percentage. |
|
cPct_raw |
Raw topline vote-share estimate without rounding; cPct is the rounded value . |
|
label |
Short candidate label. |
|
firstName |
Candidate's first name. |
|
lastName |
Candidate's last name. |
|
name |
Candidate's full name. |
|
abbrev4 |
Four-letter candidate abbreviation. |
|
party |
Party name; for example, Democratic. |
|
partyID |
Party code; for example, DEM. |
|
major_party_code_3 |
Three-letter party code. |
|
ap_cid |
AP candidate ID (PolID), used to join to AP results. Null or empty when there is no matching AP candidate ID in the AP system. |
|
candidateOrder |
Candidate's display order. |
|
q |
Question definitions. |
|
qType |
Question type. Identifies the version of the questionnaire used across different jurisdictional levels, such as a national or state-level questionnaire. |
|
qSeq |
Question sequence. Can be used to order static crosstabs. |
|
sampleSize |
Unweighted sample size for the question. |
|
mxId |
Question matrix ID; for example, 1. |
|
mxRow |
Matrix of crosstab rows. |
|
row_value |
Row code (for example, "1", "2") |
|
row_short_name |
Short question label repeated on each row (for example, "SEX") |
|
row_label |
Composite label in the format "<SHORT>=<row_value>" (for example, "SEX=1") |
|
row_n |
Raw respondent count for the row. |
|
row_w_n |
Weighted respondent count for the row. |
|
total_n |
Total raw count for the question. |
|
total_w_n |
Total weighted count for the question. |
|
marginal_percent |
The percentage of the total sample in this row. |
|
suppress |
True if the cell is suppressed. If the minimum number of respondents for this question is not met, all row values in cell will be suppressed and set to empty. |
|
cell |
Cell-level vote shares by candidate. |
|
cId |
Candidate ID. Does NOT match AP candidate IDs; use ap_cid to join AP results. cId 0 identifies the Total column in crosstab cells, not a candidate. |
|
ap_cid |
AP Candidate ID (PolID), for joining AP results. Null or empty when there is no matching AP Candidate ID in the AP system. |
|
hPct |
Horizontal (row) percentage, which describes the percentage of a group voting for each candidate. |
|
vPct |
Vertical (column) percentage, which describes the percentage of a candidate's voters falling into a group. |
|
_hPct_raw |
Unrounded horizontal (row) percentage for candidate cells; hPct is the rounded value. |
|
{filter}.{source} |
Current percentage for this row within the filter/source cell. The key is {filter_shortname}.{source} (for example, BLK.VoteCast). Sources: NEP (exit poll), VoteCast (AP VoteCast). |
|
{filter}.{source}.pChg |
Percentage-point change in the filter/source cell relative to the past Base Race (for example, past 51.6% → current 50.0% = -1.6 percentage points). |
|
cand_col |
Office short name for this xtab (for example, "GOV"), used to identify the column variable. |
|
sampleSizeWeighted |
Weighted sample size. |
|
is_demographic |
Indicates whether the question is demographic: Y or N. |
|
questionnaire_source |
Identifies the questionnaire from which this question is sourced: the pre-election questionnaire or the full questionnaire (for example, "FULL"). |
|
weight_column_used |
Name of the weight column applied to this row's percentages. Varies depending on the weighting scheme applied by the state and whether the question was asked only of the pre-election sample or of the full sample. |
|
pastTrendRace |
The past race on which this document's trend values are based (for example, "GOV2021 (D)"). |
|
filters |
Subset filter definitions available for this xtab; one object per subset. |
|
sub |
Subset ID (for example, 5). |
|
order |
Display order of the subset within the filter list. |
|
category |
Optional grouping label for the subset; empty when unused. |
|
subLongName |
Full subset name (for example, "Whites"). |
|
filter_string |
Logical condition (for example, "RACE=1"). |
|
survey_questions |
Survey question metadata. |
|
mxId |
Question matrix ID; for example, 1. |
|
shortMxLabel |
Short question label; for example, AGE. |
|
fullMxLabel |
Full matrix label/question text; for example, 60 or over. |
|
isDemograph |
Y if the question is demographic. |
|
numRows |
Number of answer rows. |
|
mxRows |
Matrix of answer rows. |
|
rowLabel |
Short code (for example, "WHITE"). |
|
rowText |
Answer text (for example, "White"). |
|
isStaticXtab |
Y if static xtabs apply. |
|
isDerivative |
Indicates whether this question is derived from other questions rather than asked directly. Such questions are often called "Add Variables". |
The file contains the survey crosstab for the race. This is an example of its top-level structure:
{
"isEmbargo": false,
"Documents": [
{
"weightingID": 20260909193108,
"resp": 2874,
"sampleSizeWeighted": 2998.7,
"cand": [
{ "cId": 101, "cPct": 45, "name": "A" },
{ "cId": 102, "cPct": 25, "name": "B" }
],
"q": [
{
"sampleSize": 2874,
"mxRow": [
{
"row_label": "Male",
"row_n": 1266,
"total_n": 2874,
"cell": [
{ "cId": 0, "hPct": 46, "vPct": 46 },
{ "cId": 101, "hPct": 43, "vPct": 44 },
{ "cId": 102, "hPct": 30, "vPct": 25 }
]
}
]
}
]
}
]
}
|
Structure |
preclose |
postclose |
|
Candidate roster (cand) |
Removed |
Removed from the roster view |
|
Candidate crosstab cells (cell where cId != 0) |
Removed (only cId: 0 totals kept) |
Kept |
|
Subgroup sample sizes (row_n, row_w_n) |
Removed |
Kept |
|
Row totals / marginals (cId: 0 cell) |
Kept |
Kept |
Errors are returned with the appropriate HTTP status and a message.
|
Status |
Message |
Description |
|
400 |
Required path parameter 'election_date' is missing |
The electionDate parameter value is missing. |
|
400 |
Invalid resultsType value: {value}. Allowed: live, l, test, t. |
The resultsType parameter value is not l, live, t or test. |
|
400 |
Invalid statepostal value: {value} |
The statepostal parameter value is not a valid postal code. |
|
400 |
Both 'statepostal' and 'officeID' query params are required |
The statepostal or officeID parameter is missing from the File Download request URL |
|
400 |
Not entitled to state: {state} |
The API key does not provide access to the requested state. |
|
405 |
Not entitled to this API |
API key lacks the VP entitlement. |
|
405 |
Method Not Allowed! |
A method other than GET is used. |
|
404 |
No data available |
The requested race is not yet available, is withheld or is suppressed. |
|
404 |
No file for {state}/{office} on {folder} |
No file is available for the requested race. |
|
500 |
Error retrieving VoterPoll xtab listing |
S3 listing, resolution or presigning failure. |
Use the Race List method to receive a list of races for an event date (optionally filtered by state and/or office).
For each race in records, note the weightingId and contentLink.
Follow the contentLink in the Race List response or construct the File Download request URL to get a redirect to a presigned file URL.
Follow the redirect and parse the crosstab JSON.
Poll the listing periodically; re-download a race when its weightingId increases. Races appear/upgrade automatically as each state's poll timing advances (preclose -> postclose).