China Unified Social Credit Code (USCC): Structure, Checksum Algorithm, and How to Validate It
If your system touches Chinese business data — KYC onboarding, e-invoice fields, supplier master data, CSV exports from a Chinese ERP — you have met the 18-character Unified Social Credit Code (统一社会信用代码, USCC). It looks like a random alphanumeric string, it is not hexadecimal, and its check digit is not Luhn. This post breaks down exactly how the code is built, how its checksum works, and where real-world copies of the code go wrong — everything here is verifiable with the USCC validator, which runs the same algorithm locally in your browser.
Why USCC trips up English-language systems
Three properties of the code routinely break validation logic written by people who assumed it behaves like Western identifiers:
- Not every letter is legal. Five letters —
I,O,S,V,Z— never appear. A naive[A-Z0-9]{18}regex accepts codes that can never exist, and worse, silently passes corrupted data downstream. - The checksum is mod 31, not mod 10 or 11. Luhn and ISO 7064 modulo-11 schemes (used for Chinese resident IDs and many European numbers) do not apply. Ported ID-card validators reject valid USCCs.
- Both
0andO-shaped confusions are one-directional. SinceOis excluded, everyOin your data is really a0that got "corrected" by a human or an OCR pipeline. ButU,W,YARE legal — stripping all vowels breaks valid codes.
The 18-character structure
| Position | Length | Field | Notes |
|---|---|---|---|
| 1 | 1 | Registration department | 1 编办 (public institutions), 5 民政 (social organizations), 9 工商/market regulation (enterprises), Y, N other |
| 2 | 1 | Organization category | Meaning depends on department; for 9: 1 enterprise, 2 individual business, 3 farmers' cooperative, 9 other |
| 3–8 | 6 | Registration authority code | Administrative-division shape (e.g. 110000 Beijing, 440300 Shenzhen) — a locality hint, not a postal code |
| 9–17 | 9 | Subject identifier | Organization code, effectively the unique serial body |
| 18 | 1 | Check character | Computed over positions 1–17 (algorithm below) |
An enterprise registered in Beijing therefore starts 91 11000 ...: department 9, category 1, authority 110000, then nine identifier characters and the check character.
The 31-character alphabet
GB 32100-2015 draws from exactly these characters:
0123456789ABCDEFGHJKLMNPQRTUWXY
That is digits 0-9 plus the letters A-Z minus I, O, S, V, Z — 31 characters total. The five exclusions remove visually confusable glyphs (I/1, O/0, S/5, V/U, Z/2). Two practical consequences:
- Lowercase input is always a transcription artifact — the standard is uppercase. Uppercasing before validation is safe and correct.
- A character-set rejection with the message "I, O, S, V, or Z found" is the single most useful error your form can show, because it tells the operator what was mistyped, not just that something was.
The checksum, exactly
Each of the first 17 characters maps to its index in the alphabet above (0→0, …, 9→9, A→10, B→11, …, Y→30). Each index is multiplied by a fixed weight, summed, and folded mod 31:
weights = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28]
check_index = (31 - (Σ alphabet_index(cᵢ) × weightᵢ) mod 31) mod 31
check_char = ALPHABET[check_index]
A detail almost no English-language writeup mentions: those weights are powers of 3 mod 31 (1, 3, 9, 27, 19=81 mod 31, 26=243 mod 31, …). Because 31 is prime and 3 is a primitive root mod 31, the weights cycle through all 30 nonzero residues — which is what makes single-character substitutions and many transpositions detectable. The check character itself can legitimately be any of the 31 characters, including 0; a validator that rejects a trailing 0 is wrong.
Worked example with a realistic enterprise shape — take the 17-char body 91110000MA01AB9C7:
- Convert each character to its alphabet index, multiply by the matching weight, and sum. For the first four:
9×1 +1×3 +1×9 +1×27 = 48; continue through position 17 the same way (the full sum for this body is 1761). 1761 mod 31 = 25;31 − 25 = 6; alphabet index 6 is6.
So the valid code is 91110000MA01AB9C76. Change any one character of the body — say MA01 to MAO1 (a letter O, illegal anyway) or MA01 to MB01 (legal characters, wrong code — its correct check character would be 8, not 6) — and the recomputed check character no longer matches. You can verify this end-to-end, including the parse of department and category, in the USCC validator.
How real-world copies get corrupted
In data-cleaning work these five failure modes cover almost everything:
| Symptom | Usual cause | Fix |
|---|---|---|
Contains I, O, S, V or Z | OCR or human "autocorrect" (an O was a 0, an I was a 1) | Map O→0, I→1 only when re-validating; never blanket-strip |
Full-width characters (9, M) | Copied from a Chinese IME field or PDF | Normalize width before validating (NFKC) |
| 17 or 19 characters | Trailing check character clipped by a narrow form field, or a bank-account number pasted alongside | Re-count; 18 is non-negotiable |
| Embedded space or newline | Excel cell wrap / PDF line break inside the code | Trim whitespace between characters, then re-validate |
| All-valid charset, checksum fails | A real typo in the body (the check digit is doing its job) | Do not "repair" the check digit — route to manual review |
The last row matters most: recomputing and overwriting the 18th character is a classic anti-pattern. It produces a format-valid code that identifies nothing, and the corruption becomes invisible to every later check.
What validation can and cannot tell you
A USCC that passes the alphabet and checksum checks is well-formed. It does not prove the code exists in the national registry, that the entity is still active, or that it matches the company name next to it in your spreadsheet. Registry status lives with 国家企业信用信息公示系统 (the National Enterprise Credit Information Publicity System) and requires a lookup this site deliberately does not perform — the validator checks format only, entirely in your browser, which is also why pasting codes into it leaks nothing.
If you build test fixtures for a system that consumes USCCs, you want codes that are checksum-valid but provably synthetic. The China test data generator produces exactly that — random bodies with a correctly computed check character, biased toward realistic 91-prefixed enterprise shapes. For format rules of other China identifiers (license plates, resident IDs), see our China plate format guide.
FAQ
Is the USCC the same as the old 组织机构代码 (organization code)? No. The 9-character organization code was folded in as positions 9–17 of the USCC when GB 32100 unified business registration in 2015. Legacy data may carry the old 9-char code (with its own ISO 7064 mod-11 check) in a field labeled as if it were the new one — a classic migration bug.
Can a USCC start with a digit?
Yes — 1, 5, and 9 are the most common first characters. Anything claiming codes must start with a letter is confusing USCC with something else.
Are lowercase usccs valid? The standard is uppercase; lowercase in your data is a transcription artifact. Uppercase, then validate.
Why does my bank's fields say 20 characters for the code? Their field is padding or storing a composite (code + name). The code itself is exactly 18.
Does the checksum catch every error? It catches all single-character substitutions and most transpositions (by construction of the weight sequence), but like any checksum it can be defeated by adversarial input. For identity assurance, use the registry — not the checksum.
Implementation notes
We ship the validator's exact reference implementation in the tool's source: a 31-char constant 0123456789ABCDEFGHJKLMNPQRTUWXY, a 17-entry weight table, and one accumulator loop. Two things we learned building it: the weight table must be written in alphabet-index space (1-based powers of 3 mod 31), not character-value space — off-by-one here passes ~1/31 of invalid codes, which survives spot checks; and (31 - (sum % 31)) % 31 needs the outer mod, because sum % 31 == 0 must map to check character 0, not to index 31 (out of range). Both bugs we saw in open-source validators we tested against while building ours.
Related Tools
Related Articles
How Color-Blind Users See Your Palette: A Six-Type Self-Check and Safe Colors
What does your UI look like to the 8% of men with color vision deficiency? The six types (protanopia/deuteranopia/tritanopia, both anomalies, achromatopsia), matrix-based simulation, a three-pair self-check list, and the WCAG practice of never encoding meaning in color alone.
Markdown to Word: Native Style Mapping and the Inline-Format Downgrade List
Turning a Markdown draft into a deliverable .docx: pandoc CLI vs in-browser local conversion, how headings/tables/code blocks map to native Word styles, which inline formats degrade to plain text, and why 'editable' beats 'looks right'.
Word to Markdown: Two Clean Paths and What Survives the Conversion
How to convert .docx to Markdown cleanly: pandoc CLI vs in-browser local conversion, a format fidelity table for headings/tables/images/auto-numbering, and fixes for the .doc legacy format, image bloat, and merged-cell tables.