Container Code Validation in Node.js — ISO 6346 Explained
Every shipping container crossing the ocean carries a unique 11-character code governed by ISO 6346. Here's how the standard works, what each part of the code means, how the mod-11 check digit catches transposition errors, and how to validate container codes in your Node.js application.
In this guide
1. What is ISO 6346?
ISO 6346 is an international standard that defines the coding, identification, and marking of shipping containers used in intermodal freight transport. Published by the International Organization for Standardization, it assigns each container a globally unique 11-character code consisting of letters and digits.
The standard is maintained by the Bureau International des Containers (BIC), which operates the global registry of owner codes. Every container manufacturer, leasing company, and shipping line must register its owner code with BIC before putting containers into service.
In logistics software, container codes appear in bills of lading, customs declarations, terminal operating systems, and vessel manifests. A single transposition error can route a container to the wrong yard, delay customs clearance, or generate phantom inventory.
2. Anatomy of a container code
An ISO 6346 container code has exactly 11 characters, split into four parts:
Owner Code
CSQ
3 letters — BIC-registered
Category
U
1 letter — equipment type
Serial Number
305438
6 digits — unique per owner
Check Digit
3
1 digit — mod-11 validation
3. The mod-11 check digit algorithm
ISO 6346 uses a weighted mod-11 algorithm. Each of the first 10 characters is assigned a numeric value, multiplied by a power-of-2 weight, and the sum modulo 11 produces the check digit. If the result is 10, it is mapped to 0.
Let's walk through CSQU3054383:
Step 1 — Convert letters to numbers
Letters are mapped: A=10, B=12, C=13, D=14, ... skipping multiples of 11 (11, 22, 33). So A=10, B=12, C=13, ..., K=21, L=23, ..., and so on. Digits 0-9 keep their face value.
| Character | C | S | Q | U | 3 | 0 | 5 | 4 | 3 | 8 | 3 |
| Value | 13 | 30 | 28 | 32 | 3 | 0 | 5 | 4 | 3 | 8 | ? |
Step 2 — Multiply by powers of 2
| Weight (2^i) | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | — |
| Product | 13 | 60 | 112 | 256 | 48 | 0 | 320 | 512 | 768 | 4096 | ? |
Step 3 — Sum and apply mod 11
13 + 60 + 112 + 256 + 48 + 0 + 320 + 512 + 768 + 4096 = 6185
6185 % 11 = 3
Check digit is 3 — matches the 11th character of CSQU3054383
// containerCheckDigit.js — ISO 6346 mod-11 check digit function validateContainerCode(code) { code = code.toUpperCase().replace(/[\s-]/g, ''); if (!/^[A-Z]{3}[UJZR]\d{7}$/.test(code)) return false; // Letter-to-number mapping: A=10, B=12, C=13, ... (skip multiples of 11) function charValue(ch) { if (ch >= '0' && ch <= '9') return parseInt(ch, 10); const n = ch.charCodeAt(0) - 'A'.charCodeAt(0); // value = 10 + n + floor((n + 8) / 10) — skips 11, 22, 33 return 10 + n + Math.floor((10 + n) / 11); } let sum = 0; for (let i = 0; i < 10; i++) { sum += charValue(code[i]) * Math.pow(2, i); } const checkDigit = sum % 11 % 10; // if mod-11 gives 10, map to 0 return checkDigit === parseInt(code[10], 10); } console.log(validateContainerCode('CSQU3054383')); // true ✓ console.log(validateContainerCode('CSQU3054384')); // false ✗ wrong check digit console.log(validateContainerCode('MAEU1234567')); // checks dynamically
4. Category codes — U, J, Z, R
The fourth character of a container code identifies the type of equipment. ISO 6346 defines four category identifiers:
| Code | Category | Description |
|---|---|---|
| U | Freight container | Standard dry, high-cube, open-top, flat-rack, and other general-purpose containers |
| J | Detachable equipment | Detachable freight container-related equipment such as generator sets |
| Z | Trailer / Chassis | Trailers and chassis used in intermodal transport |
| R | Reefer container | Refrigerated containers with integrated cooling units |
U (freight container). Category R for reefers is less common in ISO 6346 markings because many reefer containers are still marked with U and identified as reefers through their ISO size-type code instead.5. Why container code validation matters
Customs and regulatory compliance
Customs authorities worldwide require valid container codes on all import/export declarations. An invalid code will cause the declaration to be rejected, delaying cargo clearance and potentially incurring demurrage charges.
Terminal operating systems
Port terminals use container codes to track containers through gate-in, yard placement, vessel loading, and gate-out. A mistyped code creates phantom entries in the yard plan — operators search for a container that appears to exist but cannot be physically located.
BIC registry and owner identification
The three-letter owner code is registered with BIC (Bureau International des Containers). Validating the check digit confirms the code was transcribed correctly, but does not confirm the owner code is registered. For owner verification, a separate BIC registry lookup is needed.
Supply chain visibility
Freight forwarders, 3PLs, and BCOs track containers across multiple carriers and modes. A single digit error in a container code breaks the tracking chain and makes the shipment invisible until someone manually reconciles the records.
6. The production-ready solution
The IsValid Container Code API validates the format, computes the ISO 6346 mod-11 check digit, and returns the parsed components — owner code, category, serial number, and check digit — in a single call.
Full parameter reference and response schema: Container Code Validation API docs →
7. Node.js code example
import { createClient } from '@isvalid-dev/sdk'; const iv = createClient({ apiKey: process.env.ISVALID_API_KEY }); // ── Example usage ──────────────────────────────────────────────────────────── const result = await iv.containerCode('CSQU3054383'); if (!result.valid) { console.log('Invalid container code'); } else { console.log('Owner code:', result.ownerCode); // → 'CSQ' console.log('Category:', result.categoryName); // → 'Freight container' console.log('Serial:', result.serialNumber); // → '305438' console.log('Check digit:', result.checkDigit); // → '3' }
In a cargo manifest processing pipeline:
// Validate container codes in a vessel manifest async function processManifest(containers) { const results = []; for (const entry of containers) { if (!entry.containerCode) { results.push({ ...entry, status: 'missing' }); continue; } const check = await validateContainerCode(entry.containerCode); if (!check.valid) { results.push({ ...entry, status: 'invalid' }); continue; } results.push({ ...entry, containerCode: entry.containerCode.toUpperCase().replace(/[\s-]/g, ''), ownerCode: check.ownerCode, category: check.categoryName, serialNumber: check.serialNumber, status: 'valid', }); } return results; }
CSQU 305438-3.8. cURL example
Validate a standard freight container:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/container-code?value=CSQU3054383"
Validate a container with an invalid check digit:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/container-code?value=CSQU3054380"
Validate a reefer container:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/container-code?value=TRIU4567890"
9. Understanding the response
Valid container code:
{ "valid": true, "ownerCode": "CSQ", "categoryCode": "U", "categoryName": "Freight container", "serialNumber": "305438", "checkDigit": "3" }
Invalid container code:
{ "valid": false }
| Field | Type | Description |
|---|---|---|
| valid | boolean | Format correct, category valid, mod-11 check digit passes |
| ownerCode | string | 3-letter BIC owner code (e.g. "CSQ", "MAE", "MSC") |
| categoryCode | string | Single letter: U, J, Z, or R |
| categoryName | string | Human-readable category name (e.g. "Freight container") |
| serialNumber | string | 6-digit serial number assigned by the owner |
| checkDigit | string | Single check digit (0-9) computed via mod-11 |
10. Edge cases — tanks, reefers, and more
Tank containers
ISO tank containers (for liquids, gases, and powders) use the same coding scheme with category U. They are distinguished from dry containers by the ISO size-type code painted on the container (e.g. 22T0 for a standard tank), not by the owner/category code.
Reefer containers and the R category
While ISO 6346 defines R for reefer containers, in practice most reefer containers carry a U category code. The reefer nature is identified by the size-type code (e.g. 45R1). Your validation should accept both U and R for reefer containers.
Check digit 10 → 0 mapping
When the mod-11 computation yields 10, the check digit is mapped to 0. This is a known edge case — approximately 1 in 11 containers will have this mapping. If your validation logic does not handle this, it will incorrectly reject valid containers.
// The critical line in the check digit calculation: const checkDigit = sum % 11 % 10; // double-mod handles 10 → 0
Lowercase and formatting variants
Container codes may arrive from OCR systems, manual data entry, or EDI messages in mixed case or with embedded spaces/hyphens. Always normalise to uppercase and strip non-alphanumeric characters before validation. The code csqu 305438-3 is the same container as CSQU3054383.
Summary
See also
Validate container codes instantly
Free tier includes 100 API calls per day. No credit card required. Full ISO 6346 validation with parsed owner code, category, and check digit.