EU Tariff Quota Balance Monitor
Pricing
$10.00 / 1,000 conclusive quota observations
EU Tariff Quota Balance Monitor
Track EU tariff quota remaining balances from the European Commission's weekly QUOTA reports. Look up quota order numbers, export published balances, and detect critical, exhausted or reopened quotas between runs. JSON/CSV output for customs and procurement workflows.
Pricing
$10.00 / 1,000 conclusive quota observations
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
Look up EU tariff quota balances by quota order number, export them as structured JSON or CSV, and detect what changed since your last run.
Give it 09.0006 and it returns the goods description, origin, validity period,
opened volume, amount already imported, remaining balance, unit, last import
date and whether the Commission has flagged the quota critical or exhausted.
Give it a hundred order numbers and it returns a hundred answers, each with its
own status. Schedule it and each run tells you which balances moved, which
quotas went critical, which ran out and which reopened.
Data comes from the European Commission's own weekly QUOTA reports, published by
DG TAXUD in the public CIRCABC group TARIC and Quota data and information. The
Actor never touches the DDS2 consultation screens, which the Commission's
robots.txt closes to automated clients.
What it is for
- check the remaining balance on a tariff quota before committing to a shipment;
- watch a portfolio of quota order numbers and get alerted when one goes critical, is exhausted or reopens;
- pull every published EU tariff quota balance into a spreadsheet, warehouse or ERP in one run;
- feed landed-cost, customs or procurement automation with a machine-readable quota feed instead of a screen-scrape;
- keep a dated, append-only history of quota state without running a database.
Typical users: EU importers, customs brokers, freight forwarders, trade-compliance teams, and developers building customs or landed-cost workflows.
Example output
One row per published quota. Run the sample input and 09.0006 returns two rows,
because the Commission publishes a separate balance per validity period:
{"source": "eu_taxud_quota","source_id": "090006:2026-06-16:2027-02-14:3da3002f","source_url": "https://circabc.europa.eu/ui/group/0e5f18c2-4b2f-42e9-aed4-dfe50ae1263b","order_number": "090006","source_order_number": "09.0006","description": "Herrings","sub_quota": null,"origin": "E.O.","valid_from": "2026-06-16","valid_to": "2027-02-14","period_state": "OPEN","status": "AVAILABLE","critical": false,"critical_since": null,"initial_volume": 33496000,"unit": "Kilograms","imported_volume": 6774668.701,"remaining": 26721331.299,"last_import_date": "2026-09-01","source_updated_at": "2026-09-04T08:38:58Z","scraped_at": "2026-09-04T16:10:00Z","result_state": "SUCCESS","changed": true,"change_types": ["FIRST_SEEN"],"previous": null,"fingerprint": "sha256:...","schema_version": 1}
examples/sample_output.json is a real run of examples/sample_input.json,
including the exhausted 2025 period of the same order number and a confirmed
not-found lookup.
Batch lookup
{"quotaOrderNumbers": ["09.0006", "090013", "09.0159", "099524"],"detectChanges": false}
- Both written forms are accepted:
090006and09.0006. Leading zeroes are preserved, and digits are never silently altered. Only ASCII digits0-9are accepted; Unicode lookalikes are returned as freeINVALID_INPUTdiagnostics. - Duplicates are removed before any work, so a repeated number is never charged twice.
- A malformed entry does not stop the batch. It comes back as its own
INVALID_INPUTrow while every valid entry is answered. - Every row carries
input_index, so you can restore your original ordering.
To pull everything the Commission publishes, roughly 1,500 order numbers and
2,300 balances, set includeAllCurrent:
{ "quotaOrderNumbers": [], "includeAllCurrent": true, "detectChanges": false, "maxItems": 10000 }
Set a sufficient Maximum charge per run as well as maxItems. At the current
price, 1,508 conclusive order numbers cost $15.08. Apify can lower the effective
run budget to available account credit, even when you request a higher ceiling.
When that happens, unprocessed order numbers receive free FAILED diagnostics
with MAX_TOTAL_CHARGE_REACHED; a successful run status does not mean a complete
export. Check RUN_SUMMARY and the diagnostics view.
With detectChanges: false, no named monitoring baseline is written. The
Dataset, run summary and recovery checkpoint are still stored for that run.
Monitoring on a schedule
Save a Task with a stable monitorId and schedule it. The Commission publishes
weekly, on Fridays, so a weekly or daily schedule both work; a daily run simply
reports no change until the new report lands.
{"quotaOrderNumbers": ["09.0006", "09.0013", "09.0159"],"monitorId": "steel-and-fish-quotas","detectChanges": true,"emitUnchanged": false}
The first successful run records a baseline and reports FIRST_SEEN. Later runs
compare each quota against its own last successful observation and report only
what moved. With emitUnchanged: false, unchanged quotas are neither returned
nor charged, so a standing watch costs only for the movements it finds.
Attach a webhook on ACTOR.RUN.SUCCEEDED and read the changes dataset view for
a flat, one-event-per-row payload.
Change detection
| Event | Meaning |
|---|---|
FIRST_SEEN | First successful observation of this quota; the baseline |
BALANCE_CHANGED | The published remaining balance moved |
VOLUME_CHANGED | The Commission changed the volume opened for the period |
BECAME_CRITICAL | Added to the Commission's critical list |
LEFT_CRITICAL | No longer on that list |
EXHAUSTED | The balance reached zero |
REOPENED | An exhausted quota has a balance again |
SOURCE_METADATA_CHANGED | A published detail moved that no named event covers |
BECAME_NOT_FOUND | The quota period left the current reports |
REAPPEARED | A quota that had left the reports is published again |
Three deliberate absences, each because the source does not support the claim:
- No
BLOCKED/UNBLOCKED. These reports carry no blocking column. A status the Commission does not publish is not invented here. - No
VALIDITY_CHANGED. The validity period is part of a quota's identity, so a new period arrives as a new record withFIRST_SEENrather than as a mutation of the old one. BECAME_NOT_FOUNDis not a revocation. The Commission drops periods once they age out of the reports. The Actor reports that the quota left the reports and does not guess a legal reason.
Comparison is always against the last successful observation. A failed or unverifiable run never overwrites good state, so a source outage cannot manufacture a wave of false change events.
Bulk monitoring also checks order numbers seen by the same monitor in earlier
runs, so an entire order number leaving the reports produces BECAME_NOT_FOUND
once. A one-off export (detectChanges: false) still returns only current rows.
Monitoring uses compact, immutable KVS revisions ordered by source timestamp
and observation time: an older overlapping run cannot overwrite newer state.
Legacy baselines remain readable. These revisions are concurrency protection,
not a public history API; storage and key-listing costs grow with state changes
and new source generations, including generations with unchanged balances.
Do not schedule overlapping runs of the same monitor if you want to avoid two
independent checks reporting and charging for the same newly observed change.
Interrupted runs and recovery
The run's default KVS contains DELIVERY_CHECKPOINT. Once delivery is confirmed,
resurrecting that run finishes pending monitor-state writes without publishing
or charging again. If interruption occurs during delivery, its outcome may be
unknown: resurrection fails with RECOVERY_REQUIRED instead of risking duplicate
charges. Inspect that run's Dataset and charged events before starting a new
check. A new run is a new observation and can be charged; do not erase the
checkpoint to force a replay. This is fail-closed recovery, not a promise of an
atomic transaction across Dataset, billing and KVS.
Pricing
Pay per event: one charge per quota order number that receives a conclusive answer, whether that answer is a balance or a confirmed absence. One charge covers the order number however many validity periods, origins or sub-quotas the Commission publishes for it.
Never charged:
- invalid order numbers;
- duplicate inputs, which receive a free diagnostic row and are not checked twice;
- source failures, and any run where the reports could not be validated;
PARTIALrows;- retries and the report downloads themselves;
- Dataset writes and Key-Value Store operations;
- unchanged quotas when
emitUnchangedis off.
A confirmed NOT_FOUND is charged, because establishing it takes the same
validated snapshot as a balance does.
The configured price is $0.01 per conclusive order-number observation:
1 / 10 / 100 / 1,000 observations cost $0.01 / $0.10 / $1 / $10.
Platform usage is included; no separate start or dataset-item event applies.
See the live Pricing tab for the price that applies to your run. There is no
guarantee that a quota will change between checks; an unchanged-only run with
emitUnchanged: false has no event charge.
Source and freshness
| Publisher | European Commission, DG TAXUD |
| Distribution | Public CIRCABC group TARIC and Quota data and information |
| Licence | Commission Decision 2011/833/EU, access rights PUBLIC |
| Update cadence | Weekly, published Fridays |
| Coverage | Tariff quotas administered first-come first-served |
Every row carries two timestamps, and they mean different things:
source_updated_at- when the Commission generated the report;scraped_at- when this Actor read it.
This is not a real-time feed. The Commission's own QUOTA application updates
daily; the raw distribution this Actor uses is published weekly. A balance can
therefore be several days behind the live allocation position, and the Actor
tells you exactly how far behind via source_snapshot.source_age_days. If the
newest publication is more than four weeks old, or its timestamp moves backwards,
the run fails rather than present stale balances as current.
Limitations and legal notice
- Reference data, not customs advice. A quota balance does not establish that a specific consignment qualifies for preferential treatment. Eligibility also depends on origin, classification, documentation and the state of the quota at the moment your declaration is accepted. Always confirm before you rely on it.
- Weekly, not live. See above. Do not treat a balance as the position at declaration time.
- First-come first-served quotas only. Quotas administered by import licence,
including many agricultural quotas, are not in these reports. For those,
NOT_FOUNDmeans the reports do not publish the order number, not that the quota does not exist. The message on everyNOT_FOUNDrow says so. - Current and preceding periods only. Older periods age out of the reports.
- A balance is not a reservation. Another importer can draw the remaining volume between your check and your declaration.
- Not affiliated with, endorsed by, or operated by the European Commission. The Commission is the source of the data; this Actor republishes it verbatim under the reuse notice above.
API, CLI and integrations
Run it and read the results with the Apify API:
curl -X POST "https://api.apify.com/v2/acts/automa-flow~eu-tariff-quota-balance-monitor/runs?maxTotalChargeUsd=0.02" \-H "Authorization: Bearer $APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"quotaOrderNumbers": ["09.0006", "09.0013"], "detectChanges": false}'curl "https://api.apify.com/v2/datasets/<dataset-id>/items?clean=true&format=csv" \-H "Authorization: Bearer $APIFY_TOKEN"
Apify CLI:
$apify call automa-flow/eu-tariff-quota-balance-monitor --input '{"quotaOrderNumbers": ["09.0006"], "detectChanges": false}'
Python:
from apify_client import ApifyClientclient = ApifyClient("<token>")run = client.actor("automa-flow/eu-tariff-quota-balance-monitor").call(run_input={"quotaOrderNumbers": ["09.0006", "09.0013"],"monitorId": "steel-and-fish-quotas","emitUnchanged": False,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row["order_number"], row["status"], row["remaining"], row["change_types"])
Dataset views: overview, changes, critical, diagnostics. The run's
RUN_SUMMARY record in the default Key-Value Store carries source-health,
freshness and economics counters for the run.
Use with AI agents through Apify MCP
Expose the Actor as a typed tool in an authenticated MCP-compatible client:
https://mcp.apify.com?tools=automa-flow/eu-tariff-quota-balance-monitor
Example prompt:
Run automa-flow/eu-tariff-quota-balance-monitor for order numbers 09.0006 and09.0013. Report the remaining balance, unit and validity period for each, flaganything critical or exhausted, state source_updated_at, and keep NOT_FOUNDseparate from FAILED.
After publication the same tool URL becomes discoverable to Store users. The Actor returns institutional customs reference data only, and its answers are reference data rather than customs advice.
Technical notes
- HTTP only. No browser, no proxy, no login, no CAPTCHA, no session. A run is six requests and about 230 KB.
- Both balance reports, always. The Commission publishes the balances across two files. Until 2026-08-28 the critical report was a subset of the main one; from 2026-09-04 the main report excludes the critical rows. Reading only the main report on that date would have reported a 21 % dataset collapse and 515 quotas disappearing. This Actor unions both and measures every integrity threshold on the union, so the change of regime is a no-op.
- Dates are recovered, not read literally. The Commission's generator writes
DD/MM/YYYYand re-parses it asMM/DD/YYYY, so numeric date cells carry a transposed day and month. Read naively, the 2026-09-04 report claims it was generated on 2026-04-09. The parser calibrates the convention against the report's own publication timestamp and re-checks every recovered date against its own validity period; if neither reading fits, the run fails instead of publishing a wrong date. NO_RESULTSis neverSOURCE_FAILED. A timeout, a 403, an HTML error page, a truncated download, a renamed column or a stale publication producesFAILEDrows and a failed run. None of them can produceNOT_FOUNDor a successful empty dataset.- Balances are published verbatim.
remainingis the Commission's own Balance column and is never recomputed from volume minus imports; those disagree on 84 of 2,259 rows because volume awaiting allocation is not reflected in the import figure. - History-ready. Stable
source_id,scraped_at,schema_versionand a semanticfingerprintover the published fields only. Rows are append-only observations, comparable across months. - State is a compact document per order number in the Apify Key-Value Store. No database, no external service.