NIP, REGON, KRS, German VAT & IBAN Validator
Pricing
$1.00 / 1,000 record validateds
NIP, REGON, KRS, German VAT & IBAN Validator
Clean supplier and CRM data with bulk NIP, REGON, German VAT and IBAN format/checksum checks; KRS format only. Get normalized identifiers and clear failure reasons. No registry, VIES or bank lookups: valid does not mean active. PESEL is rejected and redacted.
Pricing
$1.00 / 1,000 record validateds
Rating
0.0
(0)
Developer
Daniel Michałek
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
EU Company ID Validator (NIP, REGON, KRS, DE VAT, IBAN)
Validate Polish and German company identifiers and IBANs in bulk - fully offline, using the official checksum algorithms. Clean up CRM exports, invoice data or supplier master data before it reaches your ERP or payment run.
What it does
For every input record the Actor normalizes the value (strips spaces, dashes, dots, slashes and known prefixes), checks its format and check digit(s), and returns a structured verdict.
| Type | Identifier | What is checked |
|---|---|---|
NIP | Polish tax ID | 10 digits, mod-11 checksum; optional PL prefix. Returns formatted 123-456-32-18 and EU VAT form PL1234563218. |
REGON | Polish business register ID | 9-digit (entity) or 14-digit (local unit) number, mod-11 checksums; for 14 digits the embedded 9-digit REGON is checked too. |
KRS | Polish National Court Register number | 10 digits (leading zeros included). KRS has no check digit, so only the format is verified; short numbers get a zero-padded suggestion. |
DE_VAT | German USt-IdNr | DE + 9 digits, ISO 7064 MOD 11,10 checksum. A bare 9-digit number is accepted and prefixed. |
IBAN | International Bank Account Number | Country code, country-specific length (ISO 13616 registry) and mod-97 checksum. Returns a grouped, printable form. |
Type aliases such as PL_NIP, PL_REGON, PL_KRS, USTIDNR and UST_IDNR are accepted
(case-insensitive).
Input
| Field | Type | Required | Description |
|---|---|---|---|
records | array | yes | Items are either { "type": "NIP", "value": "123-456-32-18", "id": "row-1" } or a bare string/number. id is optional and echoed back. At most 100,000 records per run. |
defaultType | string | no | One of NIP, REGON, KRS, DE_VAT, IBAN. Used for records without their own type. |
Example:
{"defaultType": "IBAN","records": [{ "id": "row-1", "type": "NIP", "value": "123-456-32-18" },{ "id": "row-2", "type": "REGON", "value": "123456785" },{ "id": "row-3", "type": "KRS", "value": "0000123456" },{ "id": "row-4", "type": "DE_VAT", "value": "DE136695976" },"PL61 1090 1014 0000 0712 1981 2874"]}
Output
One dataset item per input record, in input order:
{"id": "row-1","input": "123-456-32-18","type": "NIP","normalized": "1234563218","valid": true,"reason": null,"message": "OK","details": { "formatted": "123-456-32-18", "euVatNumber": "PL1234563218" },"status": "valid","chargeable": true}
statusisvalid,invalid(well-formed request, but the identifier fails a check) orrejected(the request itself cannot be processed).reasonexplains failures:FORMAT,CHECKSUM,BASE_CHECKSUM,LENGTH,COUNTRY, or for rejected recordsUNSUPPORTED_TYPE,EMPTY_VALUE,VALUE_TOO_LONG,PERSONAL_DATA_NOT_SUPPORTED.- A run summary (
total,valid,invalid,rejected,chargeableEvents,chargedEvents,requested,stoppedByChargeLimit) is stored in the default key-value store underOUTPUT.chargeableEventscounts eligible delivered records;chargedEvents.record-validatedcounts confirmed SDK charges and is zero for an unmonetized run. Neither count proves creator revenue.
Invalid record example:
{"id": null,"input": "GB82WEST12345698765431","type": "IBAN","normalized": "GB82WEST12345698765431","valid": false,"reason": "CHECKSUM","message": "IBAN mod-97 checksum failed","details": { "country": "GB" },"status": "invalid","chargeable": true}
Pricing (pay per event)
| Event | Charged when |
|---|---|
record-validated | once per record with status valid or invalid |
Rejected records (unsupported type, empty or oversized value, personal identifiers) are returned
but never charged. The price per event is shown on the Actor's Pricing tab in Apify Store.
If your maximum charge per run is reached, the Actor stops after the last paid record and sets
stoppedByChargeLimit: true in OUTPUT.
Paid output is published only after a confirmed charge. An explicit zero budget or insufficient remaining event capacity prevents a new charge and paid result. Unmonetized development runs retain results without inventing paid events.
The complete redacted result is saved before a charge. A completed restart returns its saved summary without duplicating records or charges. If a charge or dataset acknowledgement is lost, the run stops and requires reconciliation; it does not automatically retry the effect.
Release packaging
Release packaging: the deployment Dockerfile installs locked dependencies with TLS verification enabled and prints file SHA256 values to confirm the native source upload. The native cloud build is pending; the earlier local image passed its smoke before this packaging-only adjustment. examples/INPUT.json, examples/OUTPUT.json, and examples/DATASET.json preserve that local smoke's three public institutional VAT identifiers and actual results; its output reports zero charged events. Application code is unchanged.
Limitations
- No scraping and no network calls. Validation is purely mathematical. The Actor does not query VIES, KRS, CEIDG, GUS/REGON, BZSt or any bank, so it cannot tell whether a correctly formed identifier is actually registered, active or VAT-registered.
- Personal identifier types rejected. Values explicitly labeled
PESEL, GermanSteuer-ID/IdNr, or another supported personal identifier type are rejected and replaced by[REDACTED]in results. Company identifiers, IBANs, and user-supplied row IDs can still contain personal data. Do not put personal information in row IDs or other metadata. Original input and stored run data are retained according to the Actor's Apify storage settings; result redaction does not remove the original supplied input. - KRS numbers carry no check digit - only the 10-digit format is verified.
- DE_VAT covers German numbers only; other EU VAT formats are reported as
FORMATerrors. - IBAN lengths follow the ISO 13616 registry table built into the Actor; national BBAN internal check digits (e.g. bank sort code checks) are not verified.
- Values longer than 64 characters are rejected.
- Serialized input is limited to 1 MB, including unknown metadata. Row IDs are limited to 128 characters; unsupported type labels and echoed rejected values are limited to 64 characters. These output fields are truncated at their limits.
- The 100,000-record ceiling is an input limit, not a guarantee that a batch fits the hosted timeout. Each delivered record needs sequential provider storage calls. Start with a small batch and check the configured budget and runtime limits.
Worked example: catch a one-digit mistake
123-456-32-18 passes the NIP checksum. Change the last digit to 9 and the validator returns CHECKSUM: Check digit mismatch (expected 8, got 9).
Try this mixed list in the Actor input:
{"records": [{ "id": "demo-1", "type": "NIP", "value": "123-456-32-18" },{ "id": "demo-2", "type": "NIP", "value": "123-456-32-19" },{ "id": "demo-3", "type": "REGON", "value": "123456785" },{ "id": "demo-4", "type": "KRS", "value": "0000123456" },{ "id": "demo-5", "type": "DE_VAT", "value": "DE123456788" },{ "id": "demo-6", "type": "IBAN", "value": "GB82 WEST 1234 5698 7654 32" }]}
| Record | Status | What the result means |
|---|---|---|
| demo-1 NIP | valid | Format and checksum passed. |
| demo-2 NIP | invalid | CHECKSUM: expected 8, received 9. |
| demo-3 REGON | valid | Nine-digit format and checksum passed. |
| demo-4 KRS | valid | Ten-digit format only; no register lookup. |
| demo-5 DE VAT | valid | Format and checksum, not VAT registration. |
| demo-6 IBAN | valid | Supported country length and mod-97, not account ownership. |
Actual local execution of the same validator core on these test fixtures returned 6 processed, 5 valid, 1 invalid, 0 rejected. This example is not a hosted billing test and does not establish that any identifier or account is registered.
Price checked on 13 October 2026: $0.001 per supported valid or invalid result ($1 per 1,000 results). Rejected inputs are not charged. No separate Actor-start or dataset-write event is configured. Always check the Pricing tab for the current price.