---
title: "Machine-readable capability manifest (agent discovery)"
method: GET
path: "/api/v1/capabilities"
tags: ["Discovery"]
---

# Machine-readable capability manifest (agent discovery)

`GET /api/v1/capabilities`

## Request

- Base URL: `https://www.apier.no`
- URL: `https://www.apier.no/api/v1/capabilities`
- Auth: none required

Zero-auth, deterministic, cacheable for 1 hour. The agent-first counterpart to this OpenAPI spec: where OpenAPI describes HTTP shapes for humans + tool-generators, `/v1/capabilities` describes WHAT the agent can accomplish at a planning level and pairs each capability with the matching `openapi_operation_id` so the agent can jump into this spec for full signature details.

The manifest is a hand-curated typed constant, NOT auto-derived from route files — that would over-share (internal health checks, cron endpoints) and drift on refactors. Every new public or authenticated endpoint adds an entry here. Capability `id` values and endpoint paths are APPEND-ONLY forever; renaming either is a /v2 break. Agents may cache the response keyed by `id`.

The top-level `rulebook_version` field carries the active Rulebook version and advances in lockstep with `_meta.rulebook_version` whenever the Rulebook is updated.

Categories: `public-tool` (zero-auth discovery / utility), `company-data` (authenticated org reads), `auth` (Altinn delegation broker + approval tokens), `admin` (operator-only, behind `ADMIN_API_KEY`), `discovery` (this endpoint's siblings). `auth: "none"` entries need no Authorization header; `auth: "api_key"` entries need the Bearer consumer key. `tier_minimum` names the lowest consumer tier that may call a capability (`null` when auth is `none` or when the route is admin-only).

Rate-limited at 1000/min per IP via the shared public wrapper.

## Response `200`

Full manifest.

- object
  - `success` true, required
  - `data` object, required
    - `service` 'apier.no', required
    - `version` string, required
    - `rulebook_version` string, required: Active Rulebook version — advances in lockstep with `_meta.rulebook_version`.
    - `locale` 'nb-NO', required
    - `capabilities` CapabilityEntry[], required
      - `id` string, required: Stable dot-separated id (e.g. `public.deadlines`). Never rename.
      - `name_en` string, required: Short English display name.
      - `name_nb` string, required: Short Norwegian display name.
      - `description_en` string, required: One-to-three sentence English description from the agent's perspective.
      - `description_nb` string, required: Norwegian mirror of `description_en`.
      - `endpoint` object, required
        - `method` 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH', required
        - `path` string, required: Path with `{braces}` for parameters, aligned with the path keys in this OpenAPI document (i.e. `/api/v1/...`).
      - `auth` 'none' | 'api_key' | 'admin_api_key', required: `none` = zero-auth. `api_key` = Bearer consumer API key required (tier-gated). `admin_api_key` = Bearer ADMIN_API_KEY operator secret; consumer keys cannot call these paths.
      - `tier_minimum` 'free' | 'starter' | 'professional' | 'enterprise', nullable, required: Lowest consumer tier that may call this capability. Null when auth is `none` or when the route is admin-only.
      - `category` 'public-tool' | 'company-data' | 'auth' | 'admin' | 'discovery' | 'actions' | 'account', required
      - `openapi_operation_id` string, required: Matches the `operationId` elsewhere in this OpenAPI spec. Agents follow it to get full request/response shapes.
      - `example_request` string, required: Minimal curl or query-string example; placeholders for API keys and org numbers.
      - `data_sources` string[], required: Free-form upstream/source tags (e.g. `brreg`, `norges-bank`, `digdir`, `internal-supabase`, `internal-static`).
      - `freshness` 'static' | 'live' | 'cached' | 'on-demand', required: How the underlying data is refreshed.
      - `status` 'live' | 'gated' | 'dry-run', required: Derived operational status for this capability: `live` (callable against production), `dry-run` (validation or synthetic-upstream only — no live submission or live government data yet), or `gated` (built, but requires an approval or scope that is not yet enabled). Derived server-side from the capability's action support and the live state of its upstream government integrations; the value is deterministic, so the same capability and upstream state always produce the same status. An operational signal, not a commercial tier (see `tier_minimum`).
    - `sandbox` CapabilitiesSandboxBlock, required: The `sandbox` block on `GET /api/v1/capabilities` — the agent-discovery surface for the zero-auth sandbox API. The top-level `SandboxSimulateError` parameter description points clients at this block via `/api/v1/capabilities.sandbox.supported_error_codes`; the schema below documents the full shape so generated clients can read every related discovery field (base_url, reserved test orgs, reserved error orgs, supported error codes, CORS posture, determinism contract).
      - `available` true, required: Always `true` while the sandbox is shipping. A future PR that decommissions or temporarily disables the sandbox would flip this to `false` and document the swap on.
      - `base_url` string, uri, required: Origin-rooted base URL for the sandbox surface, e.g. `https://www.apier.no/api/v1/sandbox`. Computed from the request origin so preview / local / production deployments each advertise their own base.
      - `reserved_test_org_numbers` string[], required: Closed list of synthetic test org numbers the sandbox has fixtures for. All `999000XXX`-prefixed mnemonic — DELIBERATELY fail Brønnøysund MOD-11. Source of truth: GET /api/v1/sandbox/fixtures.
      - `magic_state_org_numbers` string[]: The `999660XXX` magic-state orgs — each MOD-11-valid org returns ONE documented company state on the authenticated sandbox read surface (bankrupt, struck-from-register, forced-liquidation, no-roles, not-VAT-registered, ENK, AS, registered-<30-days-ago, joint-signing, prokura-only, and a slow-response org that injects a fixed deterministic delay keyed on its org number). This field is the discovery pointer only; the full per-org state matrix with expected /verify + /authority verdicts lives in the `magic_scenarios` block of GET /api/v1/sandbox/fixtures and on the /sandbox page.
      - `reserved_error_org_numbers` object, required: Map of reserved error org_number → simulated error code. Calling the sandbox with one of these orgs triggers the mapped error response without needing `?simulate_error=`. Currently 999000901-904 → AUTH_MISSING_DELEGATION / AUTH_EXPIRED_TOKEN / VALIDATION_FAILED / SCOPE_MISSING.
      - `simulate_error_param` string, required: Human-readable example of the `?simulate_error=` query template, derived from the four lowercase public tokens.
      - `supported_error_codes` string[], required: Closed list of lowercase public tokens accepted on `?simulate_error=`. Mirrors the runtime `SANDBOX_SIMULATE_ERROR_PUBLIC_TOKENS`. shipped the first four (Apier-edge failure modes); added the upstream-failure block (`altinn_timeout`, `invalid_certificate`, `malformed_payload`, `upstream_5xx`) — each carries a deterministic government-shaped `upstream` envelope on the response body (Altinn RFC 7807, Maskinporten OAuth2, Skatteetaten validationErrors[]) so AI parsers exercise the same defensive parsing they need against production.
      - `cors` 'open', required: CORS posture marker. `open` means `Access-Control-Allow-Origin: *` on every sandbox response — production `/api/v1/*` keeps the restrictive default.
      - `determinism` 'byte-equivalent except _meta.response_timestamp', required: External determinism contract — scoped to the JSON RESPONSE BODY, not the full HTTP response. Every sandbox response BODY is byte-equivalent across calls EXCEPT `_meta.response_timestamp`. HTTP headers (notably `X-Correlation-ID`, which is per-request UUID v4) are NOT covered — clients writing integration tests should diff the parsed JSON body, not the raw HTTP response.
  - `_meta` object, required: `schema_version` is REQUIRED on this agent-first machine interface. Clients may safely key caches or migration logic off its value.
    - `rulebook_version` string, required: Current Rulebook version. Internal rule-version records carry structured origin metadata (`initial_seed` | `human_review` | `lovdata_drift_response` | `audit_finding` | `customer_question` | `legal_correction`) for operator forensics, but that attribution is deliberately NOT exposed on public responses to avoid leaking operational signal.
    - `data_freshness` string, date-time, required: When this data was last fetched (ISO 8601 UTC).
    - `last_verified` string, date-time, required: When this data was last verified against source (ISO 8601 UTC).
    - `source` string, required: Origin of this data. Defaults to `apier.no`. The agent-readiness probe (`GET /api/v1/health/agent-readiness`) is the one surface that may instead emit `apier.no telemetry` — it does so when at least one of its endpoint rates came from measured live telemetry, and falls back to `apier.no` when every rate is a static default; all other endpoints always emit `apier.no`.
    - `data_source` string: Authoritative origin of the underlying data (listed alongside rulebook_version, data_freshness, last_verified, legal_basis for Rulebook-influenced endpoints). Distinct from `source` (the response origin): `data_source` identifies the authoritative data publisher — e.g. 'Brønnøysund Enhetsregisteret + Apier Universal Rulebook'. Present on registry-backed endpoints.
    - `served_from` 'cache' | 'live' | 'static': Cache-aware endpoints only — 'cache' when the response was served from the local copy, 'live' when the gateway just refreshed from the upstream, 'static' when the payload was computed deterministically from pure code with no DB or upstream read (e.g. /v1/public/deadlines). Absent on endpoints that don't carry this semantic.
    - `stale` boolean: Cache-aware endpoints only — true when the upstream was unreachable and a within-limit cached row was served as a fallback. Absent on normal responses.
    - `schema_version` string, required: OpenAPI contract version at the time of the response; matches `info.version`. Always present on every `/v1/*` response so a future schema break can be traced to the exact rows / audit events that predate / postdate it. Agent-facing machine interfaces (v1/capabilities, workflows.json) may override with their own narrower surface version; all other endpoints inherit the manifest-level version.
    - `legal_basis` string: Legal basis under which the response data is reused. Present on Rulebook-influenced endpoints (v1/company/{org}/obligations, /v1/company/{org}/deadlines). Common value: 'NLOD — public registry reuse'.
    - `rule_count` integer: Rule-evaluation count — total rules evaluated for this request. Present on endpoints that invoke the Rulebook evaluator (v1/company/{org}/obligations).
    - `applicable_count` integer: Count of rules whose evaluation_result is 'applicable'. Present on evaluator endpoints.
    - `not_applicable_count` integer: Count of rules whose evaluation_result is 'not_applicable'. Present on evaluator endpoints.
    - `insufficient_data_count` integer: Count of rules whose evaluation_result is 'insufficient_data' (Tier 2 gated). Present on evaluator endpoints. rule_count = applicable_count + not_applicable_count + insufficient_data_count.
    - `cache_age_ms` integer, nullable: Cache layer: milliseconds since the cached row was computed, or null on a cache miss (served_from === 'live'). Agents use it alongside data_freshness as a staleness signal. Present on endpoints wired to the cache (v1/company/{org}/obligations, /deadlines, /summary, /v1/public/obligations, /v1/public/deadlines).
    - `response_time_ms` integer: Speed signal: total server-side processing time in milliseconds, measured via performance.now() at the route boundary. Mirrored on the `X-Apier-Response-Time-Ms` header so agents can key on it without parsing the body. Present on every endpoint.
    - `response_timestamp` string, date-time: RFC 3339 / ISO 8601 UTC timestamp stamped by the response builder at wire-exit. Mirrored on the `provenance_log.response_timestamp` column by a fire-and-forget writer. Distinct from `data_freshness` (when upstream data was fetched) and `last_verified` (when the citation was verified); this is the moment the envelope left the server. Always populated at runtime — deliberately left out of the `required` list to avoid a cascading contract change that would invalidate every pre-existing example envelope in this spec (append-only response contracts). A future revision may promote it into the `required` list alongside a bulk example refresh.
    - `response_hash` string: SHA-256 hash of the canonical-JSON form of the envelope with `_meta` stripped before hashing, prefixed with `sha256:`. Mirrored on `provenance_log.response_hash` so a consumer can independently re-hash the bytes they received and compare against what we persisted (integrity receipt). Stripping `_meta` is load-bearing: volatile fields (response_time_ms, cache_age_ms, served_from) and the hash itself would otherwise feed into the digest and break the cache-hit-bytewise-identical invariant.
    - `source_snapshot_id` string: Optional free-text pointer into an upstream sync snapshot the response derives from — e.g. a Brreg sync's `brreg-<ISO>` snapshot id. Absent when the response is not tied to a specific upstream snapshot (capabilities, tools, static deadlines).
    - `is_sandbox` true: Present and `true` only when the response was generated from sandbox fixture data (currently `ALTINN_MODE=sandbox` on `/api/v1/altinn/list-acting-capacity`). Absent (NOT `false`) on every other response — the absent-vs-false distinction is deliberate so downstream agents branching on `if (response._meta.is_sandbox)` cannot be misled into treating non-sandbox responses as positively-confirmed-not-sandbox. Distinct from the `/v1/sandbox/*` `is_sandbox: true` literal in `SandboxMeta` (which carries the sandbox surface tag); this flag rides through the production `/api/v1/altinn/*` surface to forensically tag a sandbox-mode response that an OEM evaluator received.
    - `cost_nok` number: What this call debited from the caller's prepaid credit balance, in NOK, rendered from the integer-øre ledger (50 øre → 0.5; the ledger itself never leaves whole øre and no float arithmetic touches a balance). Present on the 2xx body of every metered company-data read — the same debit that sets the `X-Credits-Cost-Ore` header, so the two never disagree. `0` when nothing was charged: credit enforcement running dark (the response then also carries `X-Credit-Check: shadow`) or the sandbox surface. Absent on unmetered endpoints and on error envelopes — a refunded 5xx/403/404 claims no cost rather than a wrong one. Lives under `_meta`, which `response_hash` excludes, so the provenance receipt is unaffected; the route's ETag is computed before the credit wrapper stamps it, so a conditional request can still short-circuit to 304. Append-only addition.
    - `wallet_remaining_nok` number, nullable: The prepaid credit balance remaining AFTER this call's debit, in NOK (same rendering as `cost_nok`; mirrors the `X-Credits-Balance-Ore` header). `null` when no balance was read: credit enforcement running dark, or the sandbox surface. Present wherever `cost_nok` is. An agent planning a sequence of metered calls can divide this by the per-call price from GET /api/v1/pricing to know how many reads remain before a 402 INSUFFICIENT_CREDITS. Append-only addition.
    - `spend_cap_remaining_nok` number: What the calling key may still spend under its tighter spend cap (Europe/Oslo calendar day or month) AFTER this call's debit, in NOK (same rendering as `cost_nok`; never below 0). Present on the 2xx body of a metered read only when credit enforcement is live AND the key has a daily or monthly cap (set with PATCH /api/v1/account/keys/{id}); absent otherwise. When it reaches 0 the next metered call on this key returns 402 SPEND_CAP_REACHED until the cap resets. Append-only addition.

## Other responses

- `429`: Per-minute rate limit reached for this (IP, endpoint) bucket on a zero-auth public endpoint. The `Retry-After` header indicates how many seconds to wait before the window resets. Public endpoints share a single soft-cap of 1000 requests per minute PER IP — there is no tier scaling, because callers aren't authenticated. Every allowed response also carries the standard `X-RateLimit-*` headers. On rare infrastructure-side failures the gateway fails OPEN and passes the request through with `X-RateLimit-Check: skipped`.

---

[API](https://skmtc.dev/apier/apis/apier-no-api.md) · [All operations](https://skmtc.dev/apier/apis/apier-no-api/llms.txt) · [OpenAPI document](https://skmtc.dev/apier/apis/apier-no-api/revisions/9ec19bc87311?raw)
