Business Gateway
Reference

Error codes

The stable code values, what causes them, and what to do.

Failures come back as:

{ "error": { "code": "VALIDATION_FAILED", "message": "…" } }

code is stable and is what your software should branch on. message is written for people and its wording may change.

The document itself

CodeHTTPCause
PEPPOL_VALIDATION_FAILED400The document does not satisfy the Peppol rules for its type
VALIDATION_FAILED400The request was malformed: a bad field, an unknown JSON key, a cursor that does not parse
INVALID_JSON400The body is not JSON at all, or not the shape the route expects
VALIDATION_UNAVAILABLE400 / 503The document could not be checked. Retry later; it is not a verdict
PEPPOL_DOCUMENT_NOT_SUPPORTED400No capability covers this document type in this direction
PEPPOL_RECIPIENT_NOT_FOUND400The receiving address is not known to us
PEPPOL_DISCOVERY_FAILED400 / 503The recipient could not be looked up on the network
PEPPOL_LOCAL_PARTICIPANT400The sender is a local participant — a sandbox company's, for instance — which is not published on the network and cannot send onto it
PAYLOAD_TOO_LARGE413Over the size limit for the body or the document
VALIDATION_ERROR502POST /v1/validate only: the check ran but its answer could not be read. Not your document's fault, and retrying will not change it

A validation failure is yours to fix — resending the same bytes fails again. A discovery failure is often the recipient's address being wrong, or their registration not covering the document type.

Credentials and access

CodeHTTPCause
UNAUTHORIZED401Missing, malformed or revoked credential
FORBIDDEN403The credential is valid but not allowed here
PERMISSION_DENIED403The API key lacks the permission this route needs
PASSWORD_CHANGE_REQUIRED403The user must set a new password first
ACCOUNT_CLOSED / COMPANY_CLOSED403The credential belongs to an account or company that has been closed
OPERATOR_MANAGED400Changing an SFTP login's method, status or company is done for you, not over the API; you can only issue a new password
NOT_FOUND404Missing, out of your scope, or not a valid id

NOT_FOUND is deliberately returned for things that exist but are outside your scope. A credential confined to one company cannot tell the difference between another company's document and one that was never created — that is the point.

State and conflicts

CodeHTTPCause
CONFLICT409It already exists
INVALID_STATE409The action does not apply in the current lifecycle state
IDEMPOTENCY_CONFLICT409The same Idempotency-Key with a different body
IDENTIFIER_TAKEN409That company or participant identifier is in use
IDENTIFIER_IN_USE409The identifier cannot change while an SFTP login uses it as its directory
EMAIL_CONFLICT409That email already belongs to a user
COMPANY_REQUIRED400Your credential reaches several companies and the request did not name one
ACCOUNT_CLOSED / COMPANY_CLOSED409Closed, and not accepting changes
LAST_OWNER / LAST_API_KEY409Removing it would leave no way in
COMPANY_NOT_DEREGISTERED409A company can only be deleted once every participant under it is DEACTIVATED
NOT_SANDBOX409Simulated inbound documents are only for companies created with sandbox: true

Company verification (KYC)

CodeHTTPCause
KYC_USE_ONBOARDING_LINK403API keys cannot do a company's KYC. Issue an onboarding link and hand it to the company
KYC_LOCKED409The company is verified; its registration number and country can no longer be changed over the API
KYC_NOT_CONFIGURED501Verification is not offered here
KYC_ONBOARDING_LINK_INVALID400The onboarding link is unknown, replaced by a newer one, or expired
KYC_SIGNING_LINK_INVALID400The signing link is unknown, used, declined or expired
KYC_DOCUMENT_NOT_SEALED400The register extract is not the sealed original — a scan, a print or a re-saved copy
KYC_DOCUMENT_NOT_FROM_REGISTER400The extract was not issued by the company register
KYC_DOCUMENT_TOO_OLD400The extract is older than 90 days
KYC_ORG_NUMBER_MISMATCH400The extract is for a different registration number than the company's
KYC_DOCUMENT_UNREADABLE400The extract could not be read
KYC_MANUAL_REQUIRED400The company's country has no register extract to upload; enter its details instead
KYC_SIGNATORIES_INSUFFICIENT400The chosen signers cannot bind the company together
KYC_NO_AGREEMENT409There is no agreement published to sign. Contact support

Rate limiting and availability

CodeHTTPCause
RATE_LIMITED429Too many requests. Wait for the number of seconds in Retry-After
PEPPOL_UNAVAILABLE503A dependency is down. Retry with backoff
PEPPOL_INTERNAL_ERROR500Our fault. Retrying an identical request rarely helps

Signing in to the console

These come from the sign-in and account-security routes the console uses. An integration working with an API key does not meet them.

CodeHTTPCause
RESET_TOKEN_INVALID400The password-reset or invitation link is unknown, expired or already used
CURRENT_PASSWORD_REQUIRED / CURRENT_PASSWORD_INVALID400Changing your own password needs your current one, and it was missing or wrong
PASSWORD_CHANGE_NOT_ALLOWED_FOR_SSO_SESSION403You signed in with single sign-on, so there is no password here to change
SSO_NOT_LINKED401That single sign-on identity is not linked to a user
SSO_EMAIL_MISMATCH400The identity's email address does not match the user's
PASSKEY_REJECTED400The passkey could not be verified
PASSKEY_CHALLENGE_EXPIRED400The passkey challenge expired or was already used; start over
PASSKEY_CLONE_DETECTED401The authenticator reported a counter that went backwards — the passkey may have been copied
PASSKEY_ALREADY_REGISTERED / PASSKEY_LIMIT409This authenticator already has a passkey here, or the user has as many as allowed
PASSKEYS_NOT_CONFIGURED501Passkeys are not offered here

What to retry

Retry 429 RATE_LIMITED after Retry-After, and 503 with exponential backoff. Both are temporary by definition.

Do not retry a 4xx unchanged — the answer will not differ. The exception is VALIDATION_UNAVAILABLE, which says the check could not be run rather than that it failed.

Always carry an Idempotency-Key on sends, so that a retry after a timeout — where you never learned whether the first attempt landed — cannot produce a second document.

On this page