/Endpoints

Live Turnout

Use Case

Use this endpoint to track voter turnout on polling day in (close to) real time. It is ideal for powering a notification service (for the latest headline number), visualising turnout by seat, or charting turnout over the course of the day. Every figure is split into overall, early and ordinary turnout.

There are two endpoints:

  • /vto/latest: the newest snapshot for the state, every Parliament seat and every DUN seat. Poll this for a live view.
  • /vto: one level (Parliament, DUN or polling district) for one 5-minute slot. Use this to build a time series or to go down to polling district (DM) level.

Data Note

On 14 November 2026, polling day for the 16th Melaka state election, the Election Commission (SPR) published real-time voter turnout via dashboard.spr.gov.my, made possible by the introduction of digital voter registration at polling centres. We launched this endpoint the same day, and will maintain it for as long as SPR continues to publish the data.

Prerequisite: API Key

All requests to this API require a Bearer token. Requests without a token (or with an invalid one) will return a 401 Unauthorized error. Paste yours below—every code snippet and the live tester at the bottom of this page will be pre-filled and ready to run.

Step 1: Get latest snapshot

GEThttps://api.electiondata.my/v1/vto/latest
ParameterTypeRequiredDescription
electionstringYesElection identifier in the form <state>-<ge|se><NN>, using the 3-letter state code, e.g. 'mlk-se16'. Only 'mlk-se16' is available for now.

Responses are cached for 30 seconds (other endpoints cache for 300 seconds), and a new snapshot arrives every 5 minutes, so polling once a minute is plenty.

A successful 200 OK response returns a JSON object with these keys:

FieldTypeDescription
timestampstringTime of the snapshot in the Election Commission (SPR) feed, in Malaysia time (MYT), e.g. '2026-11-14 08:25:52'.
slotstringThe 5-minute slot this snapshot belongs to, as HHMM in MYT (the timestamp rounded down), e.g. '0825'. Pass it as time to /vto to fetch other levels for the same moment.
stateobjectA turnout unit (see below) for the whole state.
parlimenobjectOne turnout unit per Parliament seat, keyed by seat name, e.g. 'P.134 Masjid Tanah'.
dunobjectOne turnout unit per DUN seat, keyed by seat name, e.g. 'N.01 Kuala Linggi'.

Polling district (DM) figures are not included here, to keep the response small. Use Step 2 for those.


Turnout unit: every state, seat and polling district has the same fields. The abs fields are votes cast, the vto fields are turnout percentages, and the electorate fields are the denominators those percentages are based on.

FieldTypeDescription
overall_absintegerTotal votes cast: early, ordinary and postal.
overall_vtofloatOverall turnout as a percentage to 2 decimal places (null if the electorate is 0).
overall_electorateintegerAll registered voters, from the final voter roll. Includes postal voters, so it is slightly larger than awal_electorate + biasa_electorate.
awal_absintegerEarly votes cast (awal = police, army and others who voted before polling day).
awal_vtofloatEarly-voter turnout as a percentage (null if there are no early voters).
awal_electorateintegerRegistered early voters. 0 for DUNs (and their pseudo-districts) with no early voters; null for regular polling districts.
biasa_absintegerOrdinary votes cast on polling day (biasa = ordinary).
biasa_vtofloatOrdinary-voter turnout as a percentage (null if there are no ordinary voters).
biasa_electorateintegerRegistered ordinary voters (null for the early-voting pseudo-districts).

Example unit for N.25 Rim at 08:25:

{ "overall_abs": 712, "overall_vto": 4.01, "overall_electorate": 17742, "awal_abs": 0, "awal_vto": null, "awal_electorate": 0, "biasa_abs": 712, "biasa_vto": 4.06, "biasa_electorate": 17557 }

Step 2: Get a time slot

GEThttps://api.electiondata.my/v1/vto
ParameterTypeRequiredDescription
electionstringYesElection identifier, e.g. 'mlk-se16'. Same format as in Step 1.
levelstringYesOne of 'parlimen', 'dun' or 'dm' (polling district).
timestringYesThe 5-minute slot as HHMM in Malaysia time, from '0800' until '1800' (18:00 MYT, when polls close), e.g. '0805' or '1430'.

Slot 0800 is the pre-polling baseline: it contains early votes only, with every ordinary vote still at 0. Live slots start at 0805. A slot that hasn’t happened yet returns 404 Not Found. A missing parameter, a level that isn’t one of the three options, or a time that isn’t HHMM in 5-minute steps returns 400 Bad Request.

A successful 200 OK response returns a JSON object with one turnout unit (same fields as in Step 1) per unit at the requested level, keyed by name:

FieldTypeDescription
parlimenstringParliament seat name, e.g. 'P.136 Tangga Batu'. Melaka has 6.
dunstringDUN seat name, e.g. 'N.11 Sungai Udang'. Melaka has 28.
dmstringPolling district as Parliament/DUN/DM number plus name, e.g. '136/11/01 Bukit Terendak'. Melaka returns 235 entries: 211 polling districts plus 24 '/00 Undi Awal' early-voting pseudo-districts.

Try It Out

Use the Latest tab for the newest snapshot, or switch to By Slot to pick a level and time.