Every codebase I have ever worked in has a graveyard of half-remembered validation rules. The IBAN check is mod-97, but only after you rearrange the string. The ISBN-10 check digit can be the letter X. A VIN has a check digit at position 9, unless it was built for a market that does not use one. Each identifier has its own standard, its own math, and its own way of quietly going wrong.
DigitProof is my attempt to put all of that in one place. It is a single API that validates nine families of structured identifiers, parses them, and, this is the part I actually wanted, tells you the correct check digit when the one you have is wrong.
What it validates
- IBAN: length and structure for 86 countries, mod-97 check digits, BBAN parsing (bank code, branch code, account number) for 22 countries, SEPA flag, grouped formatting
- LEI: the ISO 17442 format and its mod-97 check digits, with the LOU prefix broken out
- ISIN: country and NSIN structure with the Luhn check digit
- ISBN-10 and ISBN-13, including conversion between them
- GTIN-8, UPC-A, EAN-13, and GTIN-14, detected from length
- VIN: 17 characters, the North American position-9 check digit, make hints and model year decoding
- Payment cards: Luhn, brand detection, and the networks' published test numbers flagged as
test_only - UUID: version and variant parsing
- EU and GB VAT numbers: per-country formats, with check digits verified where a country defines them
It is format and checksum validation only. There are no bank directories or registry lookups behind it, and the listing says so plainly. A valid result means the identifier is well-formed and its math checks out. A related note on cards: the card checks are format and Luhn only, intended for published test numbers and format checks. Please do not send real cardholder data through the API; PCI DSS obligations for real card numbers stay with the caller.
A taste
Send a known-good IBAN:
curl -X POST "https://digitproof.p.rapidapi.com/v1/validate" \
-H "X-RapidAPI-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"value": "GB29 NWBK 6016 1331 9268 19"}'
You get back the parsed structure, not just a yes:
{
"type": "iban",
"valid": true,
"details": {
"country_code": "GB",
"sepa": true,
"bank_code": "NWBK",
"branch_code": "601613",
"account_number": "31926819",
"formatted": "GB29 NWBK 6016 1331 9268 19"
}
}
Now the interesting part. Change the last digit of that account number and the checksum fails, and instead of a bare false you get the expected check digits and the corrected identifier:
{
"valid": false,
"errors": [
{ "code": "bad_checksum", "expected_check_digits": "56", "actual_check_digits": "29" }
],
"correction": "GB56NWBK60161331926818"
}
There is also a dedicated check-digit endpoint that computes the digit even when the check position holds a placeholder, auto-detection if you do not know what kind of identifier you are holding (a 13-digit 978 number comes back as both ISBN-13 and GTIN-13), and batch validation for up to 100 identifiers per call.
One caveat about corrections, and credit where due: a commenter on this post, Brenda Coleman, put it more sharply than my first version did. A correction assumes the mistake is in the check digit. In the example above the mistyped digit was in the account number itself, and the "correction" is simply the check digits that the rest of that (wrong) number implies. If a data digit was the one mistyped, the corrected value is a valid identifier, but not necessarily the one you started with. Treat corrections as candidates to confirm, not as recovered originals. The listing now says the same.
How it is built
FastAPI on the free tier of Render, with the validation logic kept pure and separate from the web layer. Every validator runs on published standards and official test vectors, and the test suite caught me three real math bugs before launch, including one in the French VAT key formula. The API is stateless and stores nothing: values are processed in transit and forgotten.
Pricing
Every endpoint is available on every plan, including the free tier. The validate, batch, check-digit, and types endpoints are all there from the start, with no Pro-only identifier types and no correction feature held back to force an upgrade. Upgrading simply gets you more requests per month: start free with 150 requests a month (and remember, one request can carry a batch of 100), move up to Pro at $9/month for 5,000, Ultra at $19/month for 20,000, or Mega at $49/month for 100,000. You pay for volume, not for access.
The listing is here: https://rapidapi.com/darksundarker/api/digitproof
Feedback very welcome, especially the "I wish it also validated X" kind. That is how the next identifier on the list gets chosen.
Top comments (2)
A checksum correction can produce a mathematically valid identifier without recovering the value the user intended, so I’d label it as a candidate rather than an authoritative fix. For card numbers in particular, callers should avoid sending live PANs unless they’ve assessed the API’s PCI implications.
Brenda, thank you, you are right on both counts. A correction recomputes the check digit from the rest of the identifier, so it only recovers the intended value when the error was in the check digit itself; a mistyped data digit yields a different identifier that merely validates. The listing and this post now say so: corrections are candidates to confirm, not recovered originals. On cards, validation is format and Luhn only, meant for test numbers and format checks, and the docs now state plainly not to send real cardholder data, with PCI obligations staying on the caller. Appreciate the careful read.