Reference data
Every coded value on a declaration is checked against a vocabulary before ITS accepts it. A value that is not in its vocabulary is refused with VAL-ETD-003, naming the field.
Read the vocabularies
The vocabularies are served at /api/reference, outside /api/v1. Any valid token reads them. No permission is needed, so you can load them before the Secretariat has configured anything else.
{entityType} | Fills |
|---|---|
countries | Every country code field (ISO 3166-1 alpha-2) |
currencies | currency and guarantee.currency (ISO 4217) |
customs-offices | departure, destination and every stamp's station |
hs-codes | commodities[].hs_code |
package-kinds | commodities[].kind_of_packages |
terms-of-payment | terms_of_payment |
transport-modes | transport_mode, which ITS assigns |
au-member-states | African Union membership, used for country display names |
| Operation | Path | Query parameters |
|---|---|---|
| List | GET /api/reference/{entityType} | filter, order-by, query, page-number, page-size |
| List active only | GET /api/reference/{entityType}/active | filter, order-by, query, page-number, page-size |
| List currently effective | GET /api/reference/{entityType}/effective | page-number, page-size |
| Search | GET /api/reference/{entityType}/search | query, filter, order-by, page-number, page-size |
| Dataset version | GET /api/reference/{entityType}/version | none |
| One row | GET /api/reference/{entityType}/{id} | none |
| Available datasets | GET /api/reference | none |
| A dataset's fields | GET /api/reference/{entityType}/schema | none |
page-numberis 1-based andpage-sizedefaults to 20. Set it explicitly for the large vocabularies: 5,612 HS codes at 20 a page is 281 requests.filtertakesfield::valueexpressions, such as?filter=sectionCode::K, andorder-bytakes a field name.GET /api/reference/{entityType}/schemalists the fields a dataset has.- Responses use the same
headeranddataenvelope as the rest of the API, withpaginationon lists. - A call with no token is
401. An unknown dataset is404RES-ETD-029.
page and size still work here as deprecated aliases, and nowhere else. Write page-number and page-size.
Cache the large ones
The vocabularies change a few times a year. Cache them and check for changes instead of fetching them again:
GET /api/reference/hs-codes/version
Authorization: Bearer <access_token>
/version returns a row count and a lastModified stamp. Refetch only when they change.
It is read-only
POST, PUT, PATCH and DELETE on /api/reference are refused for everyone, permanently. These vocabularies are shared across many systems, so ITS reads them and never writes them.
If a code your national system uses is genuinely missing, raise it as a data request with the AfCFTA Secretariat. It cannot be added over the API.
Small lists you can hardcode
These lists are short and stable:
Transport modes. ITS carries road transport only, so it assigns 3 and returns it. You do not send it.
| Code | Meaning | Code | Meaning |
|---|---|---|---|
1 | Maritime transport | 6 | Multimodal transport |
2 | Rail transport | 7 | Fixed transport installation |
3 | Road transport | 8 | Inland water transport |
4 | Air transport | 9 | Transport mode not applicable |
5 |
Terms of payment (Incoterms): CAD, CFR, CIF, CIP, CPT, DAP, DDP, DPU, EXW, FAS, FCA, FOB.
Seal types: METALLIC, ELECTRONIC. Anything else is refused with VAL-ETD-005.
HS codes
commodities[].hs_code takes 6 to 12 digits, so a national tariff line of 8 or 10 digits is accepted as it is. Only the first six digits are checked against the HS vocabulary. Digits 7 to 12 are kept, printed and returned exactly as you sent them, and never interpreted.
Customs offices
A customs office is a three-character station_code, [A-Z0-9]{3}, inside a country: every office box is { "country_code": "KE", "station_code": "MBA" }.
Each State Party maintains its own customs offices in the ITS register.
- An office of your own that the register does not list is accepted. Your country is the authority on the offices it operates. The code is stored as sent, the response is still
201or200, andheader.additional_detailsnames the code so you learn about it at once. - An office in another country is refused (
VAL-ETD-004). You cannot vouch for an office you do not operate. - The one exception is the office of destination when the destination country is not on ITS. It is stored as sent and reported in
additional_details. It must still be in the destination country (VAL-ETD-081). - Entry and exit need a border office. A stamp at an office the register records as
INLANDis refused withBUS-ETD-083. An office nobody has described yet is accepted.
To see the codes of yours that the register does not list:
GET /etd/reconciliation/stations
{
"data": [
{
"country_code": "UG",
"station_code": "QQ1",
"occurrences": 412,
"first_seen_at": "2026-07-02T08:11:04+03:00",
"last_seen_at": "2026-08-13T06:40:19+03:00"
}
]
}
occurrences and last_seen_at tell a typo from a missing border post. Seen once a month ago is a typo to correct on one declaration. Seen four hundred times in the last hour is an office to add to your register. Add it and the row disappears from the next read.
Taxpayer identification numbers
ITS records a TIN exactly as you send it. It does not check the format and holds no register of formats. Validate your own taxpayer numbers before you submit.
declarant.tin (TD field 34) is still required: a declaration has to say who filed it.
Country names
Responses carry country_name beside the codes in office boxes, and country_of_origin_name on each commodity. These are the African Union's names for its member states, such as Côte d'Ivoire and DR Congo, and the ISO name for any other country.
Do not key anything on these names. The code is the identifier. You send only the two-letter code.