# Slovakia VAT Checker & Tax Debt Monitor (`automa-flow/slovakia-tax-vat-risk-monitor`) Actor

Slovakia VAT checker and tax debt API for up to 100 companies. Verify VAT registration, cancellation or deletion risk, tax debt and reliability from official lists, or monitor deterministic changes from official Finančná správa data.

- **URL**: https://apify.com/automa-flow/slovakia-tax-vat-risk-monitor.md
- **Developed by:** [Vadim Bezrukov](https://apify.com/automa-flow) (community)
- **Categories:** Business, Automation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$10.00 / 1,000 successful company checks

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Slovakia VAT Checker & Tax Debt Monitor

Check Slovak legal entities against official tax-debt, VAT registration,
VAT-cancellation, VAT-deletion, and tax-reliability lists. Run it on a schedule
to emit deterministic changes only. The Actor is HTTP-only: it uses no browser,
CAPTCHA solver, or proxy.

**Pricing:** $0.01 per successfully delivered company check. `PARTIAL`,
`FAILED`, `NOT_FOUND`, retries and unchanged monitor results are not charged.
The output contains explainable official facts and source coverage, never a
subjective risk score.

### What it checks

| Check                 | Official list | Output                                              |
| --------------------- | ------------- | --------------------------------------------------- |
| Tax debt              | `ds_dsdd`     | presence, EUR amount, match confidence and evidence |
| VAT registration      | `ds_dphs`     | currently present in the registration list          |
| VAT cancellation risk | `ds_dphz`     | present in the official cancellation-reason list    |
| VAT deletion          | `ds_dphv`     | present in the deleted-payers list                  |
| Tax reliability       | `ds_iz_ran`   | official `IDS` label when published                 |

Identity resolution uses the official RÚZ API (`registeruz.sk`) to obtain IČO,
DIČ, legal name, legal form, and registered address. The Actor accepts at most
100 companies per run and retains results for supported legal-entity forms
only. It does not provide person search or collect contact data.

VAT bank accounts are deliberately **not supported**. That specific dataset is
licensed CC BY-NC-ND and therefore cannot be repackaged in this commercial
Store Actor. Setting `checks.vatBankAccounts` to `true` fails input validation
with an explicit explanation. The commercially compatible tax/VAT checks above
remain fully available.

### Quick start

IČO is the most reliable input. Paste it into the first field; it is
checksum-validated before any network request.

```json
{
  "operation": "lookup",
  "icos": ["31333532"],
  "checks": {
    "taxDebt": true,
    "vatRegistration": true,
    "vatCancellationRisk": true,
    "vatDeletion": true,
    "taxReliabilityIndex": true,
    "vatBankAccounts": false
  }
}
```

DIČ must contain 10 digits and IČ DPH must match `SK` plus 10 digits. An exact
name lookup is accepted only with city and postcode. Identifiers are resolved
to one official RÚZ legal entity; the Actor does not guess between candidates.

### Result

Lookup emits one Dataset row per input company. A shortened example:

```json
{
  "recordType": "COMPANY_CHECK",
  "status": "SUCCESS",
  "externalId": "vendor-42",
  "ico": "31333532",
  "dic": "2020317068",
  "vatId": "SK2020317068",
  "companyName": "ESET, spol. s r.o.",
  "registeredAddress": {
    "street": "Einsteinova 24",
    "city": "Bratislava - mestská časť Petržalka",
    "postalCode": "85101",
    "country": "SK"
  },
  "taxDebt": {
    "status": "NOT_FOUND",
    "hasDebt": false,
    "amountEur": null,
    "matchConfidence": 0,
    "matchLevel": "NO_MATCH",
    "matchEvidence": []
  },
  "vat": {
    "registered": true,
    "cancellationRisk": false,
    "deleted": false,
    "bankAccounts": []
  },
  "taxReliability": {
    "index": "vysoko spoľahlivý",
    "available": true
  },
  "events": [],
  "coverage": {
    "taxDebt": "COMPLETE",
    "vatRegistration": "COMPLETE",
    "vatCancellationRisk": "COMPLETE",
    "vatDeletion": "COMPLETE",
    "taxReliabilityIndex": "COMPLETE"
  },
  "sourceUpdatedAt": "2026-07-31",
  "checkedAt": "2026-08-30T07:11:57.005Z",
  "attribution": "Zdroj údajov: Finančná správa SR - https://opendata.financnasprava.sk/",
  "errors": []
}
```

`status` describes the company check; per-check `coverage` describes each
source. `NOT_FOUND` is a normal registry outcome. `FAILED` is a technical or
contract failure and is never converted into a clean result. A run with at
least one working source can return `PARTIAL`; if all requested sources fail,
the run fails.

Input validation is isolated per company: a malformed company produces one
uncharged `FAILED` row with `INVALID_COMPANY_INPUT`, while valid companies in
the same batch continue normally and retain their original order. Invalid
global configuration still fails the run before networking.

Every row is history-ready: it includes `source`, `source_id`, `source_url`,
`scraped_at`, `schema_version`, and a deterministic fact `fingerprint`.

### How tax-debt matching works

The official debtor list does **not contain IČO**. The Actor first resolves the
official legal name and registered address by IČO, then compares normalized
Unicode name, postcode, city, and street. Slovak quotation marks, whitespace,
and legal suffix spelling are normalized for comparison only.

- `EXACT` (`1.00`): normalized name, postcode, city, and street all match.
- `HIGH_CONFIDENCE` (`0.95`): exact normalized name, postcode, and city match;
  only the street representation differs.
- `AMBIGUOUS`: the strongest candidate is below the configured threshold or
  ties another candidate. `hasDebt` is `null`, never `true`.
- `NO_MATCH`: no debtor candidate matches the official identity;
  `hasDebt=false` for this source snapshot.

Fuzzy or name-only similarity never confirms debt. `matchEvidence` shows the
fields that produced the decision. These facts are not a solvency clearance,
legal opinion, or credit recommendation.

### Monitoring

Use a stable `monitorKey` for each watchlist:

```json
{
  "operation": "monitor",
  "monitorKey": "suppliers-sk-production",
  "firstRunBehavior": "baseline_only",
  "companies": [{ "ico": "31333532", "externalId": "vendor-42" }]
}
```

`baseline_only` saves the first successful state without Dataset rows.
`emit_current` emits current rows on the first run. Later runs emit only
companies with one or more events:

- `TAX_DEBT_APPEARED`
- `TAX_DEBT_CLEARED`
- `TAX_DEBT_AMOUNT_CHANGED`
- `VAT_STATUS_CHANGED`
- `VAT_CANCELLATION_RISK_APPEARED`
- `VAT_CANCELLATION_RISK_CLEARED`
- `TAX_RELIABILITY_CHANGED`

Each `eventId` is deterministic from the watchlist, company, transition, and
source date. Re-running unchanged sources emits nothing and does not duplicate
events. State is stored in the persistent named Key-Value Store
`slovakia-tax-vat-risk-monitor-state`, under a hash of `monitorKey`; it contains
compact facts, source dates, a configuration fingerprint, and the last
successful timestamp, not raw XML. Partial/failed runs never overwrite
last-known-good state.

Changing companies, checks, freshness, or matching settings requires a new
`monitorKey`, or an intentional one-time `resetState: true`.

Daily is appropriate for VAT and reliability changes. This creates a daily
08:00 Europe/Bratislava schedule through the Apify API; replace the token and
watchlist:

```bash
curl --request POST 'https://api.apify.com/v2/schedules' \
  --header "Authorization: Bearer $APIFY_TOKEN" \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "name": "slovakia-tax-vat-daily",
    "isEnabled": true,
    "isExclusive": true,
    "cronExpression": "0 8 * * *",
    "timezone": "Europe/Bratislava",
    "actions": [{
      "type": "RUN_ACTOR",
      "actorId": "hYrMSyzTyuPOSZ7X6",
      "runInput": {
        "body": "{\"operation\":\"monitor\",\"monitorKey\":\"suppliers-sk-production\",\"firstRunBehavior\":\"baseline_only\",\"companies\":[{\"ico\":\"31333532\",\"externalId\":\"vendor-42\"}]}",
        "contentType": "application/json; charset=utf-8"
      },
      "runOptions": { "build": "latest", "memoryMbytes": 2048, "timeoutSecs": 300 }
    }]
  }'
```

This persistent webhook notifies your HTTPS endpoint only after successful
runs. It sends the run and Dataset IDs without putting an API token into the
payload; the receiver can fetch changed rows with its own secret token:

```bash
curl --request POST 'https://api.apify.com/v2/webhooks' \
  --header "Authorization: Bearer $APIFY_TOKEN" \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "eventTypes": ["ACTOR.RUN.SUCCEEDED"],
    "condition": { "actorId": "hYrMSyzTyuPOSZ7X6" },
    "requestUrl": "https://example.com/apify/slovakia-risk-changes",
    "description": "Slovakia tax and VAT monitor completed",
    "shouldInterpolateStrings": true,
    "payloadTemplate": "{\"eventType\":\"{{eventType}}\",\"actorRunId\":\"{{eventData.actorRunId}}\",\"defaultDatasetId\":\"{{resource.defaultDatasetId}}\"}"
  }'
```

Keep the same input and `monitorKey` across scheduled runs. The receiver can
read changed rows from
`GET /v2/datasets/{defaultDatasetId}/items?clean=true`.

### Freshness

With `requireFreshSource=true` (default), daily VAT/reliability sources must be
no older than `maxSourceAgeHours` (72 hours by default). The debtor list has a
monthly publication cadence, so it uses `maxDebtSourceAgeDays` (45 days by
default). A stale requested source is reported as failed coverage; if every
requested source is stale or unavailable, the run fails.

`sourceUpdatedAt` is the oldest successful selected source date. `sourceDates`
preserves the date of every list separately.

### Sources, licensing, and privacy

The runtime downloads each selected ZIP once per run from
`https://report.financnasprava.sk/`, verifies its size, SHA-256, archive entry
names, embedded XSD, root element, required fields, record count, and source
date, then parses XML as a stream. It does not use the JSON API key or consume
the shared 1,000 requests/hour API quota. `FS_OPEN_DATA_API_KEY` was used only
during source-contract qualification and is not required by customers.

Core lists are published for reuse by Finančná správa SR. The portal's required
attribution is included in every row:

`Zdroj údajov: Finančná správa SR - https://opendata.financnasprava.sk/`

Source URLs:

- `https://report.financnasprava.sk/ds_dsdd.zip`
- `https://report.financnasprava.sk/ds_dphs.zip`
- `https://report.financnasprava.sk/ds_dphz.zip`
- `https://report.financnasprava.sk/ds_dphv.zip`
- `https://report.financnasprava.sk/ds_iz_ran.zip`
- `https://www.registeruz.sk/cruz-public/api`

Only normalized legal-entity facts needed for the requested checks are
retained. Raw source rows, contacts, API keys, and bank accounts are never put
in Dataset or monitor state. Do not use the output as legal, tax, credit, or
investment advice; verify material decisions with the publisher or a qualified
professional.

### Reliability and retries

Downloads and RÚZ requests have separate connection/header/body timeouts and up
to four attempts for timeouts, HTTP 408, 429, and 5xx responses. Backoff is
exponential with jitter and respects `Retry-After`. Other 4xx responses are not
retried. No browser or proxy fallback is hidden in the Actor.

### Pricing and cost

Store pricing is pay per event at **USD 0.01 per successful emitted company
check (USD 10 per 1,000)**. `PARTIAL`, `FAILED`, `NOT_FOUND`, and source-error
rows are not charged as successful checks; unchanged monitor runs emit and
charge nothing.

The latest measured full five-source Apify Cloud smoke processed one company in
73.36 seconds at 2 GB, with reported platform usage of about USD 0.00599
including storage and transfer. A 1 GB comparison was slower and costlier, so
2 GB remains the default. An unchanged second monitor run emitted and charged
nothing. Actual cost depends on your Apify plan, memory setting, network speed,
selected checks, and Dataset volume. Because each source is downloaded only
once, adding companies to the same run amortizes the fixed source cost.

### Troubleshooting

- **Invalid IČO / DIČ / IČ DPH:** correct the format; IČO also requires a valid
  checksum.
- **LEGAL\_ENTITY\_NOT\_RESOLVED:** use IČO, or supply an exact official name plus
  city and postcode. Sole traders and natural persons are outside this Actor's
  scope.
- **AMBIGUOUS tax debt:** do not treat it as debt or clearance. Verify the
  official debtor record manually or improve the registered-address identity.
- **SOURCE\_FAILED / stale source:** inspect `coverage`, `errors`, and
  `sourceDates`; retry after the publisher updates or restores the list.
- **Monitor configuration changed:** use a new `monitorKey` or explicitly set
  `resetState=true` once.
- **No rows in monitor mode:** this is expected for `baseline_only` and for an
  unchanged successful run.

### Use with AI agents through Apify MCP

Expose the Actor as a typed MCP tool:

```text
https://mcp.apify.com?tools=automa-flow/slovakia-tax-vat-risk-monitor
```

Example prompt:

```text
Run automa-flow/slovakia-tax-vat-risk-monitor for these Slovak IČO identifiers.
Summarize VAT registration, cancellation/deletion risk, tax debt, and reliability
facts; keep PARTIAL and FAILED coverage explicit and cite each source URL.
```

The output contains official facts and coverage, not an inferred credit or risk
score. Agents should use `coverage` and `sourceDates` before drawing conclusions.

### Development

```bash
npm ci
npm test
npm run typecheck
npm run build
```

The Docker image installs `xmllint` for authoritative XSD validation and
`procps` for runtime memory telemetry. Tests use sanitized synthetic fixtures;
CI does not depend on live source records.

### Changelog

#### 0.1.1

- Isolated malformed company inputs into ordered, uncharged per-item failures.
- Preserved successful companies' monitor state when another batch item fails.
- Completed history metadata in the Dataset schema and simplified Store input.
- Added reproducible scheduling/webhook examples and sustainable USD 0.01 PPE
  pricing.

#### 0.1.0

- Initial production candidate with five commercial-compatible official lists.
- Deterministic debtor matching and seven monitor event types.
- Per-source freshness and partial-failure coverage.
- Last-known-good hashed monitor state and pay-per-successful-result charging.
- VAT bank-account input explicitly rejected because of its non-commercial
  source licence.

# Actor input Schema

## `operation` (type: `string`):

Lookup emits current facts; monitor compares with the last successful state for the same monitorKey.

## `icos` (type: `array`):

Fast start: paste one to 100 checksum-valid 8-digit company IČOs, one per line. Use Advanced companies below only for DIČ, IČ DPH, name/address lookup, or your own external IDs.

## `companies` (type: `array`):

Optional JSON entries for DIČ, IČ DPH, exact name plus city/postcode, or an externalId. You may combine these with Slovak IČOs; the total limit is 100.

## `checks` (type: `object`):

VAT bank accounts are intentionally unavailable: their source licence prohibits commercial reuse.

## `monitorKey` (type: `string`):

Required for monitor. Isolates one watchlist's last-known-good state.

## `firstRunBehavior` (type: `string`):

Choose whether a new monitor emits current facts or only saves its baseline.

## `resetState` (type: `boolean`):

Replace this monitorKey's baseline after a deliberate configuration change.

## `requireFreshSource` (type: `boolean`):

Fail stale requested sources instead of silently using them.

## `maxSourceAgeHours` (type: `integer`):

VAT and reliability lists are expected daily.

## `maxDebtSourceAgeDays` (type: `integer`):

The official debtor list follows a monthly cadence.

## `minimumMatchConfidence` (type: `number`):

Name-only matches never confirm debt. 0.90–1.00.

## Actor input object example

```json
{
  "operation": "lookup",
  "icos": [
    "31333532",
    "31322832"
  ],
  "companies": [
    {
      "ico": "31333532",
      "externalId": "vendor-42"
    }
  ],
  "checks": {
    "taxDebt": true,
    "vatRegistration": true,
    "vatCancellationRisk": true,
    "vatDeletion": true,
    "taxReliabilityIndex": true,
    "vatBankAccounts": false
  },
  "firstRunBehavior": "emit_current",
  "resetState": false,
  "requireFreshSource": true,
  "maxSourceAgeHours": 72,
  "maxDebtSourceAgeDays": 45,
  "minimumMatchConfidence": 0.9
}
```

# Actor output Schema

## `results` (type: `string`):

Lookup emits one row per company. Monitor emits current rows on first run if requested, then changed rows only.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "icos": [
        "31333532"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automa-flow/slovakia-tax-vat-risk-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "icos": ["31333532"] }

# Run the Actor and wait for it to finish
run = client.actor("automa-flow/slovakia-tax-vat-risk-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "icos": [
    "31333532"
  ]
}' |
apify call automa-flow/slovakia-tax-vat-risk-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automa-flow/slovakia-tax-vat-risk-monitor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hYrMSyzTyuPOSZ7X6/builds/1f6ktP3jdM6JTreNl/openapi.json
