EU VAT Rates API: all 27 countries (TEDB)
Pricing
Pay per event
EU VAT Rates API: all 27 countries (TEDB)
Standard and reduced VAT rates for all 27 EU Member States from the European Commission's Taxes in Europe Database (TEDB): by date, category or CN code, as clean JSON with source and retrieval time. Information only, not tax advice. Not affiliated with the European Commission.
Pricing
Pay per event
Rating
0.0
(0)
Developer
PPFTEC S.R.L
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 hours ago
Last modified
Categories
Share
EU VAT rates (TEDB)
Operator: PPFTEC S.R.L. (https://ppftec.com). Source allow-listed with conditions (Petre, 2026-10-10). Information only; not legal or tax advice.
Get the VAT rates of the 27 EU Member States as JSON, from the European Commission's Taxes in Europe Database (TEDB) web service (VatRetrievalService, anonymous SOAP). Ask for today or any date, for all countries or a few, optionally narrowed to CN codes, CPA codes or TEDB categories. Every record carries its source, retrieval time, licence attribution and a disclaimer.
For: e-commerce and invoicing tools, OSS/IOSS reporting, ERP and billing integrations, tax-content teams and AI agents that need EU VAT rates as data.
Information only; not legal or tax advice. Rates are as reported by Member States to TEDB; verify against national law before charging VAT. This actor never computes tax amounts or decides whether an exemption applies.
Quick start
Standard and reduced rates today for Romania, Germany and France (one record per country):
{ "countries": ["RO", "DE", "FR"] }
All 27 Member States on a given date:
{ "situationOn": "2026-01-01" }
Every rate rule for Greece (TEDB code EL; GR is accepted too), with categories, CN/CPA codes and comments:
{ "countries": ["GR"], "outputMode": "detailed" }
How the rate for milk (CN 0401) changed in Romania and Germany since January 2025:
{"countries": ["RO", "DE"],"cnCodes": ["0401"],"dateFrom": "2025-01-01","dateTo": "2026-10-10","outputMode": "detailed"}
Validate an input without calling TEDB (no request, nothing emitted, nothing charged; the SOAP requests are stored under key DRY_RUN):
{ "countries": ["RO"], "categories": ["FOODSTUFFS"], "dryRun": true }
Output examples
From the TEDB response recorded on 2026-10-10 (test/fixtures/all27-2026-10-10.xml), replayed offline. Every record validates against src/schemas/ before it is pushed; a record that fails is a bug and fails the run.
Summary (outputMode: "summary", the default), Romania:
{"record_type": "vat-rate-summary","country": "RO","country_iso3166": "RO","situation_on": "2026-10-10","standard_rate": 21,"other_standard_rates": [],"reduced_rates": [{"rate_value": 11,"rate_kind": "REDUCED_RATE","record_count": 33,"categories": ["ACCOMMODATION","AGRICULTURAL_PRODUCTION","CULTURAL_EVENTS","FOODSTUFFS","HOUSING_PROVISION","LOAN_LIBRARIES","PHARMACEUTICAL_PRODUCTS","RESTAURANT","SUPPLY_WATER","SUSTAINABLE_ENERGY","WOOD_ARTICLE98"]}],"other_treatments": [{ "rate_kind": "EXEMPTED", "record_count": 1 }],"rate_record_count": 35,"requested": { "situation_on": "2026-10-10", "date_from": null, "date_to": null, "cn_codes": [], "cpa_codes": [], "categories": [] },"disclaimer": "Information only; not legal or tax advice. Rates as reported by Member States to TEDB; verify against national law before charging VAT. Not affiliated with the European Commission.","provenance": {"envelope_version": "1.0.0","source_id": "tedb-vat-retrieval","source_url": "https://ec.europa.eu/taxation_customs/tedb/ws/","source_request": {"method": "POST","body_sha256": "0f33827ec05304381d492814eef0f31bd4d3f02d7140918236d3ff4f5a89668c","page": "1/1"},"retrieved_at": "2026-10-10T11:22:29.007Z","source_version": {"api_version": "v1","doc_sha256": "6ed97fbe85757712c4c3660e9f6c7b929553e2d69a0890ec5f926a60c9cce32f","dataset_revision": "situationOn=2026-10-10"},"producer": { "name": "eu-vat-rates", "version": "0.1.0", "build": null, "run_id": null, "adapter": "tedb-soap-v1" },"record_hash": "sha256:e805f76a394815ecc52a93b15d32442a58f2b2ca6d8c12b92bff189cafd026fe","licence": {"id": "CC-BY-4.0","url": "https://creativecommons.org/licenses/by/4.0/","attribution": "Source: European Commission, Taxes in Europe Database (TEDB), https://ec.europa.eu/taxation_customs/tedb/ — data supplied by Member States; retrieved 2026-10-10; modified by Clearsource (normalised)"},"personal_data": "none"}}
Detailed (outputMode: "detailed"), one of the 35 Romanian results:
{"record_type": "vat-rate","country": "RO","country_iso3166": "RO","rate_type": "REDUCED","rate_value": 11,"rate_kind": "REDUCED_RATE","situation_on": "2026-07-01","source_situation_on": "2026-07-01+02:00","category": { "id": "WOOD_ARTICLE98", "description": "Wood used as firewood (until 1 January 2030)" },"cn_codes": [{ "code": "4401 41 00", "description": "Sawdust" },{ "code": "4401 49 00", "description": "Other" }],"cpa_codes": [],"comment": "The supply for the use as heating fuel of sawdust, waste and non-agglomerated wood scraps, carried out to final beneficiaries, on the basis of a statement of liability made available to the supplier. See art. 291 para. (2) letters i), j) of the Fiscal Code.","requested": { "situation_on": "2026-10-10", "date_from": null, "date_to": null, "cn_codes": [], "cpa_codes": [], "categories": [] },"disclaimer": "Information only; not legal or tax advice. Rates as reported by Member States to TEDB; verify against national law before charging VAT. Not affiliated with the European Commission.","provenance": {"envelope_version": "1.0.0","source_id": "tedb-vat-retrieval","source_url": "https://ec.europa.eu/taxation_customs/tedb/ws/","source_request": {"method": "POST","body_sha256": "0f33827ec05304381d492814eef0f31bd4d3f02d7140918236d3ff4f5a89668c","page": "1/1"},"retrieved_at": "2026-10-10T11:22:35.939Z","source_version": {"api_version": "v1","doc_sha256": "6ed97fbe85757712c4c3660e9f6c7b929553e2d69a0890ec5f926a60c9cce32f","dataset_revision": "situationOn=2026-10-10"},"producer": { "name": "eu-vat-rates", "version": "0.1.0", "build": null, "run_id": null, "adapter": "tedb-soap-v1" },"record_hash": "sha256:e2366776a8ad65a06f19057ecabf7c1bc39866c20934d337e961bddd1b673d49","licence": {"id": "CC-BY-4.0","url": "https://creativecommons.org/licenses/by/4.0/","attribution": "Source: European Commission, Taxes in Europe Database (TEDB), https://ec.europa.eu/taxation_customs/tedb/ — data supplied by Member States; retrieved 2026-10-10; modified by Clearsource (normalised)"},"personal_data": "none"}}
Fields
Both modes
| Field | Notes |
|---|---|
record_type | vat-rate-summary or vat-rate. |
country | TEDB Member State code (EL for Greece). |
country_iso3166 | ISO 3166-1 alpha-2 (GR for Greece). |
requested | The query the record answers: situation_on or date_from/date_to, and your CN/CPA/category filters. |
disclaimer | Same text on every record (see Disclaimer). |
provenance | Source URL, SHA-256 of the SOAP request body (source_request.body_sha256), retrieval time, TEDB query date (source_version.dataset_revision), hash of the TEDB type XSD we built against (doc_sha256), record hash, licence with attribution. See docs/spec/provenance-schema.md. |
Summary (one per Member State, charged once per country returned)
| Field | Notes |
|---|---|
situation_on | The date you asked for. |
standard_rate | The general standard rate: the STANDARD/DEFAULT result without comment, category or codes. |
other_standard_rates | Other STANDARD results with their TEDB comment, e.g. Spain 7 % "Canary Islands", Germany 19 % "Import". |
reduced_rates | Distinct reduced, super-reduced and parking rates, highest first, with record_count and TEDB categories. |
other_treatments | Counts of EXEMPTED, OUT_OF_SCOPE, NOT_APPLICABLE results. |
rate_record_count | Number of TEDB results behind the summary (get them with outputMode: "detailed"). |
Detailed (one per TEDB vatRateResults element, charged per record)
| Field | From TEDB | Notes |
|---|---|---|
rate_type | type | STANDARD or REDUCED. |
rate_value | rate/value | Percentage as a number; null when TEDB gives none. |
rate_kind | rate/type | DEFAULT, REDUCED_RATE, SUPER_REDUCED_RATE, PARKING_RATE, EXEMPTED, OUT_OF_SCOPE, NOT_APPLICABLE. |
situation_on | situationOn | Date of the situation TEDB reports (when that rule started), YYYY-MM-DD; verbatim value in source_situation_on. |
category | category | { id, description } or null. |
cn_codes, cpa_codes | cnCodes, cpaCodes | [{ code, description }], as TEDB prints them (e.g. 0504 00 00). |
comment | comment | Free text supplied by the Member State, often with the legal reference; null when absent. |
Pricing (pay per event)
Example: all 27 countries in summary mode ≈ $0.054 per run; all 27 in detailed mode (about 1,100 records) ≈ $0.22.
| Event | Price | When |
|---|---|---|
apify-actor-start | $0.00005 (Apify default) | per run |
country-result | $0.002 | per country record pushed in summary mode |
rate-record | $0.0002 | per record pushed in detailed mode |
Nothing is charged for dry runs, health runs, invalid input, TEDB errors, schema drift or countries without results. Set a maximum charge per run in Apify; the actor stops cleanly when it is reached. maxResults (default 10,000) caps the records per run.
Limits
- Requests: at most 9 countries per SOAP request (all 27 = 3 requests), one request at a time, at least 1 s apart. A full 27-country response was 1.5 MB and took 8.9 s on 2026-10-10.
- Retries: HTTP 429 and 5xx (including SOAP
Serverfaults) are retried with backoff (1, 2, 4, 8 s;Retry-Afterhonoured; 5 attempts), then the run fails. SOAPClientfaults (TEDB returns them as HTTP 500) are request errors and are not retried. - Dates:
situationOn(default: today, UTC) or adateFrom/dateTorange of at most 3,660 days, between 2000-01-01 and today + 2 years. A range needsoutputMode: "detailed". How far back TEDB holds data is not documented (unverified). - Countries: the 27 EU Member States only. Northern Ireland (
XI) is mentioned in the 2021 TEDB documentation but was not tested, so it is not accepted yet. - Filters: up to 100 CN codes (2 to 10 digits), 100 CPA codes, 100 TEDB category identifiers. TEDB decides how a filter matches (e.g. CN
0401also returned chapter-level and other rules in the recorded response); readcn_codesandcommentbefore relying on a rate. - Run time: at most 30 minutes per run.
- No caching: every run calls TEDB; schedule runs rather than polling.
Data source and licence
Source: European Commission, DG TAXUD — Taxes in Europe Database (TEDB), VatRetrievalService web service (WSDL https://ec.europa.eu/taxation_customs/tedb/ws/VatRetrievalService.wsdl, endpoint https://ec.europa.eu/taxation_customs/tedb/ws/, no authentication). The data is supplied to TEDB by the Member States. Copies of the WSDL and XSDs we built against (downloaded 2026-10-10) are in src/schemas/tedb/.
Attribution (also in every record's provenance.licence.attribution and in the dataset description):
Source: European Commission, Taxes in Europe Database (TEDB), https://ec.europa.eu/taxation_customs/tedb/ — data supplied by Member States; retrieved <date>; modified by Clearsource (normalised)
Reuse: Commission content is reused under the Commission legal notice (https://commission.europa.eu/legal-notice_en), which licenses it under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/) and implements Commission Decision 2011/833/EU. Modifications: this actor converts the SOAP/XML response to JSON, renames fields, turns rate values into numbers, cuts dates to YYYY-MM-DD (the verbatim value is kept), maps EL to ISO GR in country_iso3166 and, in summary mode, aggregates results per country. A TEDB-specific disclaimer page was not found (the TEDB site is a JavaScript app); that point is open.
This actor is a product of PPFTEC S.R.L. It is not affiliated with or endorsed by the European Commission or any Member State. It does not use EU or Commission logos.
Reliability
- Schema drift fails loudly. Every TEDB response is parsed and checked against a pinned shape (
src/source-shape.schema.json, derived fromVatRetrievalServiceType.xsd). An unknown element, a missing element, an unknown rate type, a non-numeric rate, results for a country we did not ask for, or TEDB rejecting our request as XSD-invalid stops the run with exit code 1, the statusSCHEMA DRIFT at tedb-vat-retrieval: …and aDRIFT_REPORT(expected, actual, sample) in the run's key-value store. Records already pushed stay valid. - Health checks.
mode: "health"(hidden, maintainer only) runs a canary: one SOAP call for Romania today (shape, standard rate present, output schema) and the SHA-256 of the WSDL and both XSDs against the pinned copies (a changed type XSD fails, the others warn). It pushes a record to the named datasetpda-healthwith p50/p95 latency. 4 requests, at least 1 s apart. Planned schedule: daily. - Kill switch.
PDA_KILL_SWITCH=on(orPDA_DISABLED_ADAPTERS=tedb-soap-v1) stops every run before any request (statusDisabled by maintainer: …); it is checked again before every request. - Changelog: see
CHANGELOG.md.
Security and privacy
- Network: the actor calls only
https://ec.europa.eu/taxation_customs/tedb/ws/(fixed URLs; user input only reaches the XML body, escaped and validated first). Redirects are never followed. - Personal data: none. Records hold rates, categories, CN/CPA codes and Member State comments about the law.
- Container:
apify/actor-node:24pinned by digest; runs as the non-root usermyuser. - Pay-per-event guard: on Apify the actor refuses to run without pay-per-event pricing (maintainer override
PDA_ALLOW_NO_PPE=1for a private build only). - Health mode needs
PDA_HEALTH_ENABLED=1, the secret env varPDA_HEALTH_TOKEN(≥ 32 characters, Apify secret@pdaHealthToken) and the same value in the secret inputhealthToken, compared in constant time; ifPDA_MAINTAINER_USER_IDis set,APIFY_USER_IDmust match.
Use with AI assistants (MCP)
This actor can be called by AI assistants through Apify's MCP server (a service run by Apify; this actor is a separate, independent product of PPFTEC S.R.L., not affiliated with the European Commission). Add it to an MCP client such as Claude, VS Code or Cursor:
{"mcpServers": {"clearsource-eu-vat-rates": {"url": "https://mcp.apify.com?tools=clearsource/eu-vat-rates"}}}
On first use your browser asks you to sign in to Apify (OAuth); or send your token as Authorization: Bearer <APIFY_TOKEN>. The assistant reads the input schema, runs the actor and then fetches the dataset items. Runs are billed to your Apify account at the pay-per-event prices above.
Try: "What are the standard and reduced VAT rates in Romania, Germany and France today?" Details of the MCP server: https://docs.apify.com/platform/integrations/mcp (checked 2026-10-10).
Terms of use
This actor is offered by PPFTEC S.R.L. under Apify's terms plus our terms of use: https://clearsource.ppftec.com/terms
Disclaimer
Information only; not legal or tax advice. Rates as reported by Member States to TEDB; verify against national law before charging VAT. Not affiliated with the European Commission. Data is provided "as is", as returned by TEDB at provenance.retrieved_at; TEDB may lag behind changes in national law.
Calling via API
curl -X POST "https://api.apify.com/v2/acts/clearsource~eu-vat-rates/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"countries":["RO","DE","FR"]}'
Development
npm cinpm run lint && npm run typecheck && npm test && npm run buildnpm run check-shared # src/core identical in all actorsnpx -y apify-cli@latest validate-schema# Live contract test (User-Agent clearsource/eu-vat-rates@<version> (+https://clearsource.ppftec.com)):PDA_LIVE=1 npm run test:contract # 1 SOAP request (RO, today)# Offline local run with the recorded fixture (ignored on Apify):mkdir -p storage/key_value_stores/defaultecho '{"countries":["RO"]}' > storage/key_value_stores/default/INPUT.jsonPDA_REPLAY_FIXTURES=$PWD/test/fixtures CRAWLEE_STORAGE_DIR=./storage node dist/main.js
Environment variables: see .env.example (no secrets are needed for normal runs).