← The calculator's index
UNCTAD · Tariff calculator · Step 1 of 7 · concept note

Tariff calculator: concept note

One calculator of import duties and taxes, which runs on its own or inside a portal such as eRegulations. It asks the customs service where the customs service can compute, and computes from the published tariff where it cannot.

In one minute

  • What: a public page where an importer picks a product, describes a shipment and reads every duty and tax, with the rate, base and legal source of each.
  • How: one contract, two providers behind it. The ASYCUDA provider asks customs; the computing provider computes from tariff data we ingest.
  • Where: one installation per country, at calculator-bi.eregistrations.dev, calculator-rw.eregistrations.dev, and so on D26.
  • Proof: pilot 1 computes Burundi and compares every tax with OBR's answer; pilot 2 does the same for Rwanda.
  • eRegulations v7: untouched while we build; it embeds the calculator once pilot 1 passes D19.

This note answers the request of 28-09-2026, which set three points: take the prototype page as the frontend; extract the ASYCUDA integration from eRegulations and rebuild it as the calculator's backend; make a calculator possible without ASYCUDA. Two agents reviewed it adversarially; their findings are in the review. Words used in a sense of their own are in the dictionary.

1 · What exists today

Two calculators already call OBR: the prototype and eRegulations v7. Neither can serve a country without ASYCUDA.

The prototype (04-08 to 25-09-2026) is plain HTML and JavaScript for Burundi and Rwanda, behind a small relay that holds the customs key. Its value is what was measured: which fields OBR requires, which declaration types it really computes, the 21 defects found on 06-08-2026. Its debt: Rwanda is a patched copy of Burundi, and there is no store and no cache.

eRegulations v7 carries its own port of the calculator since 04-09-2026. It is bound to eRegulations: its public site does not compile without its administration library.

v7's calculator in detail
  • TariffsBO, 447 lines, talks to ASYCUDA's /api/v1: 3 commodity endpoints, 11 reference tables, the estimate, api-id and api-key headers, the language on every call.
  • Reference tables are cached in a SQL Server table, TariffsCache, for 7 days by default, filled on the first visit.
  • Its own public API, /api/tariffs/*, in eRegulations' shapes, behind a feature switch, limited to 120 requests per minute per address.
  • A Razor page and 644 lines of jQuery, with ?embed=true.
  • Ported in Admin pull requests #25 and #26, Public #38 and #44.

Other customs systems. Of those checked on 29-09-2026, only ASYCUDA's tariff API computes an estimate on request. Korea's UNI-PASS publishes tariff lookups without one; TANCIS, ICUMS, Webb Fontaine, Kenya's iCMS, GAINDE, CrimsonLogic and SOGET publish no tariff API that could be found. Everywhere else, calculators ingest the tariff and compute.

2 · What the calculator is

A page that tells an importer what a shipment will pay, line by line, with the legal source of each line. Never a declaration, never an assessment.

It answers in the country's currency and languages, runs as one installation per country D20, and can be placed inside any portal with one line. Whatever it shows is an estimate; only customs' assessment of a lodged declaration is binding. It does not classify goods: the importer picks the commodity code.

The rule inherited from the prototype. When customs computes, the calculator shows customs' answer and corrects nothing. A defect found in the customs service is reported to it, with an example it can reproduce.

Also in scope, each owned by a module of step 2
  • Languages: French and English; Kirundi off on the public page, as OBR asked; Swahili and Kinyarwanda when their authorities supply the texts (module 0).
  • Accessibility to the template's bar (module 0).
  • Printing the estimate and exporting it as CSV, as the prototype does (module 3).
  • A health probe per provider, and usage counts kept across restarts (module 9).
  • No personal data: shadow-mode logs hold shipment values and origins only, and are deleted after a set period (module 9).

3 · Two providers behind one contract

The page speaks one language, the calculator's own. Each provider is translated into it, and no provider is ever asked to change D23.

The contract is the calculator's API: product search, product details, reference tables, estimate. Amounts are exact decimals, each with its currency, and codes are the calculator's. Neither ASYCUDA's shapes nor v7's are kept as they are: one has a single currency per shipment where OBR asked for one per cost element, the other returns results that cannot hold 53 184 493,74 exactly.

Each provider has an adapter that translates, and nowhere else is a provider's vocabulary seen. Where a provider cannot take what the contract carries, its adapter converts with that provider's own published rates, and says so.

Every estimate says which provider answered, which tariff version it used, whether the figure is indicative, and how each line was reached.

Provider What it does Its figures
ASYCUDA Sends the shipment to the customs service and shows its answer. A port of v7's TariffsBO Customs' own
Computing Computes from a published tariff version: customs value, applicable measures, rates, each tax on its base Always marked indicative
rwandatrade.rw Asks Rwanda's trade portal, as the prototype does D21 The portal's

Each installation chooses its provider on its administration page, not in its environment D20. The template chooses in the environment, so this is code the calculator adds.

When ASYCUDA does not answer, the page says so and shows no figure of ours, unless the country allows it; Burundi does not D11. Exports go through ASYCUDA only, once OBR computes them D15. A stand-in that invents answers exists for demonstrations and tests only; a live installation refuses to start with one, after another country's data was once shown as Burundi's.

Shadow mode runs both providers for one country: the importer sees the authoritative answer, and every difference with the other is logged, tax by tax. For Burundi it uses v7's production settings D24. One call from our server shows whether OBR already accepts its address; OBR is asked only if not. Production calls are real traffic, so the pilot's are few and spread out.

4 · Tariff data without ASYCUDA

Where no customs service computes, the tariff is stored as data, and the engine computes from it. Nothing a country changes is code.

The model is the EU's TARIC, simplified. It is what the EU, UK and Swiss tariffs use; there is no formal standard.

Piece What it says
Measure Which tax applies, to which codes, from which origins, under which procedure, between which dates, under which legal act
Component The rate: a percentage, an amount per unit, or several joined by plus, minimum or maximum
Condition A certificate or a threshold the measure depends on
Tax type Its order, its base, its currency, its rounding: VAT, for example, on customs value plus duty plus excise

A country is data and parameters. What it needs beyond them, such as a vehicle's cylinder capacity, is a declared rule with its own test, never a branch in a country file. The common external tariff differs by EAC member, through stays, remissions and COMESA preferences, so these are measures of the country that applies them.

Tariffs arrive through connectors, each producing a draft version dated from the day a law takes effect. Pilot 1 needs the first two.

  1. A spreadsheet or CSV schedule, with a reader for rate texts such as "25% or USD 200/t, whichever is higher".
  2. Manual entry, for levies and exchange rates that change by notice.
  3. A PDF gazette, extracted and then checked line by line by the analyst.
  4. An API, where one exists.

A draft is published only when every declarable code has a customs duty, the analyst has read its differences with the version in force, and the golden cases pass: every tax equal to OBR's after rounding D12, except taxes named in the register of known OBR defects. At least twenty varied golden cases before step 7.2 D25.

Data register, tax sheets and aggregators
  • Data register. Each country lists its sources: the authority, the document or address, its format, how often it changes, the connector, who checks it. Exchange rates carry their own validity.
  • Tax sheets. Step 4 gives one sheet per tax: base, currency, rounding, order, legal source, who updates it, and what the page says if an importer disputes the figure.
  • Aggregators. ITC's Market Access Map, UNCTAD TRAINS and the WTO's data can seed a first version but never replace a national source. TRAINS stops at 2021 for Burundi, and none carries national levies.

5 · Embedding, and eRegulations

Any portal places the calculator with one line. eRegulations v7 becomes one of those portals.

Embedding is an iframe of the country's embedded page, or one script tag that inserts it and adjusts its height. A host may choose the colours, the logo and the language; anything more is a country setting. Only the sites listed for the country may frame it D9.

Six security requirements for modules 8 and 10
  • frame-ancestors built from each country's list of allowed sites.
  • CORS limited to the calculator's own pages and those sites; the prototype allowed every site.
  • Height messages sent to the allowed site only, and checked on receipt.
  • Rate limiting that trusts only our own proxy's address header; v7 trusts one any client can forge.
  • Reference answers cached, so public traffic spends the customs quota only on estimates.
  • The customs key on the server only, with its holder, its rotation, and what happens when customs locks it.

eRegulations v7, in three moves:

  1. While we build: this project does not touch v7. It keeps serving Burundi and receives changes from other requests, OBR's of 24-09-2026 among them D19.
  2. When pilot 1 passes: a small v7 change lets /Tariffs show the embedded calculator when a setting names it, and today's page when it does not.
  3. Once a country has run on the embed for an agreed period: retiring v7's own calculator is decided D1.

6 · How the work runs

Seven steps, each through four gates. Nothing is drawn or built before a step's final agreement.

The gates are: draft, first agreement, adversarial review by agents, final agreement with its date. Every role is the analyst's D8.

Step Ends with
1 · Concept note This page, agreed
2 · Short specifications One page per module, at most 450 words
3 · Mockups Public page, embedded page, administration; clickable
4 · Detailed specifications Contract, engine rules, one sheet per tax, failure policy per provider
5 · Detailed mockups Every state: empty, error, customs down, shadow
6 · Build phases One branch and one pull request per phase, each ending with something to click
7 · The tool 7.1 ASYCUDA provider and the page · 7.2 engine and pilot 1 · 7.3 administration · 7.4 embedding and v7 · 7.5 pilot 2

Step 2's eleven modules: 0 public page · 1 product search · 2 estimate form · 3 result and its evidence · 4 ASYCUDA provider · 5 engine · 6 tariff data and ingestion · 7 administration · 8 embedding · 9 health and usage · 10 technical.

The product starts from vertical-base, UNCTAD's template for services built by agents (Next.js, Prisma, Postgres), brought in at step 7 D6, D18. It sets aside what a public calculator does not use, applicant accounts and registration, and the calculator adds the tariff engine, the provider choice and a light page that can be framed.

What the template gives, and how its spec fits the seven steps
  • It gives: an installer that can run twice, country and platform administration with sign-in, reference lists and parameters, an agent server (MCP), a one-command check gate, the integration contract under which each provider is an adapter, and the four doors that say where every value is changed.
  • Its spec: its brief is this note; its sources, legal basis and lists are written in step 2; its screens in steps 3 and 5; its golden scenario in step 4. Its documents on parties, lifecycle, money and output are answered "none, because the calculator issues nothing".
  • Its check gate is necessary and not enough: it proves neither a real integration, nor security, nor accessibility, nor that a person can use the page. Each phase of step 7 closes those four checks before its final agreement.

7 · Pilots

Each pilot answers one question: does our arithmetic match the customs service's, tax by tax?

Pilot 1, Burundi. The EAC tariff, Burundi's stays and remissions and its national taxes are ingested with their legal articles, computed by the engine, and compared with OBR's own estimate: on stored golden cases, and in shadow mode. The measure of success is how many golden cases match OBR, out of how many.

Pilot 2, Rwanda D13. The same common external tariff with its own stays, remissions and taxes: it proves a second country is data, not code. It is compared with rwandatrade.rw's answers D21.

8 · OBR's requests of 24-09-2026

OBR's requests are done in v7 by other requests, and carried here as requirements D19.

OBR asked for Where it lands here
All the currencies its system handles Module 2, reference lists
Internal freight added; external freight renamed and explained Modules 2 and 5; internal freight is outside the customs value
One currency per cost element The contract (§3), module 2
Import and export tabs Module 2; exports through ASYCUDA only D15
A table of preferential treatments, filtered by origin Modules 2 and 6; preferences are measures
Kirundi off; labels checked; menu position Module 0
Hosting at OBR UNCTAD runs the calculator for now, then decided with each authority D22

9 · Risks

Risk What covers it
A computed figure taken for an assessment Every result says "estimate", names its tariff version and the legal act of each line. When one first reaches the public is decided once the calculator is finished
Rates go stale: finance laws in July, notices any day (a levy changed in December 2025), weekly exchange rates Versions dated from any day; exchange rates with their own validity; a warning past a threshold
National levies, stays and remissions missing or wrong The pilots' main test; each carries its legal act; golden cases catch drift
OBR's test service silent since 04-09-2026 Production settings D24 and stored golden cases
Public traffic spends the customs quota Rate limiting, cached reference answers, key custody (§5)
The template's method is a first draft Its origin commit recorded; fixes pulled in with template:pull
The embedded page grows heavy A size budget checked in the build

10 · Decisions

Every question of this note is answered. One is deferred: when a figure we compute may reach the public, decided once the calculator is finished.

Question Answer
?1 When ASYCUDA is silent, may we show our own figure? Never, unless the country allows it; Burundi does not D11
?2 How close must a golden case be? Equal to OBR after rounding, tax by tax D12
?3 Which country is pilot 2? Rwanda D13
?4, ?8 What does v7 receive while we build? Nothing from this project; OBR's requests come through other requests D14, D19
?5 Exports in the first release? Through ASYCUDA only D15
?6 The repository? unctad-ai/tariff-calculator-platform D16
?7 Which contract? Our own; no provider asked to change D23
?9 How is a provider chosen? One installation per country, set on its administration page D20
?10 Which OBR host for pilot 1? Production, with v7's Burundi settings D24
?11 Rwanda's source? The rwandatrade.rw tariff API D21
?12 Golden cases before step 7.2? At least twenty; known OBR defects exempted by name D25
?13 When may a computed figure reach the public? Deferred until the calculator is finished
?14 Who runs it? UNCTAD for now, then decided with each authority D22
?15 Each country's address? calculator-<country code>.eregistrations.dev D26
Sources
  • The prototype, unctad-ai/tariff-calculator: README.md, server.js, docs/BURUNDI.md, docs/NUEVO-PAIS.md and docs/handover/ at commit 4f0f969, read 28-09-2026; its history from 04-08-2026.
  • The OBR–UNCTAD meeting of 24-09-2026: docs/handover/2026-09-24-reunion-OBR-CNUCED.md.
  • eRegulations v7: eRegulations-4.0-Admin (Business/Tariffs.cs, Model/TariffsModel.cs, Model/Country/TariffsCache.cs, commits 7992fe5 and e4fb388), eRegulations-4.0-Public (Api/Presentation/Controllers/TariffsController.cs, AppCode/TariffsRateLimiting.cs, Views/Tariffs/Index.cshtml, wwwroot/assets/js/views/tariffs.js), eRegulations-deploy (releases/7.x, instances/burundi/instance.yml), local copies read 28-09-2026.
  • unctad-ai/vertical-base as of 26-09-2026: README.md, spec/README.md, docs/method/M1, M4 and M5, docs/foundations.md.
  • Research of 29-09-2026 on customs systems and tariff data: UK Trade Tariff API and its archived duty calculator; EU TARIC; US HTS; Korea UNI-PASS open APIs; WITS/TRAINS; WTO tariff data; the EAC CET 2022 gazette; the WCO Data Model.
  • The review of 29-09-2026: its findings.
  • Not seen: OBR's live service (its test host silent since 04-09-2026); v7 pull requests #120 to #128, merged after the local copy; ITC's Market Access Map, which refused access; any machine-readable EAC CET; the rwandatrade.rw API's terms; vertical-base running, which was read and not installed.
Claude, for the analyst · UNCTAD · working material, hidden from search enginesReviewed 29-09-2026 · every question answered · waiting for the final agreement Updated · 29-09-2026