Call the free validation API endpoint
curl -X POST https://aisenseapi.com/services/v1/validate/iban \
-H "Content-Type: application/json" \
-d '{"data": "NO9386011117947"}'{ "type": "iban", "valid": true, "normalized": "NO9386011117947",
"country": "NO", "structure_ok": true, "length_ok": true, "checksum_ok": true }Two details carry the whole design. The path carries the type. The body carries one field named data. Nothing else is required, and there is no header beyond the content type.
Spacing and punctuation in the input do not matter. Send a card number with spaces or a kontonummer with dots, and the service strips them before it counts.
The five supported types
Each type runs its own arithmetic. Pick the one that matches the value you hold.
| Type | Checks |
|---|---|
iban | ISO 13616 mod-97, with a length table for the countries this service meets. Outside that table length_ok is null and the checksum alone decides. |
card | Luhn. The card number is never echoed back in the response. |
orgnr | Norwegian organisasjonsnummer, 9 digits, MOD11. An NO prefix and an MVA suffix are accepted and stripped. |
kontonummer | Norwegian bank account, 11 digits, MOD11. |
phone | E.164 shape only. It says nothing about whether the number is in service. |
Any other value in the path is a mistake rather than a guess, and the service says so plainly.
Response fields
Every reply names the type it ran and carries a boolean valid. The remaining fields depend on the type, and they exist so you can see which stage failed.
| Field | Type | Description |
|---|---|---|
| type | string | The type from the path, echoed back. |
| valid | boolean | Present for every type. True only when all the checks below it pass. |
| normalized | string | The cleaned value. Returned for iban, orgnr and kontonummer, never for card. |
| country | string | IBAN only. The two-letter country prefix, such as NO or DE. |
| structure_ok | boolean | IBAN only. The country code and the two check characters are in the right shape. |
| length_ok | boolean or null | IBAN only. Null when the country is not in the length table. |
| format_ok | boolean | Digit count and allowed characters. Returned for card, orgnr and kontonummer. |
| checksum_ok | boolean | The mod-97 or MOD11 result. Returned for iban, orgnr and kontonummer. |
| luhn_ok | boolean | Card only. The Luhn result. |
| length | number | Card only. The digit count, such as 16. |
| e164 | string | Phone only. The number rewritten in E.164 form, such as +4740000000. |
| note | string | Phone only. A reminder that this is a syntax check. |
What a check digit proves
A check digit is arithmetic baked into the number itself. IBAN uses mod-97. Norwegian organisasjonsnummer and kontonummer use MOD11 with fixed weights. Payment cards use Luhn. In every case one digit is derived from all the others.
So a passing result means the digits agree among themselves. The value survived a retype, a phone call, or a scan without a single character drifting. Transposed digits are the classic failure these schemes were built to catch, and they catch nearly all of them.
It does not mean the account exists. The card may be cancelled, the company may be dissolved, the phone may never ring. The free validation API endpoint never leaves our server to look anything up, so read a true as permission to continue rather than as proof of anything real.
That distinction matters most at signup. Reject a mistyped organisasjonsnummer immediately, then confirm the live company against a register later, when a slower call is affordable.
How failures look
Change the last digit of that IBAN and the answer keeps the same shape. A bad value is a result, not an error.
# IBAN with the final digit changed
{"type":"iban","valid":false,"normalized":"NO9386011117948","country":"NO",
"structure_ok":true,"length_ok":true,"checksum_ok":false}
# Card that fails Luhn
{"type":"card","valid":false,"length":16,"format_ok":true,"luhn_ok":false}Notice which flag flipped. Structure and length still passed on the IBAN, so the caller knows the value was mistyped rather than malformed.
Only a broken request raises a real error. An unknown type or an empty body returns HTTP 400 with a short message.
POST /validate/vatnr {"data": "123"}
{"error":"Unknown validation type. Known types: iban, card, orgnr, kontonummer, phone"}
POST /validate/iban {}
{"error":"No data to validate."}Where to run the check
Run it as close to the input as you can. A web form can call the service when a field loses focus and mark the field before the user reaches the submit button. An importer can call it once per row and write the failing rows to a separate file for a person to read.
An agent should call it after pulling a number out of a document and before handing that number to anything that moves money. The reply is small, so the round trip costs almost nothing next to the mistake it prevents.
One request handles one value. There is no batch mode, so a large import means a loop, and the daily budget is the ceiling on that loop. Repeating a call is safe, because the check is pure arithmetic and holds no state between requests.
Common uses
Form validation
Catch a mistyped account or card before it travels downstream.
Agent input checking
Verify a number a model extracted from a document before acting on it.
Norwegian onboarding
Check an org number or bank account at signup without a register call.
Data cleaning
Flag the rows in an import whose check digits do not hold.
Privacy and limits
The value travels in the POST body, not the URL, so it never lands in a request path. The card type never reflects the number back either. Its reply carries only the digit count and the two booleans.
The service-wide limit is 5000 requests per IP per 24 hours. Calls to the free validation API endpoint draw on the same budget as every other service on the base URL https://aisenseapi.com/services/v1.