sheba — Iranian IBAN (Sheba) validation & info lookup
import { isShebaValid, getShebaInfo } from "@persian-tools/persian-tools";
// CommonJS
const { isShebaValid, getShebaInfo } = require("@persian-tools/persian-tools");
Public exports
isShebaValid(shebaCode: string): boolean
getShebaInfo(shebaCode: string): ShebaResultWithAccountNumber | ShebaResultWithoutAccountNumber | null
const shebaPattern: RegExp; // /IR[0-9]{24}/
const shebaPatternCode: RegExp; // /IR[0-9]{2}([0-9]{3})[0-9]{19}/
type ShebaResultWithAccountNumber = {
name: string;
nickname: string;
persianName: string;
code: string;
accountNumberAvailable: true;
accountNumber: string;
formattedAccountNumber: string;
};
type ShebaResultWithoutAccountNumber = {
name: string;
nickname: string;
persianName: string;
code: string;
accountNumberAvailable: false;
};
The valid function is
isShebaValid, notverifySheba. The latter does not exist.
Basic usage
import { isShebaValid, getShebaInfo } from "@persian-tools/persian-tools";
isShebaValid("IR820540102680020817909002"); // true
isShebaValid("IR82054010268002081790900X"); // false (non-digit)
getShebaInfo("IR820540102680020817909002");
// {
// name: "Parsian Bank",
// nickname: "parsian",
// persianName: "بانک پارسیان",
// code: "054",
// accountNumberAvailable: true,
// accountNumber: "020817909002",
// formattedAccountNumber: "020-8179-090-02",
// }
getShebaInfo("IR000000000000000000000000"); // null (invalid)
Validation algorithm (ISO 7064 mod-97)
- Match the regex
/IR[0-9]{24}/. - Move first 4 chars (
IR+ 2-digit check) to the end. - Replace letters with digits:
I=18,R=27(soIR→1827). - Compute
mod 97. Because the result is a 26-digit number too big forNumber, the helpershebaIso7064Mod97(src/modules/sheba/helpers.ts) chunks 9 digits at a time:while (remainder.length > 2) { block = remainder.slice(0, 9); remainder = (parseInt(block, 10) % 97) + remainder.slice(block.length); } return parseInt(remainder, 10) % 97; - Valid iff the result === 1.
This 9-digit chunking is intentional — it avoids needing BigInt (which would add polyfill weight on older browsers). Do not "simplify" it to BigInt(...) % 97n.
Bank info lookup
After validation, the 3-digit bank code (positions 4–6, after IR + 2 check digits) is extracted via shebaPatternCode and looked up in shebaMapCodesMap (from codes.skip.ts).
Some bank entries include a process(iban: string) function that extracts the account number. When present, the result type is ShebaResultWithAccountNumber with accountNumberAvailable: true; otherwise ShebaResultWithoutAccountNumber with accountNumberAvailable: false.
Discriminate via the flag:
const info = getShebaInfo(input);
if (!info) return notify("invalid IBAN");
if (info.accountNumberAvailable) {
use(info.accountNumber); // typed string
} else {
use(info.persianName); // bank name only
}
Common pitfalls
verifyShebadoes NOT exist. The exported validator isisShebaValid.getShebaInforeturns the bank's Persian name aspersianName, notbankName. There is nobankNamefield. Older docs are wrong.- No automatic whitespace stripping.
isShebaValid("IR82 0540 ...")returnsfalse. Strip spaces in the caller, or use a small wrapper:const clean = (s: string) => s.replace(/\s/g, "").toUpperCase(); isShebaValid(clean(userInput)); - No Persian/Arabic digit normalization. Run
autoConvertDigitsToENupstream if input may contain them. accountNumberAvailableis a real discriminant — use it inifto narrow the union.
References
- Tests:
test/sheba.spec.ts - Standard: ISO 13616 (IBAN), ISO 7064 (mod-97 checksum)
- Related:
iranian-validation-expertin.agents/