DEV Community

Cover image for How to validate SSCC codes, check digit algorithm, EDIFACT extraction and free API
Pedro
Pedro

Posted on

How to validate SSCC codes, check digit algorithm, EDIFACT extraction and free API

After 18 years working with EDI and supply chain systems, I've lost count of how many times I've had to validate an SSCC, Serial Shipping Container Code. Every time, it was either a one-off script, a colleague with a spreadsheet, or a paid tool hidden behind a login wall.

So I built SSCC Pro Vision, a free, open-source validator that runs entirely in the browser. No backend, no login, no cost. And while I was at it, I wrote up everything I know about SSCCs.


What is an SSCC?

The Serial Shipping Container Code is an 18-digit GS1 identifier used to uniquely identify a logistic unit, a pallet, box, roll cage, anything you ship. It's encoded in a GS1-128 barcode and transmitted in EDI messages like DESADV (Despatch Advice) and IFTMIN (Forwarding Instruction).

(00) E XXXXXXXXXXXXXXXXX C
      │ │               │ └─ Check digit
      │ │               └─── GCP + Serial reference
      │ └─────────────────── GS1 Company Prefix
      └───────────────────── Extension digit
Enter fullscreen mode Exit fullscreen mode

The (00) is the Application Identifier, it tells any GS1-compliant system that what follows is an SSCC. It's not part of the 18 digits.


The check digit algorithm

SSCCs use the standard GS1 Modulo-10 algorithm. Given a 17-digit body:

  1. Starting from the rightmost digit, multiply alternating digits by 3 and 1
  2. Sum all products
  3. Check digit = (10 − (sum mod 10)) mod 10

Worked example

Body: 35601234560000001

Position (from right) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Digit 1 0 0 0 0 0 0 6 5 4 3 2 1 0 6 5 3
Multiplier 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3
Product 3 0 0 0 0 0 0 6 15 4 9 2 3 0 18 5 9

Sum = 74 → Check digit = (10 − (74 mod 10)) mod 10 = (10 − 4) mod 10 = 6

Full SSCC: (00) 356012345600000016 🇵🇹


JavaScript implementation

Here's a clean, dependency-free implementation using BigInt to safely handle large numbers:

/**
 * Calculate the GS1 check digit for a 17-digit SSCC body.
 */
function getCheckDigit(body17) {
    let sum = 0;
    const digits = body17.split('').reverse();
    for (let i = 0; i < digits.length; i++) {
        sum += parseInt(digits[i]) * (i % 2 === 0 ? 3 : 1);
    }
    return (10 - (sum % 10)) % 10;
}

/**
 * Validate an 18-digit SSCC.
 */
function validateSSCC(sscc18) {
    const digits   = sscc18.replace(/\D/g, '');
    if (digits.length !== 18) throw new Error('SSCC must be 18 digits');

    const body     = digits.substring(0, 17);
    const provided = parseInt(digits[17]);
    const expected = getCheckDigit(body);

    return { valid: provided === expected, provided, expected };
}

/**
 * Normalise any SSCC input, handles 17, 18 and 20-digit formats.
 */
function normaliseSSCC(raw) {
    const d = raw.replace(/\D/g, '');
    if (d.length === 17) return d + getCheckDigit(d);     // generate CD
    if (d.length === 18) return d;                         // full SSCC
    if (d.length === 20 && d.startsWith('00')) return d.substring(2); // strip AI
    throw new Error(`Unexpected length: ${d.length}`);
}

// Examples
console.log(validateSSCC('356012345600000016'));
// { valid: true, provided: 6, expected: 6 }

console.log(validateSSCC('356012345600000019'));
// { valid: false, provided: 9, expected: 6 }

console.log(normaliseSSCC('00356012345600000016'));
// '356012345600000016'
Enter fullscreen mode Exit fullscreen mode

Common mistakes

1. Confusing the AI with the SSCC digits

When a GS1-128 barcode is scanned, the raw output is typically 00 followed by the 18 digits, 20 characters total. Always strip the leading 00 before validating.

// Wrong
validateSSCC('00356012345600000016'); // 20 digits, will fail

// Correct
validateSSCC(normaliseSSCC('00356012345600000016')); // strips AI first
Enter fullscreen mode Exit fullscreen mode

2. Fixed-width ERP files

Some systems store SSCCs in fixed-width fields where the SSCC is immediately followed by other data, a line number, quantity, etc. The regex \b(00\d{18})\b won't work here because there's no word boundary after the SSCC.

Use a lookbehind instead:

const re = /(?<!\d)(00\d{18})/g;
Enter fullscreen mode Exit fullscreen mode

This captures exactly 20 characters (00 + 18-digit SSCC) regardless of what follows.


Extracting SSCCs from EDIFACT

In EDIFACT messages, SSCCs appear mainly in the GIN segment with qualifier BJ:

GIN+BJ:356012345600000016'
Enter fullscreen mode Exit fullscreen mode

Here's a simple parser that handles custom UNA delimiters:

function extractSSCCsFromEDIFACT(text) {
    const results = [];

    // Read custom delimiters from UNA service string
    let compSep = ':', elemSep = '+', segTerm = "'";
    const una = text.match(/^UNA(.{6})/);
    if (una) {
        compSep = una[1][0];
        elemSep = una[1][1];
        segTerm = una[1][5];
    }

    const segments = text
        .replace(/\r?\n/g, '')
        .split(segTerm)
        .map(s => s.trim())
        .filter(Boolean);

    for (const seg of segments) {
        const elements = seg.split(elemSep);
        if (elements[0] !== 'GIN') continue;

        for (const el of elements.slice(1)) {
            const [qualifier, value] = el.split(compSep);
            if (qualifier === 'BJ' && value) {
                const result = validateSSCC(value);
                results.push({ sscc: value, ...result });
            }
        }
    }

    return results;
}
Enter fullscreen mode Exit fullscreen mode

Always read the UNA header before parsing. EDIFACT allows custom separators and defaulting to : + ' will silently fail on non-standard files.

Other segments to check:

  • RFF+SI:<SSCC>, Reference, Shipment ID
  • RFF+AAK:<SSCC>, Reference, Despatch number
  • PAC, Package level (less common)

Free tool & API

If you don't want to write code, I built SSCC Pro Vision, it does all of this in the browser:

  • 📷 Scan GS1-128 barcodes via camera
  • ✅ Validate or generate check digits (single or batch)
  • 🔁 Expand SSCC ranges
  • 📂 Upload EDIFACT, IDoc SAP, XML, CSV or TXT files, SSCCs extracted automatically
  • 📱 Installable as a PWA on Android and iOS

There's also a free REST API at https://sscc.birth1mark.workers.dev:

# Validate
curl "https://sscc.birth1mark.workers.dev/validate?sscc=356012345600000016"

# Generate check digit
curl "https://sscc.birth1mark.workers.dev/generate?body=35601234560000001"

# Extract from EDIFACT file
curl -X POST "https://sscc.birth1mark.workers.dev/extract" \
  -H "Content-Type: text/plain" \
  --data-binary @desadv.edi
Enter fullscreen mode Exit fullscreen mode

No auth, no rate limit headaches (500 req/hour free), no data stored. Full docs at sscc-api-guide.html.


Wrapping up

SSCCs are simple in theory but surprisingly easy to get wrong in practice, especially when you're dealing with scanned barcodes, EDIFACT files from different trading partners, or ERP exports with non-standard field widths.

The GS1 spec is the authoritative source, but hopefully this covers the practical cases you'll actually encounter.

If you work in EDI or supply chain and have questions, drop them in the comments. Happy to help. 🇵🇹


Source code: github.com/birth1mark/sscc-check
API source: github.com/birth1mark/sscc-api

Top comments (0)