Zero Motorcycles VIN decoder
What each of the 17 characters on a Zero Motorcycles frame plate means, with the full lookup tables published as plain HTML — scoped by model year, with the source of every code named — and an honest account of the fields the number cannot tell you.
TL;DR
- Zero uses three identifiers, not one. 538 is the World Manufacturer Identifier registered to ZERO MOTORCYCLES, INC. of Scotts Valley, California; PAG is registered to INTEGRATED MICRO-ELECTRONICS, INC. with a plant in Binan, Laguna, Philippines, and appears on Gen3 FST-platform bikes; A4Z is a Product Identification Number carrying the off-road X-line, which NHTSA flags as not certified to the federal safety standards for motor vehicles.
- The layout is the standard one mandated by 49 CFR 565: 1-3 WMI, 4-8 descriptor, 9 check digit, 10 model year, 11 plant, 12-17 the manufacturer sequence. Zero puts its model designator in position 12 and a five-digit serial in 13-17 — until model year 2024, when the designator disappears from its own diagrams and position 12 becomes serial.
- Position 10 uses 23 codes here, covering 2008 to 2030. Because I, O and Q are not VIN characters, A to J is nine letters, not ten: A is 2010 and J is 2018.
- Every other table on this page is scoped by model year, because Zero reuses its codes: Z6 is 21 kW through 2018 and 22 kW from 2019, and the community decoder records M0 as an MX in 2011 and a 9.8 kWh S in 2016. Each entry is now bounded at the years its sources cover, so a code asked about outside them returns nothing rather than the wrong motorcycle.
- All 23 distinct VINs in this project’s log corpus carry a check digit that satisfies the 49 CFR 565.15(c) algorithm, 23 of 23 — three of them using the letter X for a remainder of 10. Our decoder still does not verify it, and neither do most consumer tools.
- NHTSA vPIC decodes Zero VINs, but it never reads position 12. On a 2016 FXS it returns the four-way model "FX, FXR, FXS, FXSR", flags the real position-12 character as an error and suggests replacing it. 100 of the 154 fields it returns are empty.
- This page published a 9.4 kWh pack for the 2015 S, SR and SP until Zero's own MY2015 sheet and the bike's coulomb counter both said 12.5. That correction, and the ones beside it, are set out in full below.
- The decoder on this page runs entirely in your browser. Nothing is uploaded, logged or sent to a server.
Decode a VIN
Type or paste all 17 characters. Separators are stripped for you.
The decode runs entirely in your browser. The lookup tables are part of this page, nothing is sent to a server, and no VIN you type is logged, stored or transmitted. Disconnect from the network and it still works.
The examples are real motorcycles with two serial characters masked as XX, so they decode correctly but deliberately fail the check digit.
0 of 17 characters.
How the 17 characters are divided
Every road-legal motorcycle sold in the United States since 1981 carries a 17-character vehicle identification number laid out to the same federal rule. 49 CFR 565.13(b) is one sentence long: "Each VIN shall consist of seventeen (17) characters." Section 565.15 then splits them into four sections: (a) positions 1-3, which "shall uniquely identify the manufacturer and type of the motor vehicle"; (b) positions 4-8, which "shall uniquely identify the attributes of the vehicle"; (c) position 9, the check digit; and (d) positions 10-17. Most decoders describe the same layout as three parts — WMI, descriptor and identifier — by folding the check digit in with the descriptor. Either framing gives the same character boundaries.
Zero Motorcycles follows the rule exactly and fills the discretionary positions with its own scheme. The table below is the map. Every row after it in this article expands one line of it.
Two properties of the standard are worth stating before the tables, because they explain things that otherwise look like gaps. First, the letters I, O and Q are not VIN characters at all — they are excluded by ISO 3779 to stop them being confused with 1 and 0, and you can see the consequence directly in the federal year-code table below, which skips them. Second, 49 CFR 565.15(d) requires that for a motorcycle "the last four (4) characters shall be numeric". Zero goes one better and makes the last five numeric: all 23 VINs in our corpus have digits in positions 13 through 17.
| Position | Name | What Zero puts there |
|---|---|---|
| 1-3 | Manufacturer | 538 (Zero Motorcycles, Inc.), PAG (Integrated Micro-Electronics, Inc.) or A4Z (Zero’s off-road PIN) |
| 4 | Platform | S = SDS street, X = XMX, Z = FST sport, D = FST adventure; C = Commuter and S = Street in MY2009-2010, before the character meant a platform at all |
| 5-6 | Model line and pack | 65 known two-character codes, e.g. M7, DJ, XF, FA |
| 7-8 | Motor | 16 known codes, e.g. Z1 = 13 kW, Z8 = 36 kW, ZA = 11 kW 75-5. Five of them are Gen1 horsepower bands rather than figures |
| 9 | Check digit | Computed from the other 16 characters per 49 CFR 565.15(c) |
| 10 | Model year | 23 known codes, 8 = 2008 through Y = 2030 |
| 11 | Plant | C on 22 of our 23 sample VINs; P on the single PAG bike. A4Z has a plant set of its own |
| 12 | Model designator | 13 known codes, e.g. J = FXS, K = SR/F, L = SR/S. The field itself disappears from MY2024 |
| 13-17 | Sequential serial | Five digits, always numeric in our sample |
Counts are of codes currently known to this decoder, not of codes Zero has ever used, and they are interpolated from the lookup tables rather than typed here — a code added to the decoder moves this row without anyone editing it. The regulation fixes only positions 1-3, 9 and 10; everything else in this column is Zero’s own scheme, read out of Zero’s VIN Breakdown sheets, the community decoder and real VINs.
Where to find the number
On a Zero the VIN is stamped into the frame near the steering head and printed on the manufacturer label, as well as on the registration document. It also appears in the log files: Gen2 MBB headers carry it as an ASCII string, and the native Gen3 MBB header holds it null-terminated at byte offset 0x29.
Positions 1-3: three identifiers, and why some Zeros say PAG
The first three characters are the World Manufacturer Identifier, assigned by the national authority — in the United States, SAE on behalf of NHTSA. Zero holds two of them, plus a third identifier that is not a WMI at all, and this is the single most confusing thing about Zero VINs, because a Zero whose number starts PAG looks to most software like a different manufacturer entirely.
Both records are public and can be checked in one request each against NHTSA’s Product Information Catalog and Vehicle Listing (vPIC). Retrieved 29 July 2026, verbatim:
{"CommonName":"Zero Motorcycles",
"CreatedOn":"2015-08-18",
"DateAvailableToPublic":"2015-08-18",
"Make":"ZERO MOTORCYCLES",
"ManufacturerName":"ZERO MOTORCYCLES, INC.",
"ParentCompanyName":"",
"URL":"https://www.zeromotorcycles.com/",
"UpdatedOn":null,
"VehicleType":"Motorcycle"}The 2015 date is when the record entered the public vPIC dataset, not when the WMI was first used. Our corpus contains 538 VINs with a 2014 model-year code, and the code table reaches back to 2008.
{"CommonName":"IMI",
"CreatedOn":"2023-09-18",
"DateAvailableToPublic":"2023-09-18",
"Make":"ZERO MOTORCYCLES",
"ManufacturerName":"INTEGRATED MICRO-ELECTRONICS, INC.",
"ParentCompanyName":"",
"URL":null,
"UpdatedOn":"2024-02-29",
"VehicleType":"Motorcycle"}Integrated Micro-Electronics, Inc. is a contract manufacturer. A full-VIN decode of a PAG motorcycle returns PlantCity BINAN, PlantState LAGUNA, PlantCountry PHILIPPINES — while the Make stays ZERO MOTORCYCLES.
What follows from having more than one
Five things follow from those records, and between them they account for most of the wrong answers other tools give on a Zero.
- PAG is not a rebadge and not a different brand. It is the WMI of the plant that builds the bike, with the make attributed to Zero.
- The PAG record was created on 2023-09-18, which is consistent with the model years we see on PAG VINs: the only one in our corpus decodes to 2024.
- Everything downstream of position 3 changes with the WMI. Zero did not renumber a PAG bike into the 538 scheme; the descriptor positions carry a different code set, which is why the decoder branches on the WMI before anything else.
- Zero has a third identifier, A4Z, which NHTSA has had registered to ZERO MOTORCYCLES, INC. since 2017 and which Zero's own Part 566 filing names alongside 538. It carries the off-road X-line — the real A4Z numbers are 2026 XE and XB machines built in Chongqing — and it is a different code set again, so the decoder recognises the identifier, reads only the model year and the plant, and refuses to guess a model from tables that do not apply to it. There is a subsection on it below.
- Anything that is none of 538, PAG or A4Z is not a Zero. The decoder treats an unrecognised WMI as a hard error rather than an unknown. That is deliberate: the year and check digit really are manufacturer-independent, so a partial decode is available — but a confident partial decode of a vehicle that is not a Zero is worse than a refusal, and the field that does the damage is not the year, it is the word "Zero" printed beside it.
Gen3 does not imply PAG
The reverse mapping does not hold. Plenty of Gen3 bikes — SR/F, SR/S and DSR/X built in California — carry a 538 WMI. In our corpus 22 of 23 VINs are 538, and five of those 22 are FST-platform machines carrying Z at position 4. A 538 prefix tells you nothing about the platform; the character at position 4 and the family code at positions 4-6 do.
A4Z: the identifier that is not a VIN
A4Z is the interesting one, because it is the case this decoder used to get wrong in the most annoying possible way: it refused the number outright, with a message that read as a bug in our tool rather than as a fact about the motorcycle.
Six things establish what it is and how far anyone can honestly read it. The two NHTSA responses they rest on are quoted in full underneath the list, both retrieved on 30 July 2026 and both reproducible from the request URLs shown.
- It is a PIN, not a WMI, and Zero says so in its own words. The Part 566 filing NHTSA republishes verbatim reads: "Zero Motorcycles (ZMC) has previously had PIN/WMI's issued and is currently operating with PIN 'A4Z' and WMI '538'". NHTSA issues a Product Identification Number for products a manufacturer does not certify as complying with the Federal Motor Vehicle Safety Standards, and every real A4Z number decodes with exactly that warning attached — error code 10, on none of the 538 or PAG numbers.
- A4Z is not a low-volume six-character identifier. 49 CFR 565.15(a) is explicit that a six-character identifier is signalled by a 9 in position 3; A4Z has Z there. Confirming it from the other side, vPIC stores genuine low-volume manufacturers only in their six-character form — 1V9190 resolves and 1V9 returns nothing — whereas A4Z resolves and A4Z000, A4ZAAA and A4ZCJ0 all return nothing.
- Positions 12-17 are therefore an ordinary sequential serial. All three real A4Z numbers end 000075, 000031 and 000084, and mutating position 12 changes nothing in vPIC's answer. Reading a model letter there, as the 538 tables do, would eventually turn a serial digit into a motorcycle.
- Position 11 has its own plant set. vPIC reports the allowed values as (11:CTZ) for A4Z against (11:C) for 538 — Scotts Valley, Pluakdaeng in Thailand and Banan District in Chongqing. That is why the decoder keeps one plant table per identifier rather than sharing a single map.
- Positions 4-8 share no vocabulary with 538 at all: LLSL1 on the XE, BBSL2 on the XB. Through the 538 tables those would come back as platform "L" with everything else null and the decode marked valid — a confidently empty answer, which is worse than no answer.
- Zero publishes no VIN Breakdown for it. The XE and XB owner manuals have an "Identification Numbers" section that tells you where the number is stamped and nothing about how to read it, and the string A4Z appears in none of the 46 manuals we hold. vPIC is currently the only structured source, which is exactly why the decoder asserts only what vPIC and the regulation support.
"OtherManufacturerDetails": "The company has previously filed 566 in 2011. Zero Motorcycles (ZMC) has previously had PIN/WMI's issued and is currently operating with PIN \"A4Z\" and WMI \"538\" this 566 is to add \"PAG\" as a WMI for ZMC to cover an assembly plant in the Philippines."
The whole of what Zero has told the regulator about the relationship between its three identifiers, in one field of one public record.
Make ZERO MOTORCYCLES
Manufacturer ZERO MOTORCYCLES, INC.
ModelYear 2026
Model XE
Series ZS Platform
BodyClass Off-Road Vehicle - Dirt Bike/Off-Road
EngineModel Electric Motor Type ZL1
EngineHP 20
PlantCity BANAN DISTRICT
PlantState CHONGQUING
PlantCountry CHINA
VehicleDescriptor A4ZLLSL1*TZ
ErrorCode 0,10
ErrorText 0 - VIN decoded clean. Check Digit (9th position) is
correct; 10 - Off-Road Vehicle Warning - This is not a
Vehicle Identification Number (VIN) for a motor vehicle.
This indicates that the manufacturer did not certify this
product as complying with the Federal Motor Vehicle Safety
Standards that are applicable to motor vehicles as defined
in 49 U.S.C. 30102.Quoted unmasked because this is NHTSA's response to NHTSA's own published API and is reproducible with the URL above. Everywhere else on this page the same three bikes appear masked, as A4ZLLSL15TZ0000XX, A4ZLLSL17TZ0000XX and A4ZBBSL27TZ0000XX — two XE and one XB, all model year 2026, all returning ErrorCode 0,10.
The prior art accepts A4Z and then decodes it as a 538
The community decoder checks the identifier once — if ( $wmi <> '538' && $wmi <> 'A4Z' ) — and never refers to $wmi again. Every function under it applies the 538 positional scheme unconditionally. Its tables stop at 2020, so today it returns blanks for a 2026 XE rather than a wrong answer, but that is luck rather than design. Accepting the identifier and branching the schema are two different jobs, and only the first one is one line.
Two of these codes are also 538 codes, and it means nothing
XB and XE are real model-line codes at positions 5-6 of a 538 VIN — FX/FXS/FXP and FXS respectively — and they are now also the names of two 2026 off-road motorcycles. The collision is a coincidence, not a link. It is written down here because it is exactly the kind of thing that looks like a lead when someone wires up the A4Z tables later.
Positions 4-8: platform, model line, motor
49 CFR 565.15(b) is deliberately loose about these five characters: "The second section shall consist of five characters, which occupy positions four through eight (4-8) in the VIN. This section shall uniquely identify the attributes of the vehicle as specified in Table I." Table I asks a motorcycle manufacturer for "Make, type of motorcycle, line, engine type, and net brake horsepower", and leaves the encoding entirely to them. Zero splits the five characters 1 + 2 + 2.
Position 4: platform
One character, and the decoder reads it twice — once for the platform name and, on PAG VINs, again for the battery size.
| Char | Platform | Notes |
|---|---|---|
| S | SDS, from MY2011 | Street: S, SR, DS, DSR. 10 of our 23 sample VINs. |
| S | Street, MY2009-2010 | The same character, before it named a platform. No corpus VIN is this old. |
| C | Commuter, MY2009-2010 | Gen1 only, and community-sourced. Outside those two years the character means nothing and the decoder says so. |
| X | XMX, from MY2011 | Light off-road and supermoto: FX, FXS, FXP, FXE. 7 of 23 — but read the FXE note below before inferring a generation from it. |
| Z | FST sport, from MY2020 | S/F, SR, SR/F, SR/S. 5 of 23. |
| D | FST adventure, from MY2023 | DS, DSR, DSR/X. 1 of 23, and it is the PAG bike. |
The MY2011 break is real code rather than editorial. It used to sit at 2012, which matched no source at all; 2011 is where the meaning of the character changes and both the community decoder and Zero's own books agree on it. Before MY2011 position 4 names a body style — S is Street, C is Commuter — and from MY2011 it names a platform, which is why S appears twice above. Two cautions on this table. First, D is named on the 538 branch now as well as the PAG one, so a 538 VIN carrying D no longer comes back with the bare letter D as its platform. Second, this column is the chassis platform the VIN character names. It is not the product generation and it is not the log-format generation. The FXE is where the three part company: its VIN files it under X = XMX, the owner manuals and our bike catalogue put it at product generation 2 on the XMX / Cypher II platform, and our parser routes its logs to the Gen3 branch — where they are decoded by the 538XX path, a Gen2-lineage record format, not the native Gen3 ring buffer. All three FXE files in our corpus are 262,144-byte MBB\0 / BMS\0 dumps, which is what that last sentence means in practice. The three statements are true at once because they answer different questions. Third, and smallest: "XMX" is not Zero's word for this character. Every X-platform sheet from MY2014 to MY2025 prints "X = X Platform"; XMX is Zero's name for the FX family, which is why it appears in their document filenames, in the XMX service manual's parts callouts and in NHTSA's Series string. It is a fair label and a poor quotation, and this page would rather say so than quietly swap one for the other.
Positions 5-6: model line and nominal pack
Sixty-five two-character codes are known. The code carries the family (S, DS, FX, XU and their variants) and, for 42 of the 65, the nominal pack size in kWh. Thirteen codes also pin the motor power directly, which is why the decoder fills motor power from the model line first and only falls back to positions 7-8.
The list is not exhaustive and does not pretend to be. Of the 23 real VINs we can check, 22 hit a known model-line code. The single miss is the PAG bike, and it is a miss by construction rather than a gap in the table: the PAG branch returns before it reads positions 5-6 at all, because those two characters are part of the three-character family code described further down.
This is the table Zero's own books correct most often, and one of those corrections changed a number the rest of this site computes with. Codes M7 and M8 name the 2015 S, SR and SP; D7 and D8 name the 2015 DS and DSP; and until recently this page had both pairs the wrong way round, publishing 9.4 kWh for M7 and 12.5 for M8. The error was inherited wholesale from the community decoder. Zero's MY2015 owner's manual prints "M7 = 15 MY S/SR/SP (12.5)" and "M8 = 15 MY S/SR/SP (9.4)", and the one 2015 SR in our corpus settles it from the other direction: its BMS records an amp-hour counter against state of charge, and a fit across 79 distinct SOC levels gives 92.2 Ah for a full swing — 85 per cent of a ZF12.5 and a physically impossible 113 per cent of a ZF9.4. We were publishing a pack Zero never sold on that bike, and it fed the state-of-health maths as a 33 per cent error in the denominator.
The capacity in this table is what turns into a pack name elsewhere in the app, and for every code but one the mapping is one to one: a model-line code that encodes 14.4 gives a Z-Force ZF14.4, and so on down the second table below. The exception is the modular FX pack. Code XD carries the capacity 3.6/7.2 — one string covering both the one-module and the two-module build of the same bike — and that string is not a key in the pack table. The decoder keeps 3.6/7.2 as the pack size, because "this pack is modular" is worth keeping, and names the pack from the base figure instead: our own 2023 FX decodes to a nominal 3.6/7.2 kWh with the pack name Z-Force ZF3.6. Thirteen pack sizes are recognised in all, and every one of them carries the same series count.
That last claim is the one people query, so here is its basis. Every pack in the table below is marked 28s — twenty-eight cell groups in series — from the 3.3 kWh removable FX module to the 17.3 kWh DSR/X monolith, which looks wrong until you remember that a series count sets voltage, not capacity. Every Zero pack is a ~102 V nominal machine, and that requires the same series count regardless of how much energy is behind it. It is measured rather than assumed: across the Gen3 logs in our corpus the ratio of pack voltage to lowest cell voltage sits at 28.01 to 28.03, and on a MY2015 Gen2 pack the BMS reports 105.768 V against a 3.798 V cell, which is 27.85. What is not sourced anywhere, and what this field has never claimed, is how many cells sit in parallel within each of those twenty-eight groups — that is where the capacity difference actually lives.
| Code | Model line | Nominal pack | Motor from this code | Source |
|---|---|---|---|---|
| M2 | S | not encoded | from positions 7-8 | community only |
| M3 | S | not encoded | from positions 7-8 | community only |
| D2 | DS | not encoded | from positions 7-8 | community only |
| D3 | DS | not encoded | from positions 7-8 | community only |
| D4 | DS | not encoded | from positions 7-8 | community only |
| X2 | MX | not encoded | from positions 7-8 | community only |
| X3 | FX | not encoded | from positions 7-8 | community only |
| X0 | X | not encoded | from positions 7-8 | community only |
| X1 | X | not encoded | from positions 7-8 | community only |
| E1 | MX | not encoded | from positions 7-8 | community only |
| U1 | XU | not encoded | from positions 7-8 | community only |
| U2 | XU | not encoded | from positions 7-8 | community only |
| U3 | XU | not encoded | from positions 7-8 | community only |
| C2 | XU-LSM (CA) | not encoded | from positions 7-8 | community only |
| L2 | XU-M (EU) | not encoded | from positions 7-8 | community only |
| M4 | S/SR/SP | 8.5 kWh | from positions 7-8 | |
| M5 | S/SR/SP | 11.4 kWh | from positions 7-8 | |
| D5 | DS/DSR/DSP | 11.4 kWh | from positions 7-8 | |
| D6 | DS/DSR/DSP | 8.5 kWh | from positions 7-8 | |
| X4 | FX/FXL | not encoded | from positions 7-8 | |
| X5 | FXP/FXLP | not encoded | from positions 7-8 | |
| M7 | S/SR/SP | 12.5 kWh | from positions 7-8 | |
| M8 | S/SR/SP | 9.4 kWh | from positions 7-8 | |
| D7 | DS/DSR/DSP | 12.5 kWh | from positions 7-8 | |
| D8 | DS/DSR/DSP | 9.4 kWh | from positions 7-8 | |
| X6 | FX/FXS | not encoded | from positions 7-8 | |
| X7 | FXP | not encoded | from positions 7-8 | |
| M0 | S/SR/SP | 9.8 kWh | from positions 7-8 | |
| M9 | S/SR/SP | 13.0 kWh | from positions 7-8 | |
| D0 | DS/DSR/DSP | 9.8 kWh | from positions 7-8 | |
| D9 | DS/DSR/DSP | 13.0 kWh | from positions 7-8 | |
| X8 | FX/FXS | not encoded | from positions 7-8 | corpus only |
| X9 | FXP | not encoded | from positions 7-8 | community only |
| XA | FXS | 6.5 kWh (unattested) | from positions 7-8 | corpus only |
| MB | S/SP | 6.5 kWh | from positions 7-8 | |
| MC | S/SR/SP/SRP | 13.0 kWh | from positions 7-8 | |
| MD | S | 13.0 kWh | 11kW | |
| DA | DS | 6.5 kWh | from positions 7-8 | |
| DB | DS/DSR/DSP/DSRP | 13.0 kWh | from positions 7-8 | |
| XB | FX/FXS/FXP | not encoded | from positions 7-8 | |
| ME | S | 7.2 kWh | 11kW | |
| MF | S/SR | 14.4 kWh | from positions 7-8 | |
| MG | S | 14.4 kWh | 11kW | |
| DC | DS | 7.2 kWh | 11kW | |
| DD | DS/DSR | 14.4 kWh | from positions 7-8 | |
| DE | DS | 14.4 kWh | 11kW | |
| MH | S | 7.2 kWh | 11kW | |
| MK | S | 14.4 kWh | 11kW | |
| DF | DS | 7.2 kWh | 11kW | |
| DH | DS | 14.4 kWh | 11kW | |
| XC | FX/FXS/FXP | not encoded | from positions 7-8 | |
| ML | S/SR | 14.4 kWh | from positions 7-8 | |
| MM | S | 7.2 kWh | 11kW | |
| MN | S | 14.4 kWh | 11kW | |
| DJ | DS/DSR | 14.4 kWh | from positions 7-8 | |
| DK | DS | 7.2 kWh | 11kW | |
| DL | DS | 14.4 kWh | 11kW | |
| DM | DSR Black Forest | 14.4 kWh | from positions 7-8 | |
| XD | FX/FXS | 3.6/7.2 kWh | from positions 7-8 | |
| XE | FXS | 7.2 kWh | from positions 7-8 | |
| XF | FXE | 7.2 kWh (unattested) | from positions 7-8 | |
| FA | SR/F | 14.4 kWh (unattested) | from positions 7-8 | |
| FB | SR/S | 14.4 kWh (unattested) | from positions 7-8 | |
| FD | SR/F | 15.6 kWh (unattested) | from positions 7-8 | |
| FE | SR/S | 15.6 kWh (unattested) | from positions 7-8 |
A code that lists several models, such as S/SR/SP, is shared across trims and is resolved by the position-12 designator and the motor size. A pack size marked "(unattested)" means the code itself is sourced but its capacity is not: no VIN Breakdown sheet prints one, and the figure is our inference from the sibling codes or from telemetry. An empty Source cell means the code is printed in one of Zero’s own VIN Breakdown sheets, which is the plurality of this table; the marked rows are the ones that are not. "community only" means the zero-motorcycle-community decoder has it and no manual we hold does; "corpus only" means a real VIN in our logs wears it and no document attests it; "unattested" means we publish it and nothing supports it.
| Nominal kWh | Pack name | Cells | Chemistry |
|---|---|---|---|
| 3.3 | Z-Force Power Pack | 28s | Li-Ion |
| 3.6 | Z-Force ZF3.6 | 28s | Li-Ion |
| 6.5 | Z-Force ZF6.5 | 28s | Li-Ion |
| 7.2 | Z-Force ZF7.2 | 28s | Li-Ion |
| 8.5 | Z-Force ZF8.5 | 28s | Li-Ion |
| 9.4 | Z-Force ZF9.4 | 28s | Li-Ion |
| 9.8 | Z-Force ZF9.8 | 28s | Li-Ion |
| 11.4 | Z-Force ZF11.4 | 28s | Li-Ion |
| 12.5 | Z-Force ZF12.5 | 28s | Li-Ion |
| 13.0 | Z-Force ZF13.0 | 28s | Li-Ion |
| 14.4 | Z-Force ZF14.4 | 28s | Li-Ion |
| 15.6 | Z-Force ZF15.6 | 28s | Li-Ion |
| 17.3 | Z-Force ZF17.3 | 28s | Li-Ion |
Every figure is nameplate capacity. 28s means twenty-eight cell groups in series, which is why every one of these packs is a ~102 V machine whatever its size: a series count sets voltage, not energy. It is measured rather than assumed — across the Gen3 logs in our corpus the ratio of pack voltage to lowest cell voltage sits at 28.01 to 28.03, and a MY2015 Gen2 pack reports 105.768 V against a 3.798 V cell, which is 27.85. A full pack reads well above the nominal figure: the 116 V you may have seen quoted is the charged voltage. What is not sourced, and what this column has never claimed, is how many cells sit in parallel inside each group — which is where the capacity difference between a 3.3 kWh module and a 17.3 kWh pack actually lives.
Positions 7-8: motor
Sixteen codes. The first character is almost always Z; the second selects power and, where known, the Z-Force motor size. Five of the 16 are pre-2014 codes that encode a horsepower BAND rather than a figure — 0-50 hp, 50-100 hp, 100+ hp and two named motor types — and they are republished in the unit they were published in rather than converted to a single number that would look like a measurement.
Size and power are separate axes, and the pair that proves it is Z2 and Z3. Zero's MY2016 and MY2017 sheets both print Z2 = 16 kW (22 HP) - 75-7 against Z3 = 16 kW (22 HP) - 75-7R: identical figures, one suffix apart. Z5 and Z6 are not that pair, and this page used to claim they were. In the table below Z5 is 21 kW on the 75-7 and Z6 is 22 kW on the 75-7R — two different power levels as well as two different motors, so nothing about the R can be inferred from them. They were genuinely equal at 21 kW in MY2017 and MY2018; from MY2019 Zero's sheets, the service manual and the community decoder all move Z6 to 22 kW, and we were the only ones still publishing the old figure.
What the R actually buys is visible in the spec sheets rather than the VIN: the MY2021 S runs a 550 A controller and peaks at 44 kW, the SR a 775 A controller and 52 kW, on the same 30-minute rating.
This table is year- and platform-scoped underneath, and this rendering shows the newest meaning of each code — which for Z4 and Z6 is strictly less than the decoder knows. Type a VIN into the widget at the top of the page and you get the answer for that bike's model year; read the row here and you get the answer for the most recent one.
Note that these figures are the motor rating encoded in the VIN, and it is a specific one: the UNECE R85 30-minute continuous rating. Zero prints the same numbers under "Maximum Continuous-rated 30 Minutes Power" in the same manuals. A 2016 FXS decodes to 13 kW from its VIN while its published peak is 33 kW; both are true of the same motor. From MY2024 Zero renamed the field "Engine Type/Model" and stopped publishing the mapping entirely, so a decoder that returns a kW figure for a MY2024 VIN is inventing it — this one returns nothing.
| Code | Rated power | Z-Force motor | Variant | Source |
|---|---|---|---|---|
| 10 | 100+ hp | not encoded | size not encoded | community only |
| 51 | 50 - 100 hp | not encoded | size not encoded | community only |
| 05 | 0 - 50 hp | not encoded | size not encoded | community only |
| M1 | Type M / 16.2 - 19.8 HP | not encoded | size not encoded | community only |
| A1 | Type A / 26.1 - 31.9 HP | not encoded | size not encoded | community only |
| M3 | 9.1kW | not encoded | size not encoded | community only |
| ZA | 11kW | 75-5 | base | |
| ZB | 11kW | 75-7 | base | |
| Z1 | 13kW | not encoded | size not encoded | |
| Z2 | 16kW | 75-7 | base | |
| Z3 | 16kW | 75-7R | R variant | |
| Z4 | 17kW | 75-5 | base | |
| Z5 | 21kW | 75-7 | base | |
| Z6 | 22kW | 75-7R | R variant | |
| Z7 | 40kW | not encoded | size not encoded | |
| Z8 | 36kW | not encoded | size not encoded |
Rendered from MOTORS_BY_CODE. The rated figure is what the VIN encodes, which is the UNECE R85 30-minute continuous rating, not peak power — Zero prints the same numbers under "Maximum Continuous-rated 30 Minutes Power" in the same manuals. Where the value is year- or platform-scoped this table shows the newest meaning only, which for Z4 and Z6 is less than the decoder knows: type a VIN into the widget for the answer that applies to a particular model year. An empty Source cell means the code is printed in one of Zero’s own VIN Breakdown sheets, which is the plurality of this table; the marked rows are the ones that are not. "community only" means the zero-motorcycle-community decoder has it and no manual we hold does; "corpus only" means a real VIN in our logs wears it and no document attests it; "unattested" means we publish it and nothing supports it.
Z4: one code, five readings, and one disagreement nobody can settle
Z4 is the code that forced this whole redesign, so it is worth laying out in full. It is the only entry where Zero contradicts Zero — not across a decade, but between two books shipped in the same year, and then between two pages of the same book.
| Model year | Platform | What the decoder returns | Printed in |
|---|---|---|---|
| 2017 | either | 17 kW, 75-5 | OM-SDS-MY17 fig. ZOM0484 and OM-XMX-MY17 fig. ZOM0561, both at 23 HP |
| 2018-2023 | X | 15 kW, 75-5 | OM-XMX-MY18 fig. ZOM0596, XMX_Service_Manual fig. ZOM0617 (K = 2019), 22MY_XMX fig. ZOM1062 |
| 2018-2019 | S | 17 kW, 75-5 | OM-SDS-MY18 fig. ZOM0595, OM-SDS-MY19 fig. ZOM0616, SDS_Service_Manual fig. ZOM0615 |
| 2020-2021 | S | no single figure: 15 kW (Europe) / 17 kW (Rest Of The World) | 21MY_SDS p.8.1 fig. ZOM0660 prints 15 kW; p.8.12 fig. ZOM0661 prints 17 kW. One PDF. |
| 2022-2023 | S | 17 kW, 75-5 | 23_SDS p.8.8 fig. ZOM1085. The Europe sheets drop Z4 entirely by then. |
The MY2019 rows are the ones worth staring at. Zero's X service manual and its S service manual were published together, cover the same model year, and print different power against the same two characters. That is what makes this table platform-scoped as well as year-scoped — and the platform character is position 4 of the VIN, so the decoder always has it and never has to guess. The MY2020-2021 row is a different kind of problem and cannot be fixed the same way: market is a real fourth axis, and the VIN carries no market character at all — every affected bike is built in Scotts Valley. So the decoder leaves the motor power null for those two years, publishes both figures in a field of their own and names both pages. 20 HP converts to 14.9 kW, which we find suggestive of 15, but that is an inference, and Zero were still shipping the 17 kW page in 2023. A Certificate of Conformity, field P.2, or two dealer motor part numbers would settle it. Until one of those turns up, this page would rather show you the argument than the tidier number.
The community decoder said this would happen
vin_decoder.php carries two comments directly above its motor table: "HP codes seem unique across years, only single dimensional array needed, year not needed" and "Codes may actually vary between platforms (SDS vs X), not accounted for yet". Zero's own books prove the second one right and the first one wrong — on Z4 and on Z6. Whoever wrote that knew exactly where the design would break and said so in the file; we copied the table and not the warning.
Position 9: the check digit
Position 9 is not information about the motorcycle. It is a modulo-11 checksum over the other sixteen characters, and its only purpose is to catch transcription errors. The algorithm is written out in full in the regulation, so there is no ambiguity about it.
49 CFR 565.15(c), verbatim: "This section shall be the check digit whose purpose is to provide a means for verifying the accuracy of any VIN transcription. After all other characters in VIN have been determined by the manufacturer, the check digit shall be calculated by carrying out the mathematical computation specified in paragraphs (c) (1) through (4) of this section."
- 1Assign each character its value from Table III below. Digits keep their own value; I, O and Q have no value because they cannot appear in a VIN.
- 2Multiply each value by the position weight from Table IV. Position 9 has weight 0, so the check digit never contributes to its own calculation.
- 3Add the seventeen products and divide the total by 11.
- 4The remainder is the check digit, 0 through 9, except that a remainder of 10 is written as the letter X.
| Letter | Value | Letter | Value | Letter | Value |
|---|---|---|---|---|---|
| A | 1 | J | 1 | S | 2 |
| B | 2 | K | 2 | T | 3 |
| C | 3 | L | 3 | U | 4 |
| D | 4 | M | 4 | V | 5 |
| E | 5 | N | 5 | W | 6 |
| F | 6 | P | 7 | X | 7 |
| G | 7 | R | 9 | Y | 8 |
| H | 8 | — | — | Z | 9 |
I, O and Q are absent from the table because they are not valid VIN characters.
| Position | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Weight | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 10 | 0 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |
Measured: 23 of 23
We ran the algorithm over every distinct VIN in this project’s log corpus — 23 unique motorcycles, drawn from the 328 of our 352 log files whose filename carries a VIN, spanning model years 2014 to 2024, both road WMIs and four platform characters. Every one satisfies the check digit. Three of them use X in position 9, the remainder-10 case, so that branch is exercised by real data too.
The decoder here does not verify it
Neither the Python decoder that writes our database rows nor its TypeScript mirror checks position 9. A VIN with a single mistyped character will decode happily and give you a plausible, wrong answer. The widget on this page does compute the digit, purely so you can see the mismatch; the pipeline behind your uploads does not.
Position 10: the model year code
One character, and the most frequently misread position on any VIN. The code is federally fixed, not a manufacturer choice: 49 CFR 565.15(d)(1) publishes it as Table VII, quoted here verbatim from the current eCFR text.
Year Code Year Code Year Code Year Code 2005 5 2014 E 2023 P 2032 2 2006 6 2015 F 2024 R 2033 3 2007 7 2016 G 2025 S 2034 4 2008 8 2017 H 2026 T 2035 5 2009 9 2018 J 2027 V 2036 6 2010 A 2019 K 2028 W 2037 7 2011 B 2020 L 2029 X 2038 8 2012 C 2021 M 2030 Y 2039 9 2013 D 2022 N 2031 1
The sequence skips I, O, Q, U and Z among the letters and 0 among the digits, giving a 30-year cycle before the codes repeat.
Reading it without the classic mistakes
The table looks trivial and is routinely got wrong, in five specific ways.
- A to J is nine letters, not ten. I is skipped, so A = 2010, B = 2011, C = 2012, D = 2013, E = 2014, F = 2015, G = 2016, H = 2017 and J = 2018. Counting I into the sequence is the classic off-by-one that turns a 2017 bike into a 2016 one.
- K to Y is twelve codes, not fifteen, covering 2019 to 2030 — the stretch of the alphabet from K to Y is fifteen letters, but O, Q and U are all excluded, and Z is not a year code either.
- Our table carries 23 codes, from 8 = 2008 to Y = 2030. It stops there deliberately: the regulation wraps to numerals in 2031, and a decoder that guessed would silently mislabel a bike. The digit 8 was missing until recently, which made a 2008 Zero a hard error rather than a 2008 Zero.
- An unrecognised character in position 10 is a hard stop. The decoder returns "Unknown year code: I" and gives up rather than continuing with a null year, because the year feeds the platform naming and the model disambiguation below it.
- Model year is not the build date. A bike sold in late 2015 is very often model year 2016, and the log files will disagree with the VIN accordingly.
| Code | Year | Code | Year | Code | Year |
|---|---|---|---|---|---|
| 8 | 2008 | G | 2016 | R | 2024 |
| 9 | 2009 | H | 2017 | S | 2025 |
| A | 2010 | J | 2018 | T | 2026 |
| B | 2011 | K | 2019 | V | 2027 |
| C | 2012 | L | 2020 | W | 2028 |
| D | 2013 | M | 2021 | X | 2029 |
| E | 2014 | N | 2022 | Y | 2030 |
| F | 2015 | P | 2023 |
Rendered from YEARS_BY_CODE in src/lib/vin-decode.ts, which mirrors the backend decoder.
Position 11: the plant
One character identifying the assembly plant. Twenty-two of the 23 VINs in our corpus carry C; the single PAG bike carries P.
C is Scotts Valley, CA, USA. Every Zero VIN Breakdown sheet from MY2014 to MY2025 prints exactly that string, the community decoder agrees, and NHTSA reports PlantCity SCOTTS VALLEY with PlantCompanyName "Zero Motorcyles Inc." — the misspelling is in the federal dataset, not a typo here. The company was founded in Santa Cruz and moved a few kilometres up the road to Scotts Valley, which is where 380 El Pueblo Road, the address on its filings, is.
P is the Philippines, and it appears from MY2024. Zero's own MY2025 sheets spell it "Phillipines"; the correct spelling is what the decoder publishes. PAG VINs read position 11 now — the branch used to return before reaching it, so every Gen3 bike reported no plant at all, including the one in our corpus, which is built there.
The A4Z off-road line has a plant set of its own: NHTSA accepts C, T and Z in position 11 for it, against C alone for 538, and the three real A4Z VINs are all Z — Banan District, Chongqing, China. That is why the decoder keeps a separate plant table per WMI rather than sharing one.
One character is not much of a sample
With C on 22 of 23 bikes we can say what C means but not what the scheme is. If you hold a Zero VIN with something other than C or P in position 11 we would like to see it — the feedback form on this site takes it, and a masked VIN is enough.
Position 12: the model designator
Position 12 is where the regulation stops caring. 49 CFR 565.15(d)(3) says positions 12 through 17 "shall represent the number sequentially assigned by the manufacturer in the production process" for a high-volume manufacturer. Zero uses only 13 through 17 as the sequence and spends position 12 on a model letter — which is legitimate, is consistent across every 538 VIN we have, and is invisible to any decoder that assumes the regulation’s literal reading. That includes NHTSA’s own.
This is the position that makes a Zero-specific decoder worth writing. On a 2016 FXS the model-line code at positions 5-6 is X8, which means "FX or FXS" and resolves nothing; position 12 is J, which means FXS.
It is also the position with an end date. From model year 2024 Zero's VIN Breakdown diagrams have no Model row at all — the layout runs the plant character straight into the serial, on the FST street sheet, the FST adventure sheet and the X sheet alike — and the one MY2024 bike in our corpus has a digit there. So every entry in the table below is bounded at MY2023, and a 2024 or later VIN gets no model from position 12 rather than a model letter invented out of a serial digit. That bound is data, not a special case in the code, which is the only reason it is reliable.
| Code | Model | Resolves on its own? | Source |
|---|---|---|---|
| 1 | X | yes | community only |
| 2 | MX | yes | community only |
| A | S | yes | |
| B | DS | yes | |
| C | FX | yes | |
| E | XU | yes | community only |
| G | SR/DSR | no — see the rule below | |
| H | FXP | yes | |
| J | FXS | yes | |
| K | SR/F | yes | |
| L | SR/S | yes | |
| M | FXE | yes | |
| N | DSR/X | yes |
Ambiguity is decided the way the decoder decides it, not by looking for a slash: K is SR/F and L is SR/S, single models whose names happen to contain one. Every entry is bounded at model year 2023, because from MY2024 Zero’s own diagrams have no Model row and position 12 is a serial digit. An empty Source cell means the code is printed in one of Zero’s own VIN Breakdown sheets, which is the plurality of this table; the marked rows are the ones that are not. "community only" means the zero-motorcycle-community decoder has it and no manual we hold does; "corpus only" means a real VIN in our logs wears it and no document attests it; "unattested" means we publish it and nothing supports it.
The one ambiguous designator
One code still covers more than one model, and the decoder applies a fixed rule to it. There used to be two: M was published as "FXE|DSR/X" and split on the platform, but the DSR/X half was attested by no source anywhere — Zero gives the DSR/X the designator N — so it was deleted rather than disambiguated, and N was added in its place. The rule below is worth stating because it is the part of the decode most likely to be wrong on an unusual bike.
| Code | Raw value | Rule | Outcome |
|---|---|---|---|
| G | SR/DSR | Model years 2014 and 2015 resolve to SR unconditionally; from 2016 the model line decides | A model line containing DS gives DSR, otherwise SR |
The decoder carries a third rule, keyed on a 75-7R motor size, for designator values spelled S/SR or DS/DSR. No value in the current designator table is spelled that way, so that branch never executes today. It is documentation of intent, not behaviour — worth knowing before you rely on it.
Position 12 is dead on PAG VINs
The single PAG VIN in our corpus carries 0 in position 12, which is not in the designator table at all. That is expected: PAG bikes carry their model in the family code at positions 4-6 instead, and the decoder never reaches the position-12 lookup on that branch.
Why every table here is scoped by model year
Every lookup table on this page except the federal year codes is stored as a list of model-year ranges rather than as a single value per code, and every range is bounded at the years its sources actually cover. That is not tidiness. Zero reuses its codes, and a table that cannot say which years a meaning is good for has to publish it for all of them — including the ones it is wrong for.
The reuse is documented, not suspected. The community decoder keys its tables by model year and records M0 as an MX in 2011 and a 9.8 kWh S in 2016; U2 as an XU-LSM in 2011 and an XU in 2012; M4 as a plain S in 2013 and an 8.5 kWh S/SP in 2014. At position 12 it has C changing meaning four times — X in 2011, XD/X in 2012, XD/X/FX in 2013, XD/X/FX/FXL in 2014 — before Zero's own MY2015 FX manual settles it at FX. Flattening all that into one value per code is what this page used to do.
What shipped is the bound, not yet the second meaning. Ask this decoder about a MY2011 M0 today and it returns nothing at all: no model line, no pack size. Ask the old flat table and it confidently returned S/SR/SP with a 9.8 kWh pack — a 2016 street bike's specification asserted onto a 2011 dirt bike, with is_valid true and no error. Silence is the correct intermediate state, and it is what a bounded range buys you before anyone has reviewed the older reading.
Actually publishing those older meanings is a separate job, deliberately not done in the same pass. A second range changes what this page prints and what the backend writes into a database row, so each one needs its own evidence. Today three codes carry more than one range: the motor codes Z4 and Z6, where the disagreement is not across a decade but between two books Zero shipped in the same year, and the platform character S, which names a body style before MY2011 and a platform after it. Everything else is a single bounded range.
- Ranges are inclusive and may have gaps, and the gaps are load-bearing. A code Zero picked up again after a few years has no meaning in between, and the lookup returns nothing rather than reaching for the nearest range. A decoder that helpfully clamped to the closest year would resurrect exactly the answer the bound was added to remove.
- Two ranges may overlap only if they name different platform characters. That is how Z4 reads 15 kW for an X bike and 17 kW for an S bike in the same model year without duplicating every code that is not affected.
- When the model year does not resolve, the year-scoped fields stay empty and the decoder says why. It never picks the newest candidate, or the most likely one, because the twelve places in this application that read a decode read it as fact.
- Market is a fourth axis and is deliberately not one of the keys, because it is not in the VIN. Where two markets disagree, the entry publishes both figures and names both pages.
- The tables on this page are the flat projection of the ranges: one row per code, showing its newest meaning. That is lossless for every code with a single range and lossy for the ones above, which is why the motor section says so and why the widget — which knows the model year — is the thing to trust for a specific bike.
What the coverage statistic was never evidence of
The honest reason to say all this out loud is that the coverage numbers on this page look better than they are. Our corpus spans model years 2014 to 2024. Every documented collision above happens before 2014. So not one of them was ever exercised by a real VIN we hold — not M0, not U2, not M4, not the four meanings of C.
Which means the "Model: 23 / 23" line in the coverage table further down was never evidence that a flat, year-blind table worked. It was evidence that we had no motorcycle old enough to break it. The measurement was fine; the conclusion drawn from it was not, and it is the kind of conclusion a coverage statistic invites you to draw. A single MY2011 XU or MY2012 X in the corpus would have failed loudly years earlier. We would still like one, and the feedback form takes a masked VIN.
The same caution applies in the other direction, to codes the corpus attests but no document does. Model-line code XA appears in no Zero VIN Breakdown sheet and in no community table; the only thing that establishes it is a 2016 FXS in our logs wearing it. Its 6.5 kWh pack size is our inference from the sibling codes on the same sheet, and it is one of the pack sizes listed as unattested below rather than being allowed to pass for a figure Zero published.
Where each code came from
Every entry now carries a list of citations rather than a bare value, and the strongest of them is what the table below summarises. Four things can appear, and the ordering is deliberate: a claim is only as good as the best document behind it. On the web page each lookup table carries a Source column showing it per code; the plain-text mirror of this page drops the column, and the citations themselves — file, printed page, figure number — live in the decoder source either way.
| Tier | Meaning | How many |
|---|---|---|
| manual | Printed in a Zero VIN Breakdown table in an owner’s or service manual. The citation in the code names the file, the printed page and the figure number, because a manual claim is only true for the model years of that sheet. | 47 of the 65 model-line codes, 10 of the 16 motor codes, 10 of the 13 designators |
| corpus | A real VIN in our logs wears the code and decodes consistently with its year and its position-12 designator, but no document attests it. The code is real; its expansion is our reading. | 2 model-line codes |
| community | In the zero-motorcycle-community web-tools decoder, and in no manual we hold. Published, attributed, never presented as Zero’s word. | 16 model-line codes, 6 motor codes, 3 designators |
| unattested | We publish it and nothing supports it. An empty citation list is a legal, deliberate state — it is not the same as an unreviewed one, and it is why this row exists at all. | the pack size on 6 model-line codes and on 8 Gen3 family codes |
Two axes, not one. A code can be printed in a manual while the pack size beside it is our own inference — XA, XF, FA, FB, FD, FE are all in that position, and so is every Gen3 family code, because no VIN Breakdown sheet prints a pack size for an FST bike at all. One column could not say that, which is why there are two. Every count in this table is read out of the same citation lists the decoder ships with, so it moves when the evidence does.
Positions 13-17: the sequential serial
Five digits, assigned in production order. 49 CFR 565.15(d) requires the last four characters to be numeric for a motorcycle; Zero makes all five numeric, and all 23 corpus VINs comply. On the A4Z off-road numbers the serial is six digits, running from position 12, because there is no model designator to make room for.
There is nothing to decode here, but there is something to be careful about. The serial is the only part of a VIN that identifies one specific motorcycle rather than a model, so it is the part that turns a VIN into personal data. Every VIN published on this page and in this project’s documentation has two of its serial characters replaced with XX for that reason, and a masked VIN still decodes correctly because nothing reads positions 13-17.
A practical consequence: NHTSA rejects a masked VIN with error 400, "Invalid Characters Present", and names the offending positions, because X is not a digit. That is a good sanity check that you have masked the number properly before publishing it.
Do not post an unmasked VIN in a public forum
A full VIN is enough to order parts against a bike, to look up its service history at a dealer, and in some jurisdictions to file paperwork about it. Mask two characters of the serial before you paste it anywhere public. The decoder below will still give you the complete answer.
Gen3: the FST platform, PAG, and 538 bikes that are also Gen3
Gen3 — the Cypher III generation, SR/F onwards — broke the position-by-position scheme in two ways at once. Some of those bikes moved to the PAG WMI, and all of them started carrying their identity in a three-character family code at positions 4-6 rather than in the position-12 designator.
The decoder handles the two cases on different paths. A PAG VIN takes an early return: platform is fixed to FST, the pack size comes from the platform character at position 4, the model comes from the family code and the plant from position 11. Model line and motor are left null, because the 538 tables do not apply to those positions. A 538 VIN takes the normal path and only falls back to the family code if the position-12 designator produced nothing.
- The platform character determines the pack, not the model: Z gives the 15.6 kWh sport pack, D gives the 17.3 kWh adventure pack. The model itself comes from the full three-character family code.
- That split matters because Z alone cannot tell an S/F from an SR/F from an SR/S — all three are Z-platform bikes with the same nominal pack. The family codes ZFS, ZFD and ZFE separate them.
- The family codes were corroborated independently of the VIN: native Gen3 MBB firmware writes a model tag at header offset 0x18 that is one-to-one with them, so ZFE and OSRS both mean SR/S.
- On a 538 VIN the fallback only fires when the normal decode left the model null, so no Gen1 or Gen2 538 VIN is affected by it.
- The fallback fires less often than you would expect, and one corpus VIN shows what that costs when a code is missing. A 2023 SR/F on a 538 WMI carries FD at positions 5-6 and K at position 12. Position 12 resolves the model to SR/F on its own, so the model is never null, so the gate on the family fallback never opens — and while FD was absent from the model-line table that bike came back with a null model line, a null pack size and a null pack name even though the family table two rows up knew perfectly well that ZFD means an SR/F with a 15.6 kWh pack.
- The fix was to add the missing codes rather than to loosen the gate: FD (SR/F) and FE (SR/S) are both in the model-line table above at 15.6 kWh, the same nominal the family table assigns to ZFD and ZFE and the same the PAG platform table assigns to the whole Z sport platform. That VIN now decodes to model SR/F, model line SR/F, 15.6 kWh nominal and a Z-Force ZF15.6 pack. The gate is unchanged, and still only opens when the model is null.
| Char | Bikes | Nominal pack |
|---|---|---|
| Z | FST sport (S/F, SR, SR/F, SR/S) | 15.6 kWh (unattested) |
| D | FST adventure (DSR/X) | 17.3 kWh |
The character fixes the pack, never the model. Three different sport bikes share the Z character and the same nominal pack. No VIN Breakdown sheet prints a pack size for any FST code, so the capacities here come from the model spec sheets and from charge telemetry — legitimate sources, but not this one, and the column says so.
| Family code | Model |
|---|---|
| ZFS | S/F |
| ZFD | SR/F |
| ZFE | SR/S |
| ZFG | SR |
| DZA | DSR/X |
| DZB | DSR |
| DZS | DS |
An unknown family code leaves the model null rather than guessing — the earlier position-4-only shortcut mislabelled the S/F, SR/S, DSR and DS.
| Family code | Model | Nominal pack | Source |
|---|---|---|---|
| DZA | DSR/X | 17.3 kWh (unattested) | |
| DZB | DSR | 17.3 kWh (unattested) | corpus only |
| DZS | DS | 17.3 kWh (unattested) | corpus only |
| ZFS | S/F | 15.6 kWh (unattested) | |
| ZFD | SR/F | 15.6 kWh (unattested) | |
| ZFE | SR/S | 15.6 kWh (unattested) | |
| ZFG | SR | 15.6 kWh (unattested) | |
| XXF | FXE | 7.2 kWh (unattested) |
Applied only as a fallback, when the ordinary 538 decode left the model null. Gen1 and Gen2 538 VINs never reach it. The pack sizes are marked unattested for the same reason as the PAG table above: Zero prints model lines for these codes and no capacity beside them. An empty Source cell means the code is printed in one of Zero’s own VIN Breakdown sheets, which is the plurality of this table; the marked rows are the ones that are not. "community only" means the zero-motorcycle-community decoder has it and no manual we hold does; "corpus only" means a real VIN in our logs wears it and no document attests it; "unattested" means we publish it and nothing supports it.
Nominal, not usable
Every capacity in these tables is nameplate. A ZF14.4 pack does not hold 14.4 kWh of usable energy, and a pack that has been in service for six years holds less again. The VIN describes what left the factory.
Where these tables stop
Two gaps, stated so you do not read a null as a fact about your motorcycle. First, the 2026 light line — LS1, XE and XB — has no model-line code, no position-12 designator and no spec sheet here. The XE and XB at least identify themselves: they carry the A4Z identifier, so the decoder returns a manufacturer, a model year and the assembly plant and stops, which is the whole of what anyone can source for them today. The LS1 we have not seen a VIN for at all. The owner manuals put all three at product generation 3, the LS1 on LS · Cypher III and the XE and XB on X-line · Cypher III. Second, the manuals move the S, SR, DS and DSR from SDS · Z-Force (Cypher II) to FST · Cypher III at model year 2024, and our corpus holds no VIN of those models from 2024 or later — so this page cannot tell you which platform character they carry, and will not guess. A masked VIN from either group would settle it; the feedback form takes one.
Three VINs decoded position by position
The first two examples are real motorcycles from this project’s log corpus and the third is a real off-road machine found in the wild, all with two serial characters masked. The tables are generated by running each VIN through the same decoder the widget uses, so what you see here is what the code actually produces, not a hand-written illustration.
Gen2 on the 538 WMI
538XX8Z19GCJ05XX8
A 2016 FXS. Every field this decoder can fill comes from a different slice of the VIN: the platform from position 4, the model line from 5-6, the motor from 7-8, the year from 10, the plant from 11 and the model itself from position 12 — the position NHTSA does not read.
| Position | Chars | Field it sets | Decoder output |
|---|---|---|---|
| 1-3 | 538 | manufacturer | Zero Motorcycles |
| 4 | X | platform | XMX |
| 5-6 | X8 | model_line + pack | FX/FXS |
| 7-8 | Z1 | motor_power + motor_size | 13kW |
| 9 | 9 | check digit (not used by the decoder) | regulation computes 1 — this VIN is masked |
| 10 | G | year | 2016 |
| 11 | C | plant_location | Scotts Valley, CA, USA |
| 12 | J | model | FXS |
| 13-17 | 05XX8 | nothing | sequential serial, two characters masked |
decodeVin() returns is_valid = true for this VIN, with no error.
Gen3 on the PAG WMI
PAGDZAZ87RP00XX54
A 2024 DSR/X. The PAG branch of the decoder returns early: it resolves the model from the three-character family code at positions 4-6, the pack size from the platform character at position 4 and the plant from position 11, then stops. Model line and motor stay null by design, because the 538 tables do not apply to a PAG VIN. The plant used to be null too — the branch returned before position 11 — which is why the only bike in the corpus actually built in the Philippines was the one reporting no plant.
| Position | Chars | Field it sets | Decoder output |
|---|---|---|---|
| 1-3 | PAG | manufacturer | Zero Motorcycles |
| 4 | D | platform + pack | FST, 17.3 kWh |
| 4-6 | DZA | model (family code) | DSR/X |
| 7-8 | Z8 | motor_power + motor_size | not read on this branch |
| 9 | 7 | check digit (not used by the decoder) | regulation computes 1 — this VIN is masked |
| 10 | R | year | 2024 |
| 11 | P | plant_location | not read on this branch |
| 12 | 0 | model | carries no model on a PAG VIN |
| 13-17 | 0XX54 | nothing | sequential serial, two characters masked |
decodeVin() returns is_valid = true for this VIN, with no error.
Off-road on the A4Z PIN
A4ZLLSL15TZ0000XX
A 2026 XE, and the example that shows what a deliberate refusal looks like. A4Z is a real Zero identifier, so the decode succeeds and fills the two fields that are positional under 49 CFR 565 rather than Zero-specific — the model year and, from A4Z's own plant set, the assembly plant. Everything else is left null on purpose: positions 4-8 read LLSL1 here, which shares no vocabulary at all with the 538 tables, and position 12 is a serial digit rather than a model letter. This VIN is not from our log corpus; it is one of three found in the wild and confirmed against NHTSA vPIC.
| Position | Chars | Field it sets | Decoder output |
|---|---|---|---|
| 1-3 | A4Z | manufacturer | Zero Motorcycles |
| 4-8 | LLSL1 | nothing | A4Z descriptor codes; no table published for them |
| 9 | 5 | check digit (not used by the decoder) | regulation computes 9 — this VIN is masked |
| 10 | T | year | 2026 |
| 11 | Z | plant_location | Banan District, Chongqing, China |
| 12-17 | 0000XX | nothing | six-digit sequential serial, two characters masked |
decodeVin() returns is_valid = true for this VIN, with no error. It also carries a note: “Zero Motorcycles X-line (off-road). This VIN uses a different code table from the 538/PAG road bikes, so the model, model line, motor and battery are not decodable yet — only the model year and the assembly plant are positional and schema-independent.”
How far the tables get on a real fleet
Worked examples prove the mechanism but say nothing about coverage. Running all 23 distinct VINs from the corpus through the decoder gives a more honest picture of where the lookup tables run out.
| Field | Resolved | What the misses look like |
|---|---|---|
| Manufacturer and year | 23 / 23 | No misses: every WMI and every year code in the sample is covered. |
| Model | 23 / 23 | No misses — but read the model-year section above before treating that as evidence the tables are complete. |
| Motor power | 22 / 23 | PAGDZAZ87RP00XX54 (2024 DSR/X) — the PAG branch returns before positions 7-8 are read at all. |
| Plant | 23 / 23 | No misses. This row read 22 / 23 until the PAG branch was taught to read position 11 — it used to return before reaching it, so the one bike actually built in the Philippines was the only one reporting no plant at all. |
| Model line | 22 / 23 | PAGDZAZ87RP00XX54 (2024 DSR/X) — positions 5-6 are the back half of a three-character family code on a PAG VIN, not a model line, so there is nothing at 5-6 to look up. |
| Nominal pack size | 19 / 23 | 538XX8Z19GCJ05XX8 (2016 FXS); 538XX8Z1XGCJ06XX4 (2016 FXS); 538XXBZ48HCH06XX6 (2017 FXP); 538XXCZ4XKCJ11XX5 (2019 FXS) — the model-line code names a family that ships with one battery module or two, and the VIN does not say which. The BMS log does. |
Generated at build time by running the shipped decoder over every VIN in the corpus, so no figure here is transcribed. It reported is_valid on 23 of 23 and produced no errors. "Resolved" means the field came back non-null, not that it was independently verified against the bike. The pack misses are the honest kind: those bikes take one module or two, and a code that says only "FX or FXS" cannot say which. The BMS logs can. One of the two 2016 FXS in this set dumps both a BMS0 and a BMS1 file, which is a two-module pack; the other 2016 bike and the 2019 one dump a single BMS index; the FXP export in the corpus is MBB-only and carries no BMS file to read.
Read the Model row with the model-year section in mind
A clean sweep on Model across 23 bikes is a real measurement and a poor argument. Every documented case where Zero reuses a code falls before 2014, and the oldest motorcycle in this corpus is a 2014. The table above measures the tables against the bikes we happen to hold, and those bikes cannot exercise the failure the tables were redesigned to prevent.
What NHTSA vPIC gives you, and what it does not
Almost every consumer VIN decoder on the web is a wrapper around NHTSA’s vPIC API. It is free, it needs no key, and for Zero Motorcycles it is better than its reputation: it knows the make, the model year, the body class, a series name, a motor rating in kW, a battery size and an electrification level. If you only want to know what year a bike is, vPIC will tell you, and you should use it.
The problems are density and position 12. Here is the complete response profile for the masked 2016 FXS used as the first worked example above, so you can reproduce it exactly:
154 fields returned
100 empty
25 "Not Applicable"
29 carrying a value
---- the interesting ones ----
Make ZERO MOTORCYCLES
Manufacturer ZERO MOTORCYCLES, INC.
ModelYear 2016
Model FX, FXR, FXS, FXSR
Series Z2- XMX Platform
Trim FX ZF 3.3, ZF 6.5
EngineKW 13
EngineHP (empty)
DisplacementCC (empty)
BatteryKWh (empty)
VehicleDescriptor 538XX8Z1*GC
PossibleValues (12:2)
SuggestedVIN 538XX8Z19GC205!!8
ErrorText 1 - Check Digit (9th position) does not calculate
properly; 2 - VIN corrected, error in one position;
400 - Invalid Characters PresentErrors 1 and 400 are artefacts of the mask — XX in the serial breaks the check digit and is not numeric. Error 2 is not: it appears on the unmasked VIN too.
Six things that response tells you
Read line by line, the response explains both what vPIC is good for and where a Zero-specific table has to take over.
- Model comes back as a four-way ambiguity, "FX, FXR, FXS, FXSR", because vPIC resolves the model from positions 4-8 only. The bike is an FXS, and position 12 says so.
- VehicleDescriptor is 538XX8Z1*GC — eleven characters with position 9 wildcarded. Nothing after position 11 is part of vPIC’s key at all.
- PossibleValues is (12:2) and SuggestedVIN replaces the real position-12 character with 2. vPIC does not merely ignore position 12; it reports the manufacturer’s own model letter as a transcription error and proposes a different VIN.
- EngineHP, DisplacementCC and BatteryKWh are empty on this bike. Displacement is meaningless on an electric motorcycle, but horsepower and pack size are not, and neither is in what NHTSA holds for that model year.
- On newer models the submission is richer. The 2024 DSR/X returns BatteryKWh 18, BatteryType Lithium-Ion, EngineModel "75-10 5T", TopSpeedMPH 110, CurbWeightLB 545 and ABS Standard — but still no per-VIN pack code, and still nothing from position 12.
- vPIC pack figures are maxima including accessories. A 2021 SR/F returns BatteryKWh 18.0 with Trim "SR/F ZF14.4/ZF14.4 + Power Tank": 14.4 plus a 3.6 kWh Power Tank. The VIN itself says 14.4.
Use both
vPIC is authoritative for what the manufacturer submitted to the regulator, and it is the right source for make, year and regulatory class. A Zero-specific table is the only source for the model designator, the motor size string and the nominal pack code. Neither replaces the other, and the widget on this page does not query vPIC at all.
What a VIN cannot tell you
A VIN is a factory record. It is fixed at build and never updated, which makes it excellent for identity and unreliable for state. Five things in particular are routinely inferred from a Zero VIN and should not be.
- The battery pack fitted today. Packs and modules get swapped, under warranty and outside it, and an FX or FXS can leave the factory with one module and be running two a year later. The VIN still reports what shipped. The bike’s own BMS logs are the only source for what is in it now.
- Usable capacity. Every kWh figure in these tables is nameplate. Real usable energy is lower when new and lower again with age; our own measurements on a nominally 6.5 kWh FXS pack put the delivered figure near 3.9 kWh after years of service. A VIN cannot express degradation.
- Firmware. Cypher level, MBB and BMS firmware revisions, and any dealer-applied updates are all invisible to the VIN. On Gen2 bikes the same VIN can be running firmware that produces a completely different log format.
- Options and accessories. Power Tank, Charge Tank, Rapid Charger, heated grips, a taller screen, a changed final drive ratio — none of it is encoded. NHTSA sometimes lists an option in the Trim string, but that describes what the model could be ordered with, not what this bike has.
- Ownership, service history and open recalls. The VIN is the key you would use to look those up at a dealer; it does not contain them. For open recalls, NHTSA publishes a separate free lookup keyed on the same number.
Where the answers actually are
Everything the VIN cannot tell you is in the log files. Pack identity and module count come from the BMS log, real capacity from measured charge energy against state-of-charge gain, firmware from the MBB header, and fitted accessories from the charging power the bike actually draws. That is what the rest of this site does with an uploaded .bin file.
Prior art and how this table was assembled
The Zero owner community reverse-engineered most of this scheme long before we did, and the best single artefact is vin_decoder.php in the zero-motorcycle-community web-tools repository — a PHP form carrying model-line, motor, platform, plant and designator tables that overlap heavily with ours. It deserves better than the polite nod it used to get here. On the most recent pass through these tables it was the primary source for around ten corrections: the model-year code 8 = 2008, which we simply did not have; the three MY2011 model-line codes X0, X1 and E1; the five Gen1 horsepower bands at positions 7-8; the two MY2011 position-12 designators 1 and 2; and the fact that position 4 encodes a body style rather than a platform before MY2011, which moved a threshold in our code that had matched no source at all. Its year-keyed arrays are also the reason we know how many collisions a flat table was hiding.
It is also wrong in places, and the way it is wrong is instructive. On model-line code X5 it reads FX/FXLP where we read FXP/FXLP — and Zero’s own MY2014 FX owner’s manual prints "X5 = 14 MY FXP/FXLP", so our value stands and the community table is the one to correct. The same manual settles the reverse case in its favour on other codes. Neither source is authoritative on its own; the manual is, when it exists, and it does not exist before MY2014.
Our tables were checked against four further sources: Zero’s own VIN Breakdown sheets, of which we hold thirty-eight across model years 2014 to 2026, and which are the only reason this revision could correct anything; the decoder in this project’s backend, which is what writes the model and pack fields on every uploaded log; the model tags embedded in Gen3 MBB firmware headers, which independently confirm the family codes; and the 23 real VINs described above, including one whose battery telemetry decided a disagreement between two documents. Where the community tables and a real log disagree, the log wins; where a manual and a log disagree, we say so rather than choosing.
This page renders the lookup tables directly from the same TypeScript module the widget calls, which is itself generated from the Python decoder and checked in continuous integration — editing either side alone fails the build with a diff. There is no second copy to fall out of date, and the counts in the prose above are interpolated from those same tables rather than typed, because for a while the prose was the second copy. If you find a code we have wrong, or a VIN that decodes to the wrong bike, tell us — a masked VIN and the correct model is enough to fix it.
FAQ
Where is the VIN on a Zero Motorcycle?
Stamped on the steering head at the front of the frame, printed on the manufacturer label under the seat, and on the registration document. It is also written into the log files: the Gen2 MBB header carries it as ASCII text, and the Gen3 MBB header stores it null-terminated at offset 0x29, which is why an uploaded .bin usually identifies its own motorcycle.
What does a Zero VIN starting with 538 mean?
538 is Zero Motorcycles’ own World Manufacturer Identifier, registered with NHTSA to ZERO MOTORCYCLES, INC. and associated with the plant in Scotts Valley, California. It appears on the great majority of Zeros, including Gen1, Gen2 and many Gen3 machines.
Why does my Zero VIN start with PAG instead of 538?
PAG is a second World Manufacturer Identifier that NHTSA registers to INTEGRATED MICRO-ELECTRONICS, INC., with the make attributed to Zero Motorcycles and a plant in Binan, Laguna, Philippines. The record was created on 18 September 2023. A PAG VIN is a Zero built at that plant; it uses the same 17-position layout but a different code set from position 4 onwards, so a decoder must branch on the WMI before reading anything else.
Why does my Zero VIN start with A4Z?
Because it is not, strictly, a VIN. A4Z is a Product Identification Number that NHTSA has had registered to ZERO MOTORCYCLES, INC. since 18 January 2017, and Zero’s own Part 566 filing names it alongside the 538 World Manufacturer Identifier. It carries the off-road X-line: the real A4Z numbers we can find are 2026 XE and XB machines built in Banan District, Chongqing, and NHTSA decodes every one of them with an off-road warning saying the manufacturer did not certify the product to the Federal Motor Vehicle Safety Standards. It uses a different code set from position 4 onwards, so the decoder here recognises the identifier, returns the model year and the plant, and declines to guess a model from tables that do not apply.
How do I read the model year from a Zero VIN?
Take character 10 and look it up in the federal table of 49 CFR 565.15(d)(1). A is 2010 through J is 2018 — nine letters, because I is not a VIN character — then K is 2019 through Y is 2030, skipping O, Q and U. The digit 8 means 2008 and 9 means 2009. Model year is not the same as the build or registration date.
Was the 2015 Zero S really a 9.4 kWh bike?
Not if its VIN reads M7 at positions 5-6 — that is the 12.5 kWh build, and M8 is the 9.4. This page had the pair the wrong way round until recently, an error inherited from the community decoder, and the same transposition affected D7 and D8 on the 2015 DS. Zero’s MY2015 owner’s manual prints "M7 = 15 MY S/SR/SP (12.5)", and the one 2015 SR in our log corpus confirms it independently: its BMS amp-hour counter works out at 92.2 Ah for a full charge, which is 85 per cent of a ZF12.5 and more than a ZF9.4 could hold when new. If your bike’s pack size looks wrong in this app, re-upload a log or correct it in the garage — a stored value written before the fix is not updated automatically.
What is position 9 of a VIN and does Zero use it?
Position 9 is the check digit, a modulo-11 checksum over the other sixteen characters defined by 49 CFR 565.15(c). Zero computes it correctly: all 23 distinct VINs in this project’s log corpus pass the check, including three that use the letter X for a remainder of 10. Our own decoder does not verify it, so a mistyped VIN will still return a plausible answer.
Which character of a Zero VIN gives the model?
On a 538 VIN it is position 12: J is FXS, K is SR/F, L is SR/S, and so on across thirteen codes. One of them, G, covers more than one model and is resolved using the model year and the model line. On a PAG VIN position 12 carries no model information, and the model comes from the three-character family code at positions 4-6 instead. From MY2024 the field is gone from Zero's own diagrams altogether — the layout runs the plant character straight into the serial — so the decoder stops reading position 12 after MY2023 rather than eventually mistaking a serial digit for a model letter.
Can a VIN tell me my battery capacity or state of health?
It can give you the nominal pack size the bike shipped with, on most models, and nothing more. It cannot tell you which pack is fitted now — packs and modules get swapped — nor how much usable energy is left. Both of those come from the bike’s BMS log, by measuring energy delivered against state-of-charge change.
Why does the NHTSA decoder get my Zero’s model wrong?
Because vPIC builds its key from positions 1-8 and 10-11 only, and treats position 12 as part of the sequential serial, as the regulation literally reads. Zero puts its model designator there. On a 2016 FXS, vPIC returns the four-way "FX, FXR, FXS, FXSR", reports the real position-12 character as an error and proposes replacing it with 2.
Is anything sent to a server when I use the decoder on this page?
No. The lookup tables ship inside the page and the decode runs in your browser. There is no request, no logging and no analytics event attached to the VIN you type. You can confirm it by opening your browser’s network tab, or by disconnecting from the network and typing a VIN anyway.
The 538 and PAG vPIC responses quoted above were retrieved on 29 July 2026 and the A4Z ones on 30 July 2026; all are reproducible with the request URLs shown. If a field has changed since, the live API is the authority, not this page. Zero’s VIN Breakdown sheets are cited by file, printed page and figure number in the decoder source rather than linked, because they are PDFs distributed with the motorcycles rather than published documents. vPIC API
Sources:
- NHTSA vPIC API — vehicle and WMI decoding service
- NHTSA vPIC — WMI 538 record (ZERO MOTORCYCLES, INC.)
- NHTSA vPIC — WMI PAG record (INTEGRATED MICRO-ELECTRONICS, INC.)
- NHTSA vPIC — PIN A4Z record (ZERO MOTORCYCLES, INC.)
- NHTSA vPIC — Zero Motorcycles manufacturer details, quoting the Part 566 filing
- 49 CFR 565.15 — VIN content requirements, check digit and year codes (eCFR)
- 49 CFR 565.13 — VIN general requirements (eCFR)
- zero-motorcycle-community/web-tools — vin_decoder.php (prior art)
- NHTSA recall lookup by VIN
- ZeroManual — community wiki on Zero Motorcycles
This is an independent reference produced by Zero Logs Analyzer. It is not affiliated with, endorsed by or supported by Zero Motorcycles, Inc. The lookup tables are assembled from Zero’s own VIN Breakdown sheets, from community research, from public NHTSA data and from real log files, and are incomplete by construction. Do not use a decode from this page as proof of a motorcycle’s identity, specification or history.