# Error codes

The `error.code` field is **stable**: branch your logic on it. The `message` is meant for display, is written in French, and may change without notice.

The format and the retry policy are covered in [Errors and idempotency](/en/guides/erreurs).

## Authentication and keys

| Code | HTTP | Meaning |
|---|---|---|
| `PAPI_KEY_MISSING` | 401 | `Authorization` header absent or malformed |
| `PAPI_KEY_INVALID` | 401 | unknown key, wrong secret, or a prefix from another surface |
| `PAPI_KEY_REVOKED` | 401 | key revoked — it will not come back, create a new one |
| `PAPI_KEY_EXPIRED` | 401 | key past its expiry |
| `PAPI_IP_FORBIDDEN` | 403 | calling address outside this key's allow list |
| `PAPI_SCOPE_MISSING` | 403 | the key lacks the required scope — the message names it |
| `PAPI_NOT_ENABLED` | 403 | API access is not open on your account |
| `RESELLER_INACTIVE` | 403 | introducer account inactive or terminated |
| `FEATURE_DISABLED` | 404 | surface not opened — it does not exist for you yet |
| `RATE_LIMIT_EXCEEDED` | 429 | rate limit exceeded — see the `X-RateLimit-*` headers |

## Scope

A resource outside your portfolio is **not found**, never "forbidden": the API does not confirm the existence of what is none of your business.

| Code | HTTP | Meaning |
|---|---|---|
| `COMPANY_NOT_FOUND` | 404 | company does not exist, or is outside your portfolio |
| `TRANSACTION_NOT_FOUND` | 404 | transaction does not exist, or is outside your portfolio |
| `WALLET_NOT_FOUND` | 404 | no wallet for this company |
| `USER_NOT_FOUND` | 404 | account does not exist, or is outside the target company |
| `CREDIT_REQUEST_NOT_FOUND` | 404 | request does not exist, or was filed by another introducer |
| `ENDPOINT_NOT_FOUND` | 404 | no endpoint at this URL on the partner API |
| `RESELLER_NOT_FOUND` | 404 | introducer account not found — valid key on an account that no longer exists |

## Portfolio and client accounts

| Code | HTTP | Meaning |
|---|---|---|
| `COMPANY_ALREADY_EXISTS` | 409 | a company already carries this name, RCCM or NIF |
| `COMPANY_REQUEST_ALREADY_PENDING` | 409 | an onboarding request is already pending for this registration |
| `ACCOUNT_ALREADY_EXISTS` | 409 | an account already exists with the given email or phone |
| `EMAIL_ALREADY_EXISTS` | 409 | an account already exists with this email |
| `PHONE_ALREADY_EXISTS` | 409 | an account already exists with this phone number |
| `RESELLER_SELF_ASSIGNMENT` | 422 | these are an introducer account's details — a client account belongs to the client |
| `RESELLER_COMPANY_QUOTA_EXCEEDED` | 422 | portfolio company cap reached |
| `RESELLER_USER_QUOTA_EXCEEDED` | 422 | per-company account cap reached |
| `ROLE_NOT_ALLOWED` | 422 | role outside the two accepted values (`FLEET_ADMINISTRATOR`, `DAF`) |
| `NO_UPDATABLE_FIELD` | 422 | no updatable field in the body |

## Wallet and credit

| Code | HTTP | Meaning |
|---|---|---|
| `RESELLER_CREDIT_DISABLED` | 403 | payment declaration not open on your account |
| `WALLET_BLOCKED` | 400 | wallet blocked, no movement possible |
| `RESELLER_CREDIT_CAP_EXCEEDED` | 422 | per-operation cap exceeded |
| `RESELLER_DAILY_CAP_EXCEEDED` | 422 | daily cap exceeded, pending requests included |
| `PROOF_REQUIRED` | 400 | proof of payment is mandatory on every declaration |
| `PROOF_NO_FILE` | 400 | no file received under the `files` multipart field |
| `PROOF_TOO_MANY` | 400 | more than 3 proofs |
| `PROOF_TOO_LARGE` | 413 | file above 10 MB |
| `PROOF_INVALID_MIME` | 400 | file type not accepted |
| `PROOF_MIME_MISMATCH` | 400 | file content does not match the declared type |
| `PROOF_INVALID` | 422 | proof missing, deleted, already linked, or from another company |
| `PROOF_NOT_FOUND` | 404 | proof not found or deleted |

## Request

| Code | HTTP | Meaning |
|---|---|---|
| `VALIDATION_ERROR` | 422 | validation failed — `details` names the offending fields |
| `INVALID_PATH_PARAM` | 400 | path identifier is not an integer |
| `INVALID_QUERY_PARAM` | 400 | malformed query parameter |
| `IDEMPOTENCY_KEY_MISSING` | 400 | `X-Idempotency-Key` header absent on a write |
| `IDEMPOTENCY_KEY_TOO_LONG` | 422 | idempotency key above 200 characters |
| `IDEMPOTENCY_CONFLICT` | 409 | same idempotency key, different body |
| `INTERNAL_ERROR` | 500 | server error — retry with backoff and the same idempotency key |

<Callout type="tip" title="Unknown codes">
  This list covers the codes met in day-to-day integration. A code missing from here is handled generically, based on its HTTP status — never silently.
</Callout>
