SAPI-SK: error codes

All errors on /sapi use a uniform envelope with a structured error object: a machine-readable code and category, an explicit retryable flag, and a correlation_id for tracing in logs and support.

Error shape

{
  "error": {
    "category": "VALIDATION",
    "code": "SAPI-VAL-001",
    "message": "Invalid send request",
    "details": [
      { "field": "metadata.documentId", "issue": "Required" }
    ],
    "retryable": false,
    "correlation_id": "550e8400-e29b-41d4-a716-446655440000"
  }
}

The details field is optional (e.g. field-level validation). category takes values AUTH, VALIDATION, PROCESSING, TEMPORARY, and PERMANENT.

Code catalog

HTTPCodeCategoryRetryableMeaning
401SAPI-AUTH-001AUTHnoInvalid client credentials.
401SAPI-AUTH-002AUTHnoThe access token is invalid or expired.
403SAPI-AUTH-003AUTHnoThe client has no access to the given organization / Peppol participant.
403SAPI-AUTH-004AUTHnoThe IP address is not on the client's allowlist.
423SAPI-AUTH-005AUTHyesThe client is temporarily locked after 5 failed attempts (15 min).
400SAPI-VAL-001VALIDATIONnoMalformed request: bad JSON, missing field, or missing required header (Idempotency-Key, X-Peppol-Participant-Id).
400SAPI-VAL-002VALIDATIONnoX-Peppol-Participant-Id does not match metadata.senderParticipantId.
400SAPI-VAL-003VALIDATIONnoThe SHA-256 checksum does not match the payload.
400SAPI-VAL-004VALIDATIONnoThe payload exceeds the 10 MB limit.
400SAPI-VAL-005VALIDATIONnoThe document failed Peppol validation, or its number collides with a natively issued invoice (nothing was sent).
404SAPI-VAL-006VALIDATIONnoThe document does not exist or you don't have access to it.
409SAPI-PROC-001PROCESSINGnoThe Idempotency-Key was already used with a different request body.
422SAPI-PROC-002PERMANENTnoInsufficient credit to send.
500SAPI-PROC-003PROCESSINGnoInternal processing error.
429SAPI-TMP-001TEMPORARYyesRate limit exceeded: respect Retry-After.
502SAPI-TMP-002TEMPORARYyesThe Peppol network is temporarily unavailable: retry with exponential backoff.
Only retry when retryable: true (categories TEMPORARY and the SAPI-AUTH-005 lockout), and always with exponential backoff. On 429, respect the Retry-After header.

Recommendations

Don't retry 4xx errors (other than 429 and the 423 lockout) without changing the request: the retryable field is false. On 423, wait 15 minutes and retry the same request. When sending, store the providerDocumentId and use a stable Idempotency-Key to avoid duplicates on retry. Include the correlation_id when contacting support.