Every error returns the same envelope with a stable code you can branch on and a human-readable message.
{ "error": { "code": "INSUFFICIENT_CREDIT", "message": "Top up your balance to issue cards" } }
HTTP status mapping
| Status | Meaning |
|---|
400 | Invalid request — bad or missing input |
401 | Missing or invalid credentials |
402 | Payment required — insufficient platform credit |
403 | Authenticated, but not permitted |
404 | Resource not found or out of scope |
409 | Conflict — resource already exists |
410 | Gone — link expired |
500 | Internal error — safe to retry later |
Common codes
| Code | When |
|---|
UNAUTHORIZED | No valid bearer token on a protected route |
INVALID_CLIENT | Bad client_id / client_secret at the token endpoint |
INVALID_CREDENTIALS | Wrong email or password |
FORBIDDEN | Role lacks access to the resource or action |
NOT_FOUND | Resource missing or not visible to your org |
INVALID_REQUEST | Validation failed (e.g. applicant not approved, missing program_id / account_id / cardholder_id, or verified address missing state) |
APPLICANT_ALREADY_EXISTS | Duplicate applicant for the organization |
INSUFFICIENT_CREDIT | Not enough balance to cover the issuance fee |
KYC_INCOMPLETE | Action requires an approved applicant |
ISSUER_KYC_INCOMPLETE | Tenant KYC passed but issuer identity is not ready — call POST /v1/applicants/{id}/submit or kyc-share, then poll GET …/kyc-status until issuerKycReady is true |
KYC_NOT_APPROVED | kyc-share called before tenant attestation of approval |
KYC_SHARE_REJECTED | BYOK share token invalid, expired, or not addressed to Apocor’s shareRecipientId |
KYC_SHARE_FAILED | Sumsub could not import the tenant share token |
KYC_NOT_CONFIGURED | Sumsub or issuer share recipients are not configured on the platform |
RAIL_NOT_CONFIGURED | Live issuer rail credentials are missing — card issuance requires Interlace |
RAIL_ACCOUNT_MISSING | Issuer sub-account could not be created — applicant email is required |
EXTERNAL_SERVICE_ERROR | Upstream issuer failure (budget, cardholder, or card creation). Common causes: issuer account not initialized, or verified address missing state |
ISSUER_ERROR | Upstream issuer rejected the request (e.g. cardholder at card limit, duplicate spend control). Message contains the issuer detail |
NOT_IMPLEMENTED | Action requires live issuer configuration that is not enabled |
WEAK_PASSWORD | Password below the minimum length |
INVITE_EXPIRED | Onboarding link is no longer valid |
INTERNAL_ERROR | Unexpected server error |
Branch on error.code, not on error.message. Codes are stable across releases; messages may be reworded.