Luhn mod N check character
With the alphabet abcdef, the code abcdef gets the check character e, so it becomes abcdefe. Luhn mod N runs the classic double-and-sum rule in base N, for codes built from letters, hex or a house character set. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Text
- abcdef
- Alphabet
- abcdef
- Calculation mode
- Compute
- Payload
- abcdef
- Check character
- e
- With check
- abcdefe
Classic Luhn works only on digits 0–9. Real identifiers often mix letters, hex, Base36, or a house character set, and still need a trailing check character that catches mistypes. Luhn mod N maps every symbol in your alphabet to a code point, runs the same right-to-left double-and-sum idea in base N, and returns a check character from that same alphabet.
What Luhn mod N is and how it extends classic Luhn
Hans Peter Luhn’s original algorithm protects digit strings by alternating a double factor from the right, folding doubled values back into a single digit, summing, and choosing a check digit so the full number is congruent to zero modulo ten. That rule powers payment cards, IMEI tails, and many national identifiers, but it assumes N equals ten and every character is a decimal digit.
Luhn mod N keeps the same structure while letting N be the size of any ordered alphabet you define: each character maps to a code point from zero through N minus one, the fold step becomes the sum of base-N digits of factor times code point, and the check result is mapped back to a character in that alphabet. Prefer an even N when you care about the classic detection guarantees; odd alphabets still produce a deterministic check character but weaken single-substitution and transposition coverage.
Compared with Damm (digits only, quasigroup table) and barcode check digits tied to EAN or ISBN layouts, Luhn mod N is the right fit when your codes are already alphanumeric and you want one shared scheme for minting and validation.
What you can do with it
Audit exported identifier columns
Batch-validate every code in a partner CSV or warehouse export and quarantine rows whose check character no longer matches the recomputed value for your alphabet.
FAQ
What is a Luhn mod N check character?
It is a single trailing character computed with the generalized Luhn algorithm over an alphabet of size N, so common mistypes make the full string fail validation.
Is the Luhn mod N tool free?
The browser tool is free and runs locally.
How are the characters turned into numbers?
By their place in the alphabet you give: the first character is 0, the next is 1 and so on up to N minus 1, where N is the length of the alphabet. With abcdef, a is 0, f is 5 and N is 6.
Why should the alphabet have an even number of characters?
Because an even N keeps the detection strength of classic Luhn. An odd alphabet still gives a fixed, repeatable check character, but it catches fewer single wrong characters and fewer swapped neighbors.
What happens if the code has a character outside the alphabet?
The tool stops right away and reports it instead of skipping the character or guessing. The alphabet itself needs at least two different characters, so a one-letter set is refused as well.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/enc/luhn-mod-n \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"abcdef","alphabet":"abcdef"}'const res = await fetch("https://api.kit.forhosting.com/enc/luhn-mod-n", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "abcdef",
"alphabet": "abcdef"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/enc/luhn-mod-n",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "abcdef",
"alphabet": "abcdef"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/enc/luhn-mod-n", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"abcdef","alphabet":"abcdef"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"abcdef","alphabet":"abcdef"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/enc/luhn-mod-n", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "abcdef",
"alphabet": "abcdef"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "enc.luhn_mod_n",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
This capability computes that character for a payload, or validates a full string that already ends with one, and it fails fast when the input contains symbols outside the alphabet so you never silently accept garbage. Run it free in the browser or call the KIT API at the published price; both paths use the same pure arithmetic with no network and no stored values.
What Luhn mod N is and how it extends classic Luhn
Wikipedia’s formulation starts the generate pass with factor two on the rightmost payload character and the validate pass with factor one on the trailing check character, which is exactly what this tool implements so goldens match the public reference. The response always names algorithm luhn_mod_n so logs and partner contracts can record which scheme protected the value.
How to compute a check character or validate a full string
Empty text, missing alphabet, alphabets shorter than two distinct characters, and unknown mode values fail before any arithmetic runs and are not billed. Provide text as the payload without a check character for mode compute (the default), and alphabet as the ordered set of valid symbols. The engine maps each distinct alphabet character to successive code points, walks the payload right to left, and returns check_character plus with_check (payload plus that character). Mode validate expects a full string of at least two characters; the response reports valid, the trailing check_character, expected_check_character recomputed from the prefix, and the payload substring without the last character so UIs can show a clear correction. Every symbol in text must appear in alphabet: if any character is outside, the call fails with invalid_input and the message lists those symbols so you can fix the alphabet or strip noise before retrying. Because the path is pure parse with no clock, random source, or network, the same input always yields the same JSON on the free browser tool and on the API. At $0.002 per successful request you can protect bulk imports, label printers, and onboarding forms without a custom tier. Use digits 0123456789 to reproduce classic mod-10 Luhn-style generation for pure digit payloads; use 0-9A-Z for Base36-style product codes; use a custom house set when your inventory already forbids ambiguous glyphs such as O and 0.
Where generalized Luhn check characters fit real systems
Warehouse and asset tags often mix letters and digits so operators can read them aloud; appending a Luhn mod N character catches adjacent swaps and single substitutions before a handheld scan creates the wrong shipment. Software license keys and coupon codes that already exclude confusing characters still need a cheap integrity digit that partners can reimplement without a shared secret; publishing the alphabet and this algorithm is enough. Do not treat a passing check as proof of authorization or ownership — it only proves the string is well formed under Luhn mod N for that alphabet, the same honesty bar you apply to any checksum. Membership and loyalty programs that outgrew pure numeric IDs can keep one mint path: generate a sequential or random payload in the house alphabet, call compute, store with_check, and validate on every form and partner file. Data-quality jobs recompute expected_check_character for every row in an export and quarantine mismatches, which catches both human edits and off-by-one bugs in generators. Integration tests freeze goldens against known Wikipedia-style examples such as payload abcdef over alphabet abcdef yielding check character e, so upgrades never silently change the scheme.
Integration use cases
Mint alphanumeric product or asset codes
Generate a payload in your house alphabet, call compute mode, and store or print with_check so every new code carries a Luhn mod N trailing character.
Validate typed or scanned codes at entry
When a user or scanner submits a full string, call validate mode and block lookup when valid is false, showing expected_check_character to fix a single mistype.
Technical questions
How do I compute a check character with this API?
POST with text set to the payload, alphabet set to your ordered character set, and mode compute (or omit mode). The response includes check_character and with_check.
How do I validate a string that already has a check character?
POST with the full string, the same alphabet, and mode validate. The response includes valid, check_character, expected_check_character, and payload without the last character.
What happens if text contains symbols not in alphabet?
The call fails with invalid_input and the error message lists symbols outside the alphabet. Failed validation tasks are not billed.