Czech VAT Checker & Supplier Bank Account Monitor
Pricing
from $3.00 / 1,000 observed suppliers
Czech VAT Checker & Supplier Bank Account Monitor
Check up to 10,000 Czech VAT IDs against the official ADIS register. Monitor unreliable-payer status and published supplier bank accounts, compare invoice accounts, and export typed changes between runs. Failed checks preserve the last verified baseline.
Pricing
from $3.00 / 1,000 observed suppliers
Rating
0.0
(0)
Developer
Vadim Bezrukov
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Watch up to 10,000 Czech suppliers in the official ADIS VAT register and get back only what changed: a supplier that became an unreliable VAT payer (nespolehlivý plátce DPH), a published bank account that appeared or disappeared, or the account on your invoice no longer being one the tax authority publishes.
The first run stores a baseline. In changesOnly mode, later runs return changed
suppliers and diagnostic rows. The Console example uses snapshotAndChanges so
you can inspect the current status on every test run. A failed check is reported as a failed check - it never becomes a
false "account removed" alert.
Why supplier VAT and bank-account status has to be rechecked
Czech VAT rules can create supplier-related tax liability in defined circumstances. The Financial Administration explains unreliable-payer status and liability. Neither fact is stable: a supplier is declared unreliable on a date you are not told about, and bank accounts are added and withdrawn continuously. SAP's Czech localization documentation recommends a daily mass validation of supplier VAT reliability and registered bank accounts for large supplier populations, precisely because a check is only true on the day it was made.
A one-off lookup returns the current register record. This Actor answers the question an accounts-payable team actually has: "which of my 4,000 suppliers changed since yesterday?"
What it monitors
Per supplier, from the official register:
- unreliable VAT payer status, and the date it was published;
- subject type - VAT payer, identified person, VAT group, unreliable person;
- every officially published bank account, with its publication date and, where present, its withdrawal date;
- optionally, whether the specific account on your invoice is currently among them.
And between runs, these typed change events:
| Change type | Meaning |
|---|---|
BECAME_UNRELIABLE | The register now marks this supplier as an unreliable VAT payer |
BECAME_RELIABLE | That marking was lifted |
UNRELIABLE_SINCE_CHANGED | The publication date of the unreliability changed |
SUBJECT_TYPE_CHANGED | e.g. VAT payer became a VAT group |
BANK_ACCOUNT_ADDED | A new account is published - with its exact normalized key |
BANK_ACCOUNT_REMOVED | A published account is gone or was withdrawn |
EXPECTED_ACCOUNT_BECAME_PUBLISHED | The account you pay is now published |
EXPECTED_ACCOUNT_BECAME_UNPUBLISHED | The account you pay is no longer published |
BECAME_NOT_FOUND | The DIČ no longer resolves in the VAT register |
BECAME_FOUND | It resolves again |
Quickstart
{"monitorKey": "accounts-payable-prod","suppliers": [{ "vatId": "CZ27082440", "reference": "supplier-001", "expectedBankAccount": "2171532/0800" },{ "vatId": "CZ26168685", "reference": "supplier-002" }],"mode": "changesOnly","firstRunBehavior": "emitCurrent"}
Run it once to get every supplier's current status and store the baseline. Put it
on a schedule with the same monitorKey and later runs return only changes.
vatId- Czech DIČ.CZ, spaces and dashes are normalized away. An 8-digit DIČ is checksum-validated locally, so a typo is rejected before it costs a request.reference- your AP/ERP/invoice key, echoed back unchanged on that exact row.expectedBankAccount- optional; see below.monitorKey- names the stored baseline. One key per watchlist.mode-changesOnly(default) orsnapshotAndChangesto also get unchanged rows.firstRunBehavior-emitCurrent(default) orbaselineOnlyto store the baseline silently so your first alert is a real change.
Sample change record
{"record_type": "CHANGE","status": "SUCCESS","reference": "supplier-001","vat_id": "27082440","found": true,"subject_type": "PLATCE_DPH","unreliable_payer": false,"unreliable_since": null,"change_types": ["BANK_ACCOUNT_REMOVED", "EXPECTED_ACCOUNT_BECAME_UNPUBLISHED"],"changes": {"published_accounts": { "added": [], "removed": ["999888777/0300"] },"expected_account_published": { "previous": true, "current": false }},"expected_bank_account": "999888777/0300","expected_account_published": false,"source": "czech_fs_adis_vat_register","source_generated_at": "2026-09-06","scraped_at": "2026-09-06T04:15:00Z","fingerprint": "9f2c…"}
Every row is an append-only observation with a stable source_id, a scraped_at
and a semantic fingerprint, so it is usable as an alert payload as-is and joins
to its own history later.
Supplier watchlist example
Batch your whole vendor master. 10,000 unique suppliers require 100 requests to the official service before retries. Runtime depends on source responsiveness:
{"monitorKey": "vendor-master","suppliers": [{ "vatId": "CZ27082440", "reference": "V-000117" },{ "vatId": "26168685", "reference": "V-000118" },{ "vatId": "CZ 45-274-649", "reference": "V-000119" }],"mode": "changesOnly","firstRunBehavior": "baselineOnly"}
Suppliers you drop from the list keep their baseline for 90 days, so splitting one watchlist across several runs does not reset anything. Suppliers included in a run keep their last successful baseline even when their check fails or is skipped for budget reasons, regardless of the baseline's age.
Only one run may use a given monitorKey at a time. An overlapping run fails
before reading the baseline or querying ADIS; retry it after the active run ends.
Different monitor keys can run concurrently.
Invoice / payment bank-account example
{"monitorKey": "pre-payment-check","suppliers": [{ "vatId": "CZ27082440", "reference": "INV-2026-0042", "expectedBankAccount": "2171532/0800" },{ "vatId": "CZ26168685", "reference": "INV-2026-0043", "expectedBankAccount": "CZ4026000000002531920518" }],"mode": "snapshotAndChanges"}
Accepted formats are the Czech domestic form [prefix-]number/bankCode and IBAN.
A Czech IBAN and its domestic form are treated as the same account - the
register publishes both shapes, and comparing them as raw strings would report a
correct account as unpublished. Anything that cannot be normalized deterministically
is rejected with an explicit error rather than guessed at.
expected_account_published is true, false, or null when the comparison
cannot be performed safely (no account supplied, supplier absent, check unverified).
falsemeans: the supplied account is not among the accounts returned as published by the Czech tax authority for this VAT ID at the observation time. That is a fact about the register. It is not a fraud finding, and this Actor draws no legal conclusion from it.
If you edit expectedBankAccount between runs, the comparison for that field
restarts from the new value and reports expected_account_rebaselined - your own
edit is never reported as a change in the official register.
For duplicate DIČ rows, each invoice's expected account is compared independently
against the previous and current published account sets. Only the first row owns
the saved expected-account setting; later rows never inherit its account event.
Scheduling, webhooks and MCP
Save the input as a task, then schedule it - daily before the payment run is the
usual pattern. Add a webhook on ACTOR.RUN.SUCCEEDED pointing at your own
endpoint and read the change view:
{{resource.defaultDatasetId}}/items?view=changes&clean=true
Or poll the same view over the API:
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?view=changes&clean=true" \-H "Authorization: Bearer $APIFY_TOKEN"
With mode=changesOnly, unchanged verified observations are suppressed.
Diagnostic rows and first-run baselines may still be present. Dataset views
project and unwind fields; they do not provide a status filter. Unwinding empty
change_types or published_accounts omits those rows, including diagnostics.
Use monitoring or invoiceAccounts to preserve emitted supplier-level rows.
Select record_type=CHANGE
client-side for change alerts, and separately handle failed, partial and skipped
checks using the full results and RUN_SUMMARY.
MCP
Connect using Streamable HTTP and your own Apify OAuth session (recommended) or bearer token. Execution requires authentication; anonymous Store discovery is separate and becomes available after publication. Expose the Actor as a typed tool:
https://mcp.apify.com?tools=automa-flow/czech-vat-supplier-change-monitor
Example prompt:
Run automa-flow/czech-vat-supplier-change-monitor for monitorKeyaccounts-payable-prod with suppliers CZ27082440 and CZ26168685. Tell me which ofthem changed since the last run, and for any BANK_ACCOUNT_REMOVED say exactlywhich account key was removed. If any supplier could not be verified, say soinstead of treating it as unchanged.
The typed change_types are designed to be read by an agent without further
parsing, and the distinct SOURCE_FAILED / PARTIAL statuses exist so an agent
cannot mistake an unreachable register for a clean bill of health.
Pricing
Pay per event, with no start fee and no monitor-run fee. Apify runtime usage is included. Post-run storage retention and exports can incur your account's normal platform charges; the live Pricing tab is authoritative.
| Plan discount tier | Per verified supplier | 100 suppliers / run | 1,000 suppliers / run |
|---|---|---|---|
| Free / Bronze | $0.004 | $0.40 | $4.00 |
| Silver | $0.0035 | $0.35 | $3.50 |
| Gold / Platinum / Diamond | $0.003 | $0.30 | $3.00 |
At Free/Bronze prices, 100 suppliers checked daily cost $12 for 30 runs; 1,000 suppliers checked weekly cost $16 for four runs. One supplier costs $0.004 and the maximum 10,000 unique suppliers cost at most $40 per run. These are worst-case event bills when every supplier is successfully observed.
Never charged: invalid input, authoritative NOT_FOUND results, internal
retries, planned source maintenance, source failures, unresolved suppliers,
discarded watchlist anomalies, or a DIČ listed twice (charged once).
A supplier that changesOnly mode reports as unchanged is charged: the
verified check is what you are buying, and suppressing the row is what keeps your
dataset a changelog rather than a dump.
Set Apify's maximum total charge to bound a run. The platform may lower this limit to your available account credit.
The Actor selects an affordable prefix of unique suppliers before
querying ADIS, using the current event prices and remaining budget. This is a
conservative worst-case allocation: unused capacity from failures or NOT_FOUND
does not expand the selected prefix during that run. Remaining rows have
status=SKIPPED, error.code=BUDGET_LIMIT, and no business observation; their
previous state is preserved. If the SDK declines a charge, that supplier is also
reported as skipped, without advancing its baseline. RUN_SUMMARY includes
skipped, budget_limit_reached and charged_observations.
charged_monitor_runs is retained for compatibility and is zero with current pricing.
Failure semantics
Every supplier has an explicit outcome:
status | Meaning |
|---|---|
SUCCESS | The register returned a complete current record |
NOT_FOUND | The register explicitly answered NENALEZEN - an authoritative absence, not a failure |
PARTIAL | The request succeeded but this supplier was not conclusively answered |
SOURCE_FAILED | Timeout, HTTP error, malformed or unrecognised response after the retry budget |
SOURCE_MAINTENANCE | The service reported planned maintenance |
INVALID_INPUT | Rejected before any request was sent |
SKIPPED | The budget could not fund this check; no observation was delivered and the previous baseline was preserved |
Guarantees:
- A source failure never becomes an observation. No
found, no accounts, no change events, and the stored baseline is left exactly as it was. - A failed batch does not touch a successful one. Every input is classified;
snapshotAndChangesemits all rows, whilechangesOnlysuppresses unchanged successes. - Reconciliation is by DIČ, never by position in the response.
- Malformed subjects with an identifiable DIČ fail independently. Unknown account structures and invalid calendar dates are errors, never empty account lists.
- No false mass removals. If most of the suppliers this monitor last saw suddenly return absent, or most of them simultaneously lose every published account, that is treated as a source incident: the observations are discarded, no change event is emitted, every baseline is preserved, and the run says so.
- If the register cannot be reached for a single supplier, the run fails loudly and charges nothing.
For large lists, allow a longer run timeout: cloud validation processed 100 suppliers in 13 seconds and 476 checked suppliers in about 50 seconds. These are individual measurements, not latency guarantees. The default timeout is 30 minutes to accommodate the supported 10,000-row ceiling.
Source limits and maintenance window
The Actor talks directly to the official service over plain HTTPS - no browser, no proxy, no credentials. It batches at the documented 100 DIČ per request, holds at most 2 requests in flight against a documented allowance of 4, and never retries its way around a rate limit. Concurrency is deliberately not a user input.
The service documents a maintenance window of 00:00-00:10 Europe/Prague.
Schedule outside it. If a run does hit it, the result is an explicit
SOURCE_MAINTENANCE status and untouched state, not an empty success.
Legal and data limitations
- Public data from the Czech Financial Administration's ADIS VAT register, a service the tax authority explicitly publishes for third-party software.
- This Actor is not an official government service, not legal advice, not a fraud detector, and not a guarantee that any payment is safe. It reports what the register said, when it said it. Verify against the official record before acting on anything with financial consequences.
- Data minimization: the extended operation also returns a structured postal address. The Actor discards it - supplier VAT reliability and published accounts are answerable without it. No directors, owners, dates of birth or personal contact data are collected.
- Note that a 9- or 10-digit Czech DIČ is a natural person's identifier. The Actor
only ever echoes back identifiers you supplied, and
referenceis never written to logs.
API usage
curl -X POST "https://api.apify.com/v2/acts/automa-flow~czech-vat-supplier-change-monitor/runs?maxTotalChargeUsd=0.01" \-H "Authorization: Bearer $APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"monitorKey": "accounts-payable-prod","suppliers": [{ "vatId": "CZ27082440", "reference": "supplier-001" }],"mode": "changesOnly"}'
Start with RUN_SUMMARY: inspect failed/partial/skipped counts before treating
an empty change view as no changes. Retrieve rows whose record_type=CHANGE for
review; handle diagnostics separately. Never automate a payment decision from this
register check alone.
Outputs: the default dataset (overview, plus the changes, accounts and
diagnostics, monitoring and invoiceAccounts views) and a RUN_SUMMARY record in the key-value store with
per-run counts, source request/retry totals and the watchlist-safety verdict.
Technical source details
| Source | Czech Financial Administration, ADIS VAT register (Registr plátců DPH) |
| Endpoint | https://adisrws.mfcr.cz/dpr/axis2/services/rozhraniCRPDPH.rozhraniCRPDPHSOAP |
| Operation | getStatusNespolehlivySubjektRozsirenyV2 |
| Documentation | https://adisspr.mfcr.cz/pmd/dokumentace/webove-sluzby-spolehlivost-platcu |
| Batch size | 100 DIČ per request |
| Authentication | none |
| Browser / proxy | none |
State is a single compact key-value record per monitorKey
(CZECH_VAT_MONITOR_V1_<hash>) holding the last successful observation per
supplier - a comparison baseline, not a history database. Full observations
accumulate naturally in the dataset of each run.
Recovering an interrupted monitor
The read/compare/write cycle uses a non-expiring mutex marker in the named Apify
Request Queue czech-vat-supplier-monitor-locks. Atomic unique-key insertion
prevents competing runs from reading the same baseline. The queue is used only
for coordination; its placeholder URL is never fetched. This uses the documented
request insertion contract.
Normal completion, including a handled ADIS failure, releases the marker. An interrupted run or an unexpected storage error keeps it in place because a remote write may still be in flight. There is no automatic expiry or takeover.
To recover, stop all runs and pause schedules using the affected monitorKey;
wait for their termination. In that queue, delete only the request whose
uniqueKey matches the CZECH_VAT_MONITOR_V1_<hash> shown in the lock error.
Keep the KVS record with the same key. Resume with a new run after confirming the
old runs cannot resume. For local execution the equivalent marker is a file under
<storage_dir>/czech-vat-supplier-monitor-locks/.