Error reference
The canonical Apier error reference — the standard error envelope, the explanation and handover schemas, and the full structured error_code catalogue.
[Cite this as: Apier.no Docs v0.1.0 — last updated 2026-06-23]
Every Apier API error returns the same structured envelope, so your agent can branch on a machine-readable error_code instead of string-matching prose. This page is the canonical reference for that envelope, the explanation object it carries, and every error_code the API can emit.
The error envelope
Every 4xx and 5xx response from /api/v1/* has the same top-level shape — { success: false, error_code, explanation, _meta }:
{
"success": false,
"error_code": "AUTH_NO_DELEGATION",
"explanation": {
"summary": "Ingen aktiv systembruker-delegering finnes for 999999999.",
"why": "Konsumenten har ingen aktiv systembruker-delegering hos Altinn for 999999999.",
"fix_steps": [
"Opprett en systembruker via altinn.no/systembruker og knytt den til integrasjonen.",
"Be en signaturberettiget godkjenne delegeringen i Altinn.",
"Gjenta forespørselen når delegeringen vises som aktiv."
],
"relevant_link": "https://altinn.no/systembruker",
"legal_basis": null,
"handover": {
"who": "company_admin",
"where": "https://altinn.no/systembruker",
"what": "Opprette systembruker og godkjenne delegering for 999999999.",
"why": "Uten delegering har systembrukeren ingen rettigheter på vegne av organisasjonen."
}
},
"_meta": {
"rulebook_version": "2026.6.0",
"data_freshness": "2026-06-23T08:00:00Z"
}
}success is always false on an error. error_code is a stable machine string from the catalogue below. explanation is human-and-agent readable, and all of its prose is Norwegian bokmål. _meta rides on errors too, so your agent can diff the rulebook_version it last saw against the one that just failed. Every value above is synthetic — 999999999 is the documentation fixture organisation number.
The explanation object
explanation always carries a summary; every other field is optional and present only when it applies. The type is ApiErrorExplanation in src/types/api.ts.
| Field | Required | Meaning |
|---|---|---|
summary | Required | One-sentence statement of what went wrong. |
why | Optional | Longer explanation of the cause, in Norwegian bokmål. |
fix_steps | Optional | Ordered, imperative next steps the caller can take. |
relevant_link | Optional | Public Altinn / Skatteetaten / Brønnøysund / Apier-docs URL for this error. |
legal_basis | Optional | Lovdata-style legal reference when the error maps to a statute. |
details | Optional | Field-level validation problems as [{ field, message }]. |
handover | Optional | Present when a human must act before the agent can proceed (see below). |
The handover object
When an agent reaches a boundary it cannot cross on its own — an Altinn role that isn't delegated, a Maskinporten scope that isn't granted, or an error that needs Apier triage — explanation.handover names who must step in. It is absent for errors the agent can resolve itself by retrying, adjusting input, or waiting.
| Field | Meaning |
|---|---|
who | The human role to escalate to — one of company_admin, accountant, altinn_user, apier_support. |
where | A stable URL or location where that person performs the action. |
what | The concrete action they must take. |
why | Why the agent itself cannot complete it. |
error_code catalogue
The authoritative list is the EXPLAINER_ERROR_CODES tuple in src/types/explainer.ts — 38 codes, grouped below by theme. Each code's enriched explanation (summary, fix steps, handover) is produced by the Compliance Explainer in src/lib/compliance/explainer.ts.
Auth & delegation
| Code | Meaning |
|---|---|
AUTH_INSUFFICIENT_ROLE | The system user lacks the required Altinn role for this action. |
AUTH_NO_DELEGATION | No active Altinn system-user delegation exists for the organisation. |
AUTH_MISSING_DELEGATION | Semantic alias of AUTH_NO_DELEGATION — same explanation, surfaced by the sandbox ?simulate_error= flow. |
AUTH_EXPIRED_TOKEN | The one-time approval token was valid earlier but its lifetime has elapsed. |
Validation & lookup
| Code | Meaning |
|---|---|
VALIDATION_FAILED | The request failed schema validation at the API boundary — correct the input field. |
NOT_FOUND | The requested resource was not found in the source register. |
COMPANY_NOT_FOUND | The organisation number was not found in Brønnøysund — deregistered, not yet registered, or wrong. |
DEADLINE_PASSED | The filing deadline had already passed at call time. |
REQUEST_TOO_LARGE | The request body exceeds the 256 KB limit for write calls. |
Scope & plan
| Code | Meaning |
|---|---|
SCOPE_MISSING | The required Maskinporten scope is not in the consumer's grant. |
SCOPE_INSUFFICIENT_FOR_ACTION | The active delegation does not cover every Maskinporten scope the action type requires (see missing_scopes). |
PLAN_INSUFFICIENT | The action is unavailable on the live path — either the tier does not cover writes, or the action type is not live-enabled yet. |
Idempotency
| Code | Meaning |
|---|---|
IDEMPOTENCY_KEY_REQUIRED | The write call requires an Idempotency-Key header. |
IDEMPOTENCY_KEY_MISMATCH | The same Idempotency-Key was reused with a different request body. |
IDEMPOTENCY_IN_PROGRESS | An earlier request with the same Idempotency-Key is still being processed. |
Approval & risk
| Code | Meaning |
|---|---|
APPROVAL_TOKEN_REQUIRED | The write needs a time-boxed, human-approved token; rejected before any upstream call. |
APPROVAL_TOKEN_INVALID | The approval token is unknown or malformed — existence is deliberately not disclosed. |
APPROVAL_TOKEN_USED | The approval token has already been consumed — single-use, even on a failed attempt. |
APPROVAL_TOKEN_EXPIRED | The approval token passed its short lifetime before the request was sent. |
APPROVAL_TOKEN_MISMATCH | The token was minted for a different action_id or organisation than the request. |
RISK_ELEVATED | The anomaly detector requires human approval; obtain an approval token and retry. |
Execution & circuit
| Code | Meaning |
|---|---|
EXECUTION_FAILED | A valid, approved submission could not be completed against the upstream. |
EXECUTION_TIMEOUT | The submission timed out; whether it registered upstream is unknown until polled. |
EXECUTION_DEADLINE_EXCEEDED | The request exceeded Apier's 8-second total execution budget. |
EXECUTION_CIRCUIT_OPEN | Apier's circuit breaker is open for this upstream; new requests are rejected for about 30 seconds. |
RETRY_BUDGET_EXHAUSTED | Apier exhausted its retry budget (up to three attempts) without success. |
FOLLOWUP_REQUIRED | The action is partially complete; read outcome.followup_action to finish it. |
Government & upstream
| Code | Meaning |
|---|---|
UPSTREAM_UNAVAILABLE | The named upstream service is unavailable or timed out. |
GOVERNMENT_API_ERROR | The submission reached the upstream but was rejected with an operational error. |
GOVERNMENT_RATE_LIMITED | The government API responded 429; Apier respects the quota and did not execute the call. |
GOVERNMENT_UNAVAILABLE | The government API returned a 5xx or dropped the connection; Apier retried and gave up. |
GOVERNMENT_VALIDATION_REJECTED | The government API rejected the content — format, totals, or missing required fields. |
MASKINPORTEN_AUTH_FAILED | Maskinporten rejected Apier's token request — server-side; the client cannot fix it. |
ALTINN_DELEGATION_MISSING | Altinn returned 401/403 — Apier's system user has no active delegation for the organisation. |
Rate limiting
| Code | Meaning |
|---|---|
RATE_LIMIT_EXCEEDED | The API key hit its per-minute rate limit for this route and tier. |
Sandbox
| Code | Meaning |
|---|---|
SANDBOX_TEST_KEY_REQUIRED | A sandbox magic feature (X-Apier-Simulate or ?as_of=) requires the synthetic sandbox bearer, not a real key. |
General & fallback
| Code | Meaning |
|---|---|
INTERNAL_ERROR | An unexpected internal error on Apier; the cause is not in the request content. |
UNKNOWN | The error could not be classified against a known code — the safe fallback. |
Get a live explanation
Every code above can be expanded into a full explanation object on demand. POST /api/v1/explain is a zero-auth endpoint (no API key needed) that takes an error_code plus an optional context and returns the canonical explanation — the same object the API attaches to a real error. It makes no upstream calls and stores no data.
curl -X POST https://apier.no/api/v1/explain \
-H "Content-Type: application/json" \
-d '{ "error_code": "AUTH_NO_DELEGATION", "context": { "org_number": "999999999" } }'The response wraps the explanation in the standard success envelope:
{
"success": true,
"data": {
"explanation": {
"error_code": "AUTH_NO_DELEGATION",
"summary": "Ingen aktiv systembruker-delegering finnes for 999999999.",
"why": "Konsumenten har ingen aktiv systembruker-delegering hos Altinn for 999999999.",
"fix_steps": [
"Opprett en systembruker via altinn.no/systembruker og knytt den til integrasjonen.",
"Be en signaturberettiget godkjenne delegeringen i Altinn.",
"Gjenta forespørselen når delegeringen vises som aktiv."
],
"relevant_link": "https://altinn.no/systembruker",
"legal_basis": null,
"handover": {
"who": "company_admin",
"where": "https://altinn.no/systembruker",
"what": "Opprette systembruker og godkjenne delegering for 999999999.",
"why": "Uten delegering har systembrukeren ingen rettigheter på vegne av organisasjonen."
}
}
},
"_meta": {
"rulebook_version": "2026.6.0"
}
}The context fields (org_number, scope, role, field, upstream_system) are interpolated into the Norwegian text wherever the template references them; omit them and the explanation falls back to a neutral Norwegian noun. The standard trust _meta block rides on the response alongside rulebook_version.
Going deeper
This page is the canonical index. For a walkthrough of handling these errors in agent code — retry strategy, the human-handover boundary, and worked examples — see Error handling and the Compliance Explainer.