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
| Check | Refusal | |
|---|---|---|
| 1 | The credential is present and valid | UNAUTHENTICATED |
| 2 | The credential is live and owns its short code | CREDENTIAL_REVOKED |
| 3 | serviceId is a number | VALIDATION_FAILED |
| 4 | The service exists, is yours, and a live grant covers it | SERVICE_NOT_FOUND |
| 5 | The service itself is live: approved and active | SERVICE_NOT_ACTIVE |
| 6 | Your source IP is in that grant's allowlist | IP_NOT_ALLOWLISTED |
| 7 | The grant holds the capability this operation needs | ABILITY_NOT_GRANTED |
| 8 | The rate limit for this grant | RATE_LIMITED |
| 9 | Idempotency: the transaction id is claimed | DUPLICATE_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:
| Refusal | Cause |
|---|---|
SERVICE_NOT_ON_SHORT_CODE | The 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.