Damm check digit
Add one digit to any number and catch the typos people actually make: 572 gets the Damm check digit 4 and becomes 5724, and any single wrong digit or swap of two neighboring digits breaks the check. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Digit string only
- 572
- Calculation mode
- Compute
- Input
- 572
- Check digit
- 4
- With check
- 5724
Typing long account codes, serial numbers, or membership IDs by hand is where most digit mistakes hide. The Damm check digit algorithm appends a single trailing digit so that every single-digit substitution and every adjacent transposition breaks the checksum — a stronger guarantee than simple modulo-10 schemes for the exact typos people make.
What the Damm algorithm catches that weaker checks miss
Check digits exist because humans and keyboards introduce predictable damage: one wrong key, two neighboring digits swapped, or a digit inserted or dropped. Many everyday schemes, including the classic Luhn rule used on payment cards, catch most single-digit errors and many adjacent swaps, but they leave a few transposition pairs invisible — notably 09 versus 90 under Luhn. H. Michael Damm designed a different construction: digits are combined left to right through a fixed 10-by-10 totally anti-symmetric quasigroup table, starting from interim zero.
The algebraic properties guarantee that changing any one digit, or swapping any two adjacent digits, cannot leave the final interim at zero. That is the practical win for account numbers, warehouse SKUs, patient or ticket IDs, and any fixed-length code where a single mistype would otherwise route work to the wrong record. This tool implements that standard table and the standard left-to-right walk; it does not invent a house variant.
The output always names the algorithm as damm so downstream systems can record which scheme protected the value.
Where Damm check digits fit real systems
Membership and loyalty programs mint sequential or random numeric IDs and need a trailing digit that call-center agents and mobile keyboards will not silently corrupt. Warehouse and logistics teams print carton or asset codes; a transposition of two digits on a handheld scanner path is common, and Damm catches every adjacent swap that weaker schemes miss. Healthcare and education offices that still move paper forms with multi-digit reference numbers can validate on entry and show an immediate correction instead of creating a duplicate chart or enrollment.
Integration tests and data-quality jobs recompute the expected check digit for every row in a CSV export and flag rows where the stored full number no longer matches, which catches both human edits and off-by-one bugs in generators. Product teams that already use Luhn for card-like fields can still adopt Damm for internal identifiers where the stronger transposition property matters more than card-network conventions.
Do not treat a passing Damm check as proof of authorization or ownership — it only proves the digit string is well formed under this algorithm, the same honesty bar you apply to any checksum.
What you can do with it
Audit exported ID columns
Batch-validate every numeric ID in a partner CSV or warehouse export and quarantine rows whose check digit no longer matches the recomputed expected value.
FAQ
What is a Damm check digit?
It is a single trailing digit computed with H. Michael Damm’s quasigroup algorithm so that any one wrong digit or any adjacent transposition makes the full number fail validation.
What happens with letters, spaces, or hyphens?
Provide digits 0-9 only; failed validation tasks are not billed.
Is the Damm check digit tool free?
The browser tool is free and runs locally.
How is Damm different from the Luhn check digit?
Luhn catches most single-digit errors but misses a few swaps of neighboring digits, such as 09 typed as 90. Damm catches every single wrong digit and every swap of two adjacent digits, which suits account and member numbers typed by hand.
How do I check a number that already has its Damm digit?
Choose the validate option and enter the full number. Walking the whole number, check digit included, through the Damm table must end at zero; if it does not, one of the digits was mistyped.
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/damm \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"number":"572"}'const res = await fetch("https://api.kit.forhosting.com/enc/damm", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"number": "572"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/enc/damm",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"number": "572"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/enc/damm", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"number":"572"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"number":"572"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/enc/damm", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"number": "572"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "enc.damm",
"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 digit for a payload you already have, or validates a complete number that already includes one, and it rejects non-numeric input with a clear error instead of silently ignoring garbage. Run it free in the browser or call the KIT API at the published price; both paths use the same pure arithmetic, no network and no stored numbers.
What the Damm algorithm catches that weaker checks miss
Because of that table’s structure, after you process the payload the interim digit is exactly the check digit you should append, and processing the full number including that digit always ends at zero when the number is well formed. Compared with barcode family check digits (EAN, UPC, ISBN), Damm is not tied to a retail GTIN layout — it applies to any pure digit string you choose as payload, which is why it belongs in an encoding utility rather than a product-barcode validator.
How to compute a check digit or validate a full number
Send a number field that contains only characters 0 through 9. Empty strings, missing number, and invalid mode values fail before any table lookup runs and are not billed. Spaces, hyphens, letters, decimal points, and scientific notation are rejected as non-numeric input with invalid_input so you never accept a silently stripped value. Mode compute is the default: the engine walks the payload through the Damm table, returns check_digit as a one-character string, and returns with_check as the payload plus that digit so you can store or print a single string. Mode validate expects a full number of at least two digits (one or more payload digits plus the trailing check digit). The response reports valid true when the full walk ends at interim zero, and always includes the trailing check_digit, the expected_check_digit recomputed from the payload alone, and the payload substring without the last digit. That shape makes it easy to show “you typed X, expected Y” in a form without a second call. 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, onboarding forms, and batch label printers without negotiating a custom tier. Prefer compute when you mint new IDs; prefer validate when you receive an ID from a user, a partner file, or a scanned label and need a boolean gate before looking up the record.
Integration use cases
Mint membership or account IDs
Generate a sequential payload, call compute mode, and store with_check so every new ID carries a Damm trailing digit before it is printed on cards or emailed to members.
Validate typed or scanned codes at entry
When a user or scanner submits a full number, call validate mode and block lookup when valid is false, showing expected_check_digit to help correct a single mistype.
Technical questions
How do I compute a Damm check digit with this API?
POST with number set to the payload digits and mode compute (or omit mode). The response includes check_digit and with_check (payload plus check digit).
How do I validate a number that already has a check digit?
POST with the full digit string and mode validate. The response includes valid, check_digit, expected_check_digit, and payload without the last digit.