Skip to main content

Errors and troubleshooting

Find what you see below, then follow the action. The error catalogue lists every code. When you ask for help, share the HTTP status, the error code and the correlation id. Never share your client secret, your private key or an access token.

What a refusal looks like

A refusal uses the same envelope as a success. The code is in header.additional_details:

{
"header": {
"response_code": 400,
"response_message": "Validation failed",
"additional_details": "Error code: ERR-015. CorrelationId: ... 2 validation error(s)",
"correlation_id": "8f1c9a2e-3b7d-4c11-9f8a-2d5e7b0c4a13"
},
"validation_errors": [
{ "field": "general_information.departure", "message": "must not be null" },
{ "field": "commodities", "message": "must not be empty" }
]
}
  • Match on the code, never on the message. The code is stable. The message may change or be translated.
  • A structural validation failure names every field at once. validation_errors[].field is a dotted path into data, such as commodities[0].hs_code, so you can fix a payload in one round trip.
  • Log the correlation id. It is also in the X-Correlation-ID response header. You can send your own X-Correlation-ID on a request; ITS then records that value.

Refusals from the Idempotency-Key check happen before the request reaches ITS's own error handling, and use a shorter shape:

{
"code": "VAL-IDEM-001",
"error": "The Idempotency-Key header is required on this endpoint",
"category": "VALIDATION"
}

Code prefixes

PrefixKindTypical HTTP
VAL-Validation: the request is not acceptable as sent400
BUS-Business rule: the request is valid but not allowed now409, sometimes 400 or 412
AUTHZ-Authorisation: you may not do this, or not for this country403
RES-Resource: not found, or not yours404
INT-Integration: a deployment or partner-system problem, not your request502 or 503
SYS-System: ITS could not complete the request500 or 503
ERR-Platform: refused before any ITS rule ranvaries

The codes you will meet most

CodeHTTPMeaningWhat to do
ERR-015400Structural validation failedRead validation_errors and fix every field it names
VAL-ETD-003400A value is not in its reference vocabularyCheck the code against Reference data
VAL-ETD-004400The station does not exist or is in another countryYou can only stamp at your own offices
VAL-ETD-007400Invalid route: same departure and destination, next_country_code missing on an exit or sent on another act, or a destination trying to exitSee Lifecycle and stamps
VAL-ETD-034400A listing filter, order-by or tz could not be readThe message names what was wrong
VAL-ETD-064400Not a stamping actUse entry, depart, exit or discharge
VAL-IDEM-001400Idempotency-Key missingSend one on every stamp, cancellation and acknowledgement
VAL-IDEM-003422The key was already used with a different bodyUse a new key for a new act; reuse a key only for an identical retry
BUS-IDEM-002409A request with this key is still runningWait, then retry with the same key
AUTHZ-ETD-008403Not your country's turn to actSee Who may act, and when
AUTHZ-ETD-014403Your credential cannot be attributed to an organisationContact the Secretariat
AUTHZ-ETD-016403You are not entitled to act for this countryCheck which country you are acting for
AUTHZ-ETD-017403No submission arrangement is recorded for youThe Secretariat must record your participation or delegation
AUTHZ-ETD-021403Section F, the departure formalities, cannot be amendedCorrect a wrong stamp with another stamp
BUS-ETD-009409Not valid in the declaration's current stateRead the declaration and act on its current state
BUS-ETD-063409The goods cannot be released yet: the previous country has not exitedA wait. The message names the country
BUS-ETD-082409Discharge stamped away from the declared office of destinationThe message names the right office
BUS-ETD-083409Entry or exit stamped at an office registered as inlandCheck the station, or correct your register
VAL-ETD-018428An amendment without If-MatchSend the content hash from the ETag
BUS-ETD-019412If-Match is stale: someone amended since you readRead again, reapply your change and resubmit
BUS-ETD-020409The amendment changes nothingNothing to do
VAL-ETD-028400Amendment reason missingSend envelope.amendment_reason
BUS-ETD-022409A concurrent changeSafe to retry
RES-ETD-001404No such declaration, or you may not see itITS will not say which
RES-ETD-030404No announcement of that version for your countryCheck the version_no you acknowledge
SYS-ETD-023503ITS could not sign the version. Nothing was recorded.Retry later

Refused before ITS ran

These come from the HTTP layer, before anything specific to eTDs has run:

CodeHTTPMeaning
ERR-002404No such path. Different from an eTD 404, which means no such declaration or not yours.
ERR-022405The wrong method on a real path. The likeliest cause is an endpoint that moved. See Changes to the API.
ERR-023415Your Content-Type is not one this endpoint reads, or you sent a body with none. Send Content-Type: application/json.
ERR-024406Your Accept header asks for something this endpoint cannot produce.

A 400 with an empty body usually means an unencoded > or < in a filter. Send them as %3E and %3C.

Look up a refusal afterwards

Every refusal is recorded for 90 days. Look it up by its correlation id:

curl --fail-with-body --silent --show-error \
--cert "$ITS_CLIENT_CERT" --key "$ITS_CLIENT_KEY" \
--header "Authorization: Bearer $ITS_TOKEN" \
"$ITS_GATEWAY_URL/etd/rejections?correlation_id=8f1c9a2e-3b7d-4c11-9f8a-2d5e7b0c4a13"
{
"header": { "response_code": 200, "response_message": "SUCCESS" },
"data": [
{
"correlation_id": "8f1c9a2e-3b7d-4c11-9f8a-2d5e7b0c4a13",
"received_at": "2026-08-15T22:41:07.221Z",
"method": "POST",
"path": "/api/v1/etd",
"status": 400,
"error_code": "ERR-015",
"reason": "INVALID_FIELDS",
"validation_errors": [
{
"field": "general_information.departure",
"message": "must not be blank",
"rejected_value": null
}
]
}
]
}
  • Without correlation_id, GET /etd/rejections lists your organisation's refusals, newest first. It takes page-number and page-size (default 10, at most 100).
  • path is the route template, such as /api/v1/etd/{serial_no}, so you can group by it.
  • reason is a coarse group: INVALID_FIELDS, UNKNOWN_VALUE, BUSINESS_RULE, NOT_ENTITLED, NOT_FOUND, RATE_LIMITED, PRECONDITION, UNPARSEABLE or INTERNAL_ERROR. error_code is the precise one.
  • Request bodies are not stored, only the fields and values ITS objected to. Your credentials are never stored.

The notifications feed also sends integration.rejections when ITS refused a number of your requests in a day.

Retry or fix?

What you seeRetry?
4xxNo. Fix the request first. The exceptions are BUS-ETD-022 and BUS-ETD-063, which are safe to retry later, and BUS-ETD-019, which needs a fresh read.
5xxYes, with controlled backoff. Keep the same Idempotency-Key and the same body.
A timeoutYes, with the same Idempotency-Key and body. The first attempt may have landed.
A TLS or certificate errorNo. Investigate. Never turn off certificate checks.

FAQ

Every call returns 403

Check that the Authorization header is actually sent. A call with no token is refused with 403 everywhere under /api/v1, not 401. If the header is there, check the error code: AUTHZ-ETD-017 means the Secretariat has not yet recorded who you may submit for.

My stamp was refused with BUS-ETD-063

The country behind you has not stamped its exit, so you cannot release the goods inland yet. The message names that country. Wait and retry. Your entry stamp was recorded.

My entry answered transition_fired: false

You stamped entry at a one-stop border post before the previous country stamped its exit. The entry is recorded. The state moves when your neighbour exits. It is not an error.

My amendment was refused with 412

Someone changed the declaration after you read it. Every stamp appends a version, so this happens during ordinary movement. Read it again, reapply your change and resubmit with the new ETag.

My amendment cleared fields I did not mean to change

An amendment replaces the whole document. A field you leave out of a section you send is cleared. Read the declaration, change what you need, and send all of it back.

A declaration I expect to see answers 404

Either it does not exist, or your country is not party to it: it did not file it, will not receive it, has not stamped it and has not been named next. ITS will not tell you which.

The list ignores my paging

cursor and limit were removed from GET /etd. An unknown parameter is ignored, so you get page one at the default size. Use page-number and page-size.

I get 405 on an endpoint that used to work

The endpoint moved. See Changes to the API.

My exit named a country with no system on ITS

The exit is recorded and additional_details says so. Nobody is told and nobody can read the declaration through that country. When a country on ITS lies further along the route, name that country on your exits instead.