Cerrtify

Errors

Error envelope, common codes, and how to handle them.

All Cerrtify errors return a JSON envelope:

{ "error": "error_code", "detail": "human-readable message" }

The error field is a stable machine-readable code; detail is a human-readable message that may change.

Common codes

CodeHTTPMeaning
bad_json400Request body is not valid JSON
invalid_request400Required field missing or malformed
invalid_ip400endUserIp is not a valid IPv4/IPv6 address
missing_orderRef400orderRef field required but missing
invalid_orgnr400orgnr is not a valid 10-digit organisationsnummer
query_too_short400Company search q is under 2 characters
query_too_long400Company search q is over 100 characters
missing_job_id400No job id in the path — call /service/jobs/{id}
read_body400The request body could not be read to the end (dropped connection, wrong Content-Length)
no_active_qr_session404The order has no active QR session (already complete or canceled)
missing_api_key401X-API-Key header missing
invalid_api_key401Key does not exist or wrong format
unauthorized401Generic auth failure
insufficient_credits402Your organisation is out of credits (production only) — top up in the dashboard. Note: this error uses a message field instead of detail
api_key_revoked403Key was revoked in the dashboard
api_key_expired403Key passed its expires_at
organisation_inactive403Your organisation is no longer active
insufficient_scope403The key lacks the scope this endpoint requires (bankid, persondata, or company)
spar_not_configured403Production: no SPAR certificate is configured for your organisation — upload one in the dashboard under Certifikat → SPAR
ip_not_allowed403Request IP is not in your organisation's IP allowlist
origin_not_allowed403Browser Origin not in your domain allowlist
invalid_origin403Browser Origin header is malformed
job_not_found404Async job ID does not exist or belongs to another organisation
company_not_found404Sandbox only: the org.nr is not one of the sandbox test companies
rate_limited429Per-key rate limit exceeded — retry after the Retry-After header
search_failed500The company register search failed server-side — retry, then report it if it persists
internal500Unexpected server error while reading an async job
upstream_unavailable502The upstream provider is down or failing right now — see Upstream outages
bankid_response_parse502BankID answered, but with a body we could not parse
upstream_parse_error502SPAR answered, but with a body we could not parse
enqueue_failed503Async job queue is unavailable
audit_unavailable503A regulated call (persondata, company) could not be audit-logged, so it was refused
service_unavailable503A required upstream (SPAR, BankID, Bolagsverket) is misconfigured server-side

Upstream outages

When an upstream provider is unreachable or returning server errors, the API responds 502 with a standardized envelope naming the affected service:

{
  "error": "upstream_unavailable",
  "service": "bankid",
  "message": "There is currently a problem with BankID. Please try again shortly."
}

service is one of bankid, persondata, or company (more may be added as services launch). The problem is on the provider's side — retry with backoff or surface the message to your user.

This only covers genuine outages. Provider-level 4xx protocol errors (e.g. an invalid BankID orderRef) still pass through unchanged with the provider's own response body, so you keep full error fidelity.

Two other 502s are not part of that envelope: bankid_response_parse and upstream_parse_error. There the provider did answer, but with something we could not parse, so there is no service or message field — only the standard error (and sometimes detail). Treat them like upstream_unavailable: retry with backoff.

On this page