EU Tariff Quota Balance Monitor avatar

EU Tariff Quota Balance Monitor

Pricing

$10.00 / 1,000 conclusive quota observations

Go to Apify Store
EU Tariff Quota Balance Monitor

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

Vadim Bezrukov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

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: 090006 and 09.0006. Leading zeroes are preserved, and digits are never silently altered. Only ASCII digits 0-9 are accepted; Unicode lookalikes are returned as free INVALID_INPUT diagnostics.
  • 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_INPUT row 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

EventMeaning
FIRST_SEENFirst successful observation of this quota; the baseline
BALANCE_CHANGEDThe published remaining balance moved
VOLUME_CHANGEDThe Commission changed the volume opened for the period
BECAME_CRITICALAdded to the Commission's critical list
LEFT_CRITICALNo longer on that list
EXHAUSTEDThe balance reached zero
REOPENEDAn exhausted quota has a balance again
SOURCE_METADATA_CHANGEDA published detail moved that no named event covers
BECAME_NOT_FOUNDThe quota period left the current reports
REAPPEAREDA 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 with FIRST_SEEN rather than as a mutation of the old one.
  • BECAME_NOT_FOUND is 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;
  • PARTIAL rows;
  • retries and the report downloads themselves;
  • Dataset writes and Key-Value Store operations;
  • unchanged quotas when emitUnchanged is 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

PublisherEuropean Commission, DG TAXUD
DistributionPublic CIRCABC group TARIC and Quota data and information
LicenceCommission Decision 2011/833/EU, access rights PUBLIC
Update cadenceWeekly, published Fridays
CoverageTariff 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.

  • 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_FOUND means the reports do not publish the order number, not that the quota does not exist. The message on every NOT_FOUND row 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 ApifyClient
client = 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 and
09.0013. Report the remaining balance, unit and validity period for each, flag
anything critical or exhausted, state source_updated_at, and keep NOT_FOUND
separate 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/YYYY and re-parses it as MM/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_RESULTS is never SOURCE_FAILED. A timeout, a 403, an HTML error page, a truncated download, a renamed column or a stale publication produces FAILED rows and a failed run. None of them can produce NOT_FOUND or a successful empty dataset.
  • Balances are published verbatim. remaining is 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_version and a semantic fingerprint over 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.