Skip to main content

Order of checks

Every request passes through the same checks in the same order, and the first one that fails is the one you are told about.

This matters more than it sounds. A refusal names the earliest problem, not the only one, so fixing it can reveal the next. If you are setting up a new integration and each fix produces a different refusal, that is the system working, not a moving target.

The order

CheckRefusal
1The credential is present and validUNAUTHENTICATED
2The credential is live and owns its short codeCREDENTIAL_REVOKED
3serviceId is a numberVALIDATION_FAILED
4The service exists, is yours, and a live grant covers itSERVICE_NOT_FOUND
5The service itself is live: approved and activeSERVICE_NOT_ACTIVE
6Your source IP is in that grant's allowlistIP_NOT_ALLOWLISTED
7The grant holds the capability this operation needsABILITY_NOT_GRANTED
8The rate limit for this grantRATE_LIMITED
9Idempotency: the transaction id is claimedDUPLICATE_TRANSACTION_ID

Step 3 exists because of a change, and it tells you when you have hit it. serviceId used to be a 26-character string. It is now a number, and a request still sending the old form is refused here with a message saying so, rather than failing further in as something harder to read.

Then, and only then, your request body

The eight checks above are authorisation. Once they pass, the request runs, and it can still be refused on its own contents. The one that surprises integrators most:

RefusalCause
SERVICE_NOT_ON_SHORT_CODEThe shortCode in your request body is not the short code the serviceId sits on.

That is a field mismatch, not a credential problem. It arrives after everything above has passed, so if you see it, your token, your grant, your address and your capability are all correct and the two values in your own body disagree.

Why this order

Cheapest and most damaging first. There is no point resolving a service for a caller who has no valid credential, and no point running a fraud check for a request that will be rate limited.

The IP allowlist sits at step 6 rather than step 1 for a specific reason: the allowlist belongs to the grant, and there is no grant until the credential and the route are both known. So a request with a valid token from an unlisted address gets past the earlier checks before being refused, which is correct, not a leak.

SERVICE_NOT_ACTIVE (step 5) is worth recognising during onboarding. It means everything about you is right and the service is paused or still awaiting approval. You will meet it before any answer about your address or your capability, so it is not a sign that either of those is wrong, and it is not something you can fix from your side.

Reading a refusal

Each check answers a different question, so the code tells you where to look:

  • 1–2 → your token. Is it the right one, and is it still live?
  • 3 → the shape of serviceId. You are sending something that is not a number.
  • 4 → your access, or the service itself. The token is fine. One answer covers does not exist, is not yours, has been removed, and your grant on it has lapsed - deliberately, so that nobody can map the platform's services by asking about them one at a time. If you expected this service to work, the operator team can tell you which of the four it is; the API will not.
  • 5 → the service, not you. Nothing on your side will change it. Contact the operator if it is unexpected.
  • 6 → your network. Compare the address in the response with what you registered.
  • 7 → your permissions. Valid, authorised for the service, not for this operation.
  • 8–9 → your behaviour. Slow down, or generate a fresh transaction id.
  • SERVICE_NOT_ON_SHORT_CODE → your request body, and nothing above it.