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 — and an honest account of the four fields the number cannot tell you.
TL;DR
- Zero uses two World Manufacturer Identifiers. 538 is 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.
- 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.
- Position 10 uses 22 codes here, covering 2009 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.
- All 21 distinct VINs in this project’s log corpus carry a check digit that satisfies the 49 CFR 565.15(c) algorithm, 21 of 21. 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.
- 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 21 VINs in our corpus have digits in positions 13 through 17.
| Position | Name | What Zero puts there |
|---|---|---|
| 1-3 | World Manufacturer Identifier | 538 (Zero Motorcycles, Inc.) or PAG (Integrated Micro-Electronics, Inc.) |
| 4 | Platform | S = SDS street, X = XMX, Z = FST sport, D = FST adventure |
| 5-6 | Model line and pack | 60 known two-character codes, e.g. M7, DJ, XF, FA |
| 7-8 | Motor | 12 known codes, e.g. Z1 = 13 kW, Z8 = 52 kW, ZA = 11 kW 75-5 |
| 9 | Check digit | Computed from the other 16 characters per 49 CFR 565.15(c) |
| 10 | Model year | 22 known codes, 9 = 2009 through Y = 2030 |
| 11 | Plant | C on 20 of our 21 sample VINs; P on the single PAG bike |
| 12 | Model designator | 10 known codes, e.g. J = FXS, K = SR/F, L = SR/S |
| 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. The regulation fixes only positions 1-3, 9 and 10; everything else in this column is Zero’s own scheme, reverse-engineered from 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: two WMIs, 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, 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 2009.
{"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 two WMIs
Four things follow from those two 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.
- Anything that is neither 538 nor PAG is not a Zero. The decoder treats an unrecognised WMI as a hard error rather than an unknown, and returns "Unknown manufacturer WMI: XXX".
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 20 of 21 VINs are 538, and five of those 20 are Gen3 FST-platform machines. A 538 prefix tells you nothing about the generation; the family code at positions 4-6 does.
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 (S before 2013) | Street: S, SR, DS, DSR. 9 of our 21 sample VINs. |
| X | XMX (X before 2013) | Light off-road and supermoto: FX, FXS, FXP, FXE. 6 of 21. |
| Z | FST | Gen3 sport: S/F, SR, SR/F, SR/S. 5 of 21. |
| D | FST | Gen3 adventure: DS, DSR, DSR/X. 1 of 21. |
The 2013 threshold is real code, not editorial: the decoder returns the bare letter as the platform name for model years up to 2012 and the three-letter name after. Read "Gen3" here as the chassis platform this VIN character names, not as the log-format generation: the character tells you which platform Zero built the bike on, and it does not decide how the diagnostic files are framed. The FXE sits under X = XMX by its VIN while its logs are handled as Gen3.
Positions 5-6: model line and nominal pack
Sixty two-character codes are known. The code carries the family (S, DS, FX, XU and their variants) and, for most of the range, the nominal pack size in kWh. A few 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 21 real VINs we can check, 19 hit a known model-line code; the two misses are Gen3 machines whose descriptor uses the family scheme described further down, not the 538 model-line scheme.
The capacity in this table is what turns into a pack name elsewhere in the app. 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. Thirteen pack sizes are recognised, and every one of them is a 28-cell-group series string.
| Code | Model line | Nominal pack | Motor from this code |
|---|---|---|---|
| M2 | S | not encoded | from positions 7-8 |
| M3 | S | not encoded | from positions 7-8 |
| M4 | S/SR/SP | 8.5 kWh | from positions 7-8 |
| M5 | S/SR/SP | 11.4 kWh | from positions 7-8 |
| M7 | S/SR/SP | 9.4 kWh | from positions 7-8 |
| M8 | S/SR/SP | 12.5 kWh | from positions 7-8 |
| M9 | S/SR/SP | 13.0 kWh | from positions 7-8 |
| M0 | S/SR/SP | 9.8 kWh | from positions 7-8 |
| 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 |
| ME | S | 7.2 kWh | 11kW |
| MF | S/SR | 14.4 kWh | from positions 7-8 |
| MG | S | 14.4 kWh | 11kW |
| MH | S | 7.2 kWh | 11kW |
| MK | S | 14.4 kWh | 11kW |
| ML | S/SR | 14.4 kWh | from positions 7-8 |
| MM | S | 7.2 kWh | 11kW |
| MN | S | 14.4 kWh | 11kW |
| D2 | DS | not encoded | from positions 7-8 |
| D3 | DS | not encoded | from positions 7-8 |
| D4 | DS | not encoded | 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 |
| D7 | DS/DSR/DSP | 9.4 kWh | from positions 7-8 |
| D8 | DS/DSR/DSP | 12.5 kWh | from positions 7-8 |
| D9 | DS/DSR/DSP | 13.0 kWh | from positions 7-8 |
| D0 | DS/DSR/DSP | 9.8 kWh | from positions 7-8 |
| DA | DS | 6.5 kWh | from positions 7-8 |
| DB | DS/DSR/DSP/DSRP | 13.0 kWh | from positions 7-8 |
| DC | DS | 7.2 kWh | 11kW |
| DD | DS/DSR | 14.4 kWh | from positions 7-8 |
| DE | DS | 14.4 kWh | 11kW |
| DF | DS | 7.2 kWh | 11kW |
| DH | DS | 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 | not encoded | from positions 7-8 |
| X2 | MX | not encoded | from positions 7-8 |
| X3 | FX | not encoded | from positions 7-8 |
| X4 | FX/FXL | not encoded | from positions 7-8 |
| X5 | FXP/FXLP | not encoded | from positions 7-8 |
| X6 | FX/FXS | not encoded | from positions 7-8 |
| X7 | FXP | not encoded | from positions 7-8 |
| X8 | FX/FXS | not encoded | from positions 7-8 |
| X9 | FXP | not encoded | from positions 7-8 |
| XA | FXS | 6.5 kWh | from positions 7-8 |
| XB | FX/FXS/FXP | not encoded | from positions 7-8 |
| XC | FX/FXS/FXP | not encoded | 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 | from positions 7-8 |
| C2 | XU-LSM (CA) | not encoded | from positions 7-8 |
| L2 | XU-M (EU) | not encoded | from positions 7-8 |
| U1 | XU | not encoded | from positions 7-8 |
| U2 | XU | not encoded | from positions 7-8 |
| U3 | XU | not encoded | from positions 7-8 |
| FA | SR/F | 14.4 kWh | from positions 7-8 |
| FB | SR/S | 14.4 kWh | from positions 7-8 |
| FD | SR/F | 15.6 kWh | from positions 7-8 |
| FE | SR/S | 15.6 kWh | 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.
| 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 a Zero pack sits near 116 V nominal.
Positions 7-8: motor
Twelve codes. The first character is almost always Z; the second selects power and, where known, the Z-Force motor size. Size and power are separate axes: 75-7 and 75-7R each appear at both 16 kW and 21 kW in the table, so the R suffix is a variant marker rather than a power tier. The three highest codes all sit on the 75-10R at 40, 52 and 82 kW.
Note that these figures are the motor rating encoded in the VIN, which for the older bikes is the sustained rather than peak number. A 2016 FXS decodes to 13 kW from its VIN while its published peak is 33 kW; both are true of the same motor.
| Code | Rated power | Z-Force motor | Variant |
|---|---|---|---|
| M3 | 9.1kW | not encoded | size not encoded |
| 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 | 21kW | 75-7R | R variant |
| Z7 | 40kW | 75-10R | R variant |
| Z8 | 52kW | 75-10R | R variant |
| Z9 | 82kW | 75-10R | R variant |
Rendered from MOTORS_BY_CODE. The rated figure is what the VIN encodes, which on the older bikes is the sustained rather than the peak number.
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: 21 of 21
We ran the algorithm over every distinct VIN in this project’s log corpus — 21 unique motorcycles across 327 log files, spanning model years 2014 to 2024, both WMIs and all four platform characters. Every one satisfies the check digit. One of them uses 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 fifteen letters covering 2019 to 2030, skipping O, Q, U and Z.
- Our table carries 22 codes, from 9 = 2009 to Y = 2030. It stops there deliberately: the regulation wraps to numerals in 2031, and a decoder that guessed would silently mislabel a bike.
- 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 |
|---|---|---|---|---|---|
| 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 | ||
| G | 2016 | R | 2024 |
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 of the 21 VINs in our corpus carry C; the single PAG bike carries P.
Our decoder maps C to "Santa Cruz, CA" and leaves every other character null. NHTSA, for the same VINs, reports PlantCity SCOTTS VALLEY, PlantState CALIFORNIA and PlantCompanyName "Zero Motorcyles Inc." — the misspelling is in the federal dataset, not a typo here. Scotts Valley is in Santa Cruz County, a few kilometres from Santa Cruz itself, and Zero has been associated with both addresses; treat the two answers as the same plant.
For PAG VINs the decoder returns early and never reads position 11 at all, so plant_location stays null. NHTSA fills the gap from the WMI instead, reporting BINAN, LAGUNA, PHILIPPINES.
One character is not much of a sample
With C on 20 of 21 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.
| Code | Model | Resolves on its own? |
|---|---|---|
| A | S | yes |
| B | DS | yes |
| C | FX | yes |
| E | XU | yes |
| G | SR/DSR | no — see the rules below |
| H | FXP | yes |
| J | FXS | yes |
| K | SR/F | no — see the rules below |
| L | SR/S | no — see the rules below |
| M | FXE or DSR/X | no — see the rules below |
The two ambiguous designators
Two of the ten codes cover more than one model, and the decoder applies a fixed rule to each. These rules are worth stating because they are the part of the decode most likely to be wrong on an unusual bike.
| Code | Raw value | Rule | Outcome |
|---|---|---|---|
| M | FXE|DSR/X | Split on the platform resolved from position 4 | XMX platform gives FXE; anything else gives DSR/X |
| 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.
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 21 corpus VINs comply.
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 model line, motor and plant are left null because the 538 tables do not apply. 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. One corpus VIN is a Gen3 SR/F on a 538 WMI whose positions 5-6 are FD, a code absent from the 60-entry model-line table — but position 12 is K, which resolves the model to SR/F on its own, so the family fallback never runs and the bike ends up with a null model line and a null pack size.
| Char | Bikes | Nominal pack |
|---|---|---|
| Z | FST sport (S/F, SR, SR/F, SR/S) | 15.6 kWh |
| 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.
| 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 |
|---|---|---|
| DZA | DSR/X | 17.3 kWh |
| DZB | DSR | 17.3 kWh |
| DZS | DS | 17.3 kWh |
| ZFS | S/F | 15.6 kWh |
| ZFD | SR/F | 15.6 kWh |
| ZFE | SR/S | 15.6 kWh |
| ZFG | SR | 15.6 kWh |
| XXF | FXE | 7.2 kWh |
Applied only as a fallback, when the ordinary 538 decode left the model null. Gen1 and Gen2 538 VINs never reach 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.
Two VINs decoded position by position
Both examples below are real motorcycles from this project’s log corpus, 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 | Santa Cruz, CA |
| 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 and the pack size from the platform character at position 4, then stops. Model line, motor and plant stay null by design, because the 538 tables do not apply to a PAG VIN.
| 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.
How far the tables get on a real fleet
Two worked examples prove the mechanism but say nothing about coverage. Running all 21 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 | 21 / 21 | No misses: both WMIs and all sample year codes are covered. |
| Model | 21 / 21 | Position 12 or, on Gen3, the family-code fallback catches every one. |
| Motor power | 20 / 21 | The single PAG VIN, whose early return never reads positions 7-8. |
| Plant | 20 / 21 | Same PAG VIN, for the same reason. |
| Model line | 19 / 21 | The PAG VIN, plus one Gen3 538 bike whose FD code is not in the table. |
| Nominal pack size | 17 / 21 | Three FX-family bikes whose model-line codes carry no capacity, plus the same Gen3 538 bike. |
The decoder reported is_valid on 21 of 21 and produced no errors. "Resolved" means the field came back non-null, not that it was independently verified against the bike.
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 and motor code tables that overlap heavily with ours. It is worth reading, and it is worth knowing its limits: it is a script rather than a document, so none of the tables inside it are legible without opening the source, and none of it is indexable, which is a large part of why this page exists.
Our tables were checked against three further sources: 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 21 real VINs described above. Where the community tables and a real log disagree, the log wins.
This page renders the lookup tables directly from the same TypeScript module the widget calls, which in turn mirrors the Python decoder. There is no second copy to fall out of date. 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.
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, U and Z. The digit 9 means 2009. Model year is not the same as the build or registration date.
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 21 distinct VINs in this project’s log corpus pass the check, including one that uses 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 ten codes. Two of the ten cover more than one model and are resolved using the platform character or the model year. 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.
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 vPIC responses quoted above were retrieved on 29 July 2026 and are reproducible with the request URLs shown. If a field has changed since, the live API is the authority, not this page. 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.)
- 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 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.