Compliance API bridging AI agents to Norwegian government systems (Altinn, Maskinporten, BRREG)
Bridge AI agents to Norwegian government systems via Altinn, Maskinporten, and BRREG.
Topics
altinnaltinn3mcpmodel-context-protocolnorway
Captured live from the server via tools/list.
get_company_summary
Retrieve a one-shot compliance summary for a Norwegian organisation by its 9-digit organisasjonsnummer (organisation number, the public ID issued by the Brønnøysund Register Centre / Enhetsregisteret — Central Register of Legal Entities). Use this as your FIRST call when orienting against a company: one round-trip COMPOSES entity_type (e.g. AS / Aksjeselskap (limited company), ENK / Enkeltpersonforetak (sole proprietorship), NUF / Norskregistrert utenlandsk foretak (Norwegian branch of a foreign company)), the nace_codes industry classification, mva_registered (VAT-registration tri-state), the served data_tier, the full obligations[] catalogue the Universal Rulebook evaluates (one verdict per applicable rule, each carrying its own per-obligation state), and the rolling deadlines[] filing calendar — all computed from one rule version and one company snapshot so downstream reasoning never has to reconcile drifting views. On tier_1 it also returns upgrade_path, a Norwegian pointer at the Altinn delegation flow (null on tier_2). It deliberately does NOT return the registry identity flat — no legal name, registered municipality, signaturrett (signing authority), prokura (power of procuration), role-holders, or a top-level company-wide status enum; call get_company_context for those identity fields. For deeper drill-down on individual obligations call get_company_obligations; for upcoming filing dates alone call get_company_deadlines. Input: { org_number } as 9 digits passing the Brønnøysund MOD-11 control-digit check. Failure modes the agent must handle: 404 not_found if the org_number is well-formed but unknown; SCOPE_INSUFFICIENT if the API key is not scoped read:brreg; UPSTREAM_TIMEOUT if Brønnøysund is slow; VALIDATION_FAILED on a non-9-digit or mod-11-failing input. For the registry identity flat (legal name, signaturrett, prokura, role-holders) without a compliance verdict, use get_company_context instead.
Retrieve the universal obligation set for a Norwegian entity type. Returns every regulatory obligation that applies by virtue of an entity BEING that organisational form, BEFORE per-company Tier-2 data (employee count, MVA registration, turnover) is layered on. Use this tool when an agent wants to answer 'what does an AS owe?' or 'what are the baseline filings for an Enkeltpersonforetak?' without naming a specific company. Each obligation in the response carries a tier_2_required boolean — true means the rule engine needs commercial data to know whether the obligation actually applies to a SPECIFIC company (e.g. MVA / VAT registration only applies above the NOK 50,000 turnover threshold), false means the obligation applies unconditionally to every entity of that type. Common Norwegian regulatory concepts surfaced in the response include MVA / VAT (Merverdiavgift, Norwegian value-added tax), A-melding (the monthly employer payroll report consolidating tax + payroll-tax + pension data), Aksjonærregisteret (shareholder register filing), and Årsregnskap (annual accounts). Input: { entity_type } from the closed enum AS / ASA / ENK / DA / ANS / SAMVIRKE / STIFTELSE / NUF / OFFENTLIG. For per-company evaluation that DOES layer on commercial data, call get_company_obligations. Failure modes the agent must handle: VALIDATION_FAILED on an unknown entity_type (the enum is closed; there is no 'OTHER' fallback); SCOPE_INSUFFICIENT if the API key is not scoped read:rulebook; UPSTREAM_TIMEOUT on rulebook latency. For a specific company's evaluated obligations rather than the entity-type template, use get_company_obligations instead.
Parameters (1)
entity_typestringrequired
Norwegian organisational form (closed enum): AS / ASA / ENK / DA / ANS / SAMVIRKE / STIFTELSE / NUF / OFFENTLIG.
get_exchange_rate
Fetch the most recent Norges Bank (Norway's central bank, Norges Bank in Norwegian — the official issuer of the krone) exchange-rate reference between two currencies. Norges Bank publishes the daily NOK reference rate at ~16:00 Oslo time and Norwegian tax + accounting authorities (Skatteetaten / Norwegian Tax Administration; Regnskapsloven / Accounting Act) accept it as the canonical conversion benchmark for obligations denominated in foreign currency — including annual accounts (Årsregnskap), MVA / VAT (Merverdiavgift) filings on cross-border transactions, and dividend reporting. Use this tool whenever an agent needs an authoritative NOK rate, OR a NOK-quoted rate against another currency, for a regulatory calculation. The response includes the rate value, the date the rate is valid for (Norges Bank publishes weekday rates only; weekends + Norwegian public holidays return the prior business day's rate), and the source attribution so the agent can cite it back to a user. This is one of the few tools that does NOT depend on Norwegian-company input; it is the currency-of-record lookup. Input: { base, quote } as ISO 4217 three-letter currency codes (uppercase, exactly 3 chars). Either side can be NOK or any other currency Norges Bank publishes. Failure modes the agent must handle: VALIDATION_FAILED on a non-ISO-4217 input; UPSTREAM_TIMEOUT if Norges Bank is slow; 404 not_found if the (base, quote) pair is not in the published set; SCOPE_INSUFFICIENT if the API key is not scoped read:norgesbank. For compliance obligations or filing deadlines rather than a currency rate, use get_company_summary instead.
Parameters (2)
basestringrequired
Base currency — ISO 4217 three-letter code (uppercase).
quotestringrequired
Quote currency — ISO 4217 three-letter code (uppercase).
list_acting_capacity
Resolve every Norwegian regulatory action a person is currently authorised to perform on behalf of a specific organisation. The lookup combines the actor's Altinn role assignments (DAGL — Daglig leder / managing director, LEDE — Styreleder / board chair, MEDL — Styremedlem / board member, NESTL — Nestleder / vice chair, INNH — Innehaver / sole proprietor, REGN — Regnskapsfører / accountant, REVI — Revisor / auditor) with a conservative role-to-action map maintained in `src/lib/altinn/role-action-map.ts`. The response returns the raw Altinn role list AND the derived action tokens an agent may safely pass to /v1/actions/execute downstream, with a per-action `legal_reference` citation pinned to lovdata.no (all 10 entries verified 2026-05-16 — aksjeloven, skatteforvaltningsloven, regnskapsførerloven, revisorloven). Inputs are an 11-digit Norwegian fødselsnummer or D-nummer (which is HMAC-SHA-256 hashed via RECEIPT_HMAC_SECRET before any storage; the raw value is NEVER persisted, NEVER logged, and NEVER returned in the response — the response echoes only `actor.fnr_hmac`) plus the 9-digit Norwegian organisasjonsnummer of the represented entity. Results are cached for up to 1 hour in `resolved_permissions` so repeat lookups within the cache window do not re-hit Altinn; `metadata.cached === true` indicates a cache hit. Required scope: `read:altinn`. PR-MCP-02b: when ALTINN_MODE=sandbox, returns deterministic fixture payloads for OEM evaluation; metadata.data_sources tags as 'altinn-sandbox' and _meta.is_sandbox=true. For your own consumer's delegation snapshot on the org, use check_authorization instead.
Parameters (2)
fnrstringrequired
11-digit Norwegian fødselsnummer / D-nummer of the actor. HMAC-SHA-256 hashed before any storage — the raw value is never persisted, logged, or returned.
org_numberstringrequired
9-digit Norwegian organisasjonsnummer of the represented entity.
get_company_profile
Resolve a Norwegian organisasjonsnummer (9-digit org number) into a structured company profile sourced from Brønnøysund Enhetsregisteret (data.brreg.no). The response carries the company's display name, organisational form (e.g. AS = Aksjeselskap, ENK = Enkeltpersonforetak, ASA = Allmennaksjeselskap), Norwegian industry codes (NACE) with descriptions, the registered street address (forretningsadresse) and any separate business address (postadresse), the Enhetsregisteret registration date, the agent-facing status enum (`active` for operating entities, `dissolved` for entities that have been deleted, gone bankrupt, are under voluntary or forced liquidation), the dissolution date when known (slettedato), the MVA-registered flag (registrertIMvaregisteret), and a deduplicated list of role codes assigned to natural persons (DAGL, LEDE, MEDL, NESTL, INNH, etc.). Per Norwegian data minimisation rules (CLAUDE.md Rule 11), the response deliberately CARRIES role codes ONLY — never personal identifiers (fødselsdato, personnummer, home address, email, phone). The data is Tier 1 public infrastructure under NLOD (Norsk lisens for offentlige data); no delegation is required. Cache TTL is 24 hours (matches Brreg's daily publish cadence); if Brreg is unavailable, the response may serve a stale cached row up to 7 days old with metadata.stale=true and metadata.staleness_seconds populated. Required scope: `read:brreg`. For an evaluated compliance verdict rather than the raw registry profile, use get_company_summary instead.
Return the authorisation snapshot for the calling consumer's delegation on a Norwegian organisation. The response carries: the current `status` enum (`full` / `partial` / `none`); the `missing_scopes` array (Altinn / Maskinporten scope tokens the delegation lacks — empty when status=`full`); the `granted_scopes` array (the scope tokens the delegation already covers); and the `delegation_chain` (ordered list of System-User and consumer-id breadcrumbs the auth gateway walked to derive the verdict). Agents that need to check whether a SPECIFIC regulatory action (submit_mva, file_a_melding, etc.) is permitted should fetch the snapshot via this tool and compare `granted_scopes` to the scopes their target action requires — the rulebook's action→scope mapping is in the openapi.json `x-action-scopes` extension. The evaluation always runs against the calling consumer — there is no per-action and no per-actor input at v1. (The PR-070-tools brief's proposed `action` and `actor_national_id` parameters were dropped to match the route exactly. The underlying /v1/auth/permissions/{org} route does not parse either today; both will land in future PRs once the route adds the parameters AND a canonical fnr validator + shared hashFnr helper extract from PR-MCP-02's inline implementation per SA-001 §3.) Failure modes: SCOPE_INSUFFICIENT if the API key is not scoped read:altinn; VALIDATION_FAILED on shape or mod-11. The underlying endpoint is always a 200 — when no delegation exists for the (consumer, org) pair the verdict is `status: "none"` with the missing scopes enumerated, NOT a 404. Required scope: `read:altinn`. For which actions a SPECIFIC person may perform for the org, use list_acting_capacity instead.
Parameters (1)
org_numberstringrequired
9-digit Norwegian organisasjonsnummer (passing MOD-11) the calling consumer's delegation is checked against.
get_company_context
Retrieve the structured Brønnøysund identity slice for a Norwegian organisation by its 9-digit organisasjonsnummer (organisation number, the public ID issued by the Brønnøysund Register Centre / Enhetsregisteret — Central Register of Legal Entities). The response carries the canonical registry facts: legal name; entity type / organisasjonsform (e.g. AS / Aksjeselskap (limited company), ENK / Enkeltpersonforetak (sole proprietorship), NUF / Norskregistrert utenlandsk foretak (Norwegian branch of a foreign company), ASA / Allmennaksjeselskap (public limited company)); the Norwegian Industrial Classification (NACE) industry codes assigned to the entity; the registered street and postal addresses; the Enhetsregisteret incorporation date; the dissolution date when the entity has been deregistered (`slettedato`); and the role-holder summary (signaturrett / signing-authority and prokura / power-of-procuration role codes assigned to natural persons — codes only, never personal identifiers per the data-minimisation policy). Cache window is 24 hours; cache hits are served from the canonical companies table without re-hitting Brønnøysund. Choose this tool when an agent needs the identity slice ONLY without the rule-engine compliance verdict; pair with get_company_obligations or get_company_deadlines for the regulatory layer. Input: { org_number } as 9 digits passing the Brønnøysund MOD-11 control-digit check. Failure modes: 404 NOT_FOUND if the org_number is well-formed but unknown to Brønnøysund; SCOPE_INSUFFICIENT if the API key is not scoped read:brreg; UPSTREAM_TIMEOUT on Brønnøysund latency; VALIDATION_FAILED on shape or mod-11 failure. Required scope: `read:brreg`. For a compliance verdict (obligations + deadlines) rather than registry identity, use get_company_summary instead.
Compute the upcoming Norwegian regulatory filing calendar for a specific organisation, looking horizon_months into the future. The response is one entry per (obligation, period) pair, each carrying: a stable obligation_id matching get_company_obligations; the due_date as an ISO 8601 timestamp in Europe/Oslo (DST-aware — the engine never hardcodes +01:00 / +02:00 and CET ↔ CEST transitions do not shift due dates by a calendar day); the legal_reference citation; a recurring boolean indicating whether the deadline repeats on a fixed cadence; and a business_day_adjusted boolean indicating whether the engine moved the date to the next Norwegian business day to land off a weekend or public holiday. Choose this tool when the agent needs the calendar view (when does the next MVA / A-melding / Årsregnskap filing land?) rather than the obligation menu. Pair with get_company_obligations to learn what each obligation_id requires. Inputs: { org_number } as 9 digits passing the Brønnøysund MOD-11 control-digit check, plus an optional horizon_months between 1 and 60 (defaults to the endpoint's standard horizon — matches the route's own horizonMonthsSchema clamp). Determinism (Rule 9): same input + same rulebook_version produces a byte-identical calendar. Failure modes: 404 NOT_FOUND for unknown org_numbers; SCOPE_INSUFFICIENT if the API key is not scoped read:brreg; VALIDATION_FAILED on shape, mod-11, or out-of-range horizon (boundary [1, 60] matching the underlying route — round-7 polish widened from [1, 24] so the tool no longer refuses horizons the REST surface accepts). Required scope: `read:brreg` (matches the underlying /v1/company/{org}/deadlines route's `SCOPE_REQUIREMENTS` binding — round-7 polish corrected an earlier `read:rulebook` declaration that would have produced SCOPE_INSUFFICIENT at runtime since the route checks read:brreg). For the per-obligation compliance verdict rather than the date calendar, use get_company_obligations instead.
Look-ahead window in months (1–60). Omitted → the endpoint's default horizon (12).
get_company_obligations
Evaluate the Apier Rulebook for a Norwegian organisation and return every applicable regulatory obligation with its current state and the legal reference it derives from. The response is one entry per obligation, each carrying: a stable obligation_id (e.g. `MVA_FILING_BIMONTHLY`, `A_MELDING_MONTHLY`, `ARSREGNSKAP_FILING`); the legal_reference citation pinning the obligation to lovdata.no (`Skatteforvaltningsloven § 8-3`, `Aksjeloven § 7-6`, etc.); the current state enum (`filed` / `pending` / `in_progress` / `failed` / `overdue` / `unknown`); the bokmål description (description_nb) inherited byte-for-byte from the Rulebook — agents must NEVER re-translate this string; and the freshness window the evaluation is valid until. Determinism (Rule 9): the same org_number plus rulebook_version always produces a byte-identical obligation list. The evaluation always runs against the CURRENT instant — there is no historical-instant input at v1. (The underlying /v1/company/{org}/obligations route does not parse `?as_of=` today; the PR-070-tools brief's proposed `as_of` parameter was dropped to match the route exactly. Historical-instant evaluation lands in a future PR once the route adds the parameter.) Choose this tool when the agent needs the full obligation menu rather than upcoming deadlines (use get_company_deadlines for the calendar view). Failure modes: 404 NOT_FOUND for unknown org_numbers; SCOPE_INSUFFICIENT if the API key is not scoped read:brreg; VALIDATION_FAILED on shape or mod-11. Required scope: `read:brreg` (matches the underlying /v1/company/{org}/obligations route's `SCOPE_REQUIREMENTS` binding — round-7 polish corrected an earlier `read:rulebook` declaration that would have produced SCOPE_INSUFFICIENT at runtime since the route checks read:brreg). For the upcoming filing calendar alone, use get_company_deadlines instead.
Compute the universal Norwegian regulatory filing calendar — the set of deadlines that apply to every Norwegian business of the covered categories (MVA, A-melding, Årsregnskap), independent of any specific organisation. The response is the calendar for a single Europe/Oslo calendar year, one entry per (obligation, period) pair with: a stable obligation_id (e.g. `MVA_FILING_BIMONTHLY`, `A_MELDING_MONTHLY`, `ARSREGNSKAP_FILING`); the due_date as an ISO 8601 timestamp in Europe/Oslo (DST-aware — CET ↔ CEST transitions never shift due dates by a calendar day); the legal_reference citation pinning the deadline to lovdata.no; a recurring boolean; and a business_day_adjusted boolean. Choose this tool when an agent needs the universal calendar (questions like 'when is the next MVA filing deadline' that don't depend on a specific org_number) — it requires no organisasjonsnummer and no scope check beyond rulebook read access. Input: optional `year` (Europe/Oslo calendar year, integer between 2020 and 2100; defaults to the current Oslo year at the endpoint when omitted — a request at 23:30 UTC on 31 Dec is already 00:30 of the next year in Oslo during CET, and the route's default uses the Oslo wall-clock not UTC). Determinism (Rule 9): same input + same rulebook_version produces a byte-identical calendar. Failure modes: SCOPE_INSUFFICIENT if the API key is not scoped read:rulebook; VALIDATION_FAILED on year shape (non-integer, outside 2020–2100; the 2020 lower bound matches the underlying /v1/public/deadlines route's MIN_YEAR — older years aren't in the Rulebook's coverage window). Required scope: `read:rulebook`. For a specific company's filing calendar rather than the universal one, use get_company_deadlines instead.
Parameters (1)
yearinteger
Europe/Oslo calendar year the calendar should cover (2020–2100). Omitted → the current Oslo year at the endpoint.
validate_action
Run the Apier dry-run validator against a proposed regulatory action without producing ANY upstream side effect — no Maskinporten call, no Altinn / Skatteetaten / NAV submission. The response is the structured verdict from `src/lib/actions/dry-run.ts` carrying: the five check slots (`company_exists`, `system_user_authorised`, `scopes_delegated`, `deadline_in_future`, `data_format_valid`) each with pass / fail / skipped status and a human-readable reason; the overall valid boolean; and the DRY_RUN_DISCLAIMER constant — a passing dry-run is NOT a guarantee of upstream success, only a strong-but-not-guaranteed signal that the local prerequisites are satisfied. The dry-run response also echoes `would_be_payload` — the exact upstream-shaped payload a live execute would submit — plus a `preview_notice`, so you can preview precisely what would be filed without submitting anything. Checks short-circuit deterministically: `scopes_delegated` is skipped when `system_user_authorised` fails (no delegation to inspect); each skipped check carries an explanation. Use this tool BEFORE calling the live execute path to catch missing delegations, expired scopes, deadline misses, and payload-shape errors with zero upstream cost. Inputs match the underlying /v1/actions/execute body schema exactly: { org_number, action_type, period, payload }. action_type is the closed enum `mva_melding` (VAT return) | `a_melding` (employer report). period encoding depends on action_type — for mva_melding accept `YYYY-T1..T6` (bimonthly), `YYYY-A` (annual), or `YYYY-MM` (monthly); for a_melding only `YYYY-MM`. payload is the upstream-shaped JSON for the action; the per-action discriminated Zod (in `src/lib/actions/payload-schemas.ts`) owns shape validation — this tool only caps size at 64 KiB UTF-8 bytes (PAYLOAD_TOO_LARGE on exceedance). Failure modes: SCOPE_INSUFFICIENT if the API key is not scoped read:actions; VALIDATION_FAILED on shape / mod-11 / action_type enum / period-regex / payload-size; the dry-run validator itself NEVER throws — every failed check is reported via valid=false plus the breakdown fields. Required scope: `read:actions` (matches the underlying /v1/actions/execute endpoint — dry-run shares the live-execute scope vocabulary). To actually file a (sandbox) VAT return rather than dry-run-validate, use submit_vat_return instead.
Parameters (4)
org_numberstringrequired
9-digit Norwegian organisasjonsnummer (passing MOD-11) the proposed action targets.
action_typestringrequired
The regulatory action to dry-run — `mva_melding` (VAT return) or `a_melding` (employer report).
The upstream-shaped JSON payload for the action; the route's per-action discriminated Zod owns shape validation. Capped at 64 KiB UTF-8 here.
explain_compliance_error
Resolve a structured Apier compliance error code into a Norwegian-bokmål Explanation envelope sourced from the Apier Compliance Explainer (PR-049). The response carries a one-line summary, a 1–3 sentence why, an ordered list of fix_steps, an optional Apier / Altinn / Skatteetaten / Brønnøysund relevant documentation link, an optional Lovdata-style legal_basis citation when the error maps to a concrete regulatory provision, and an optional handover block (who / where / what / why) for errors a human must resolve (e.g. AUTH_INSUFFICIENT_ROLE, AUTH_NO_DELEGATION, SCOPE_MISSING). Errors agents can resolve themselves (VALIDATION_FAILED, RATE_LIMIT_EXCEEDED, NOT_FOUND, IDEMPOTENCY_KEY_MISMATCH, IDEMPOTENCY_IN_PROGRESS, UPSTREAM_UNAVAILABLE) ship `handover: null`. The full catalogue of supported error codes mirrors `EXPLAINER_ERROR_CODES` (33 codes today across auth, validation, scope, upstream, idempotency, action-execute, government, and reliability domains); pass any code an Apier endpoint returned in an error envelope. The optional `context` object carries placeholder values (org_number, role, scope, field, upstream_system) that the explainer interpolates into the bokmål text — missing values fall back to a Norwegian 'ukjent <noun>' rather than leaking placeholder syntax. Required scope: `read:rulebook`. For a company's live obligations rather than an error explanation, use get_company_obligations instead.
Parameters (2)
error_codestringrequired
A structured Apier error code (the closed EXPLAINER_ERROR_CODES catalogue) returned in an Apier error envelope.
contextobject
Optional placeholder values the explainer interpolates into the Norwegian-bokmål text; missing values fall back to a Norwegian 'ukjent <noun>'.
submit_vat_return
Submit a Norwegian VAT return (MVA-melding) in Apier's SANDBOX — a zero-risk, fully simulated environment that NEVER contacts a real government system. No Altinn, Maskinporten, Skatteetaten, or NAV call is ever made; every response is built from in-code synthetic fixtures, so nothing you do here files a binding return. The tool has two modes, chosen by whether you supply an approval_token. Call it WITHOUT an approval_token to PREVIEW: it runs the same precondition checks a live filing would (company exists, system-user authorised, scopes delegated, deadline in the future, payload shape) and returns the dry-run verdict, filing NOTHING. Call it WITH an approval_token — a single-use sandbox approval token a human operator obtains out-of-band from the sandbox approval-token route — to FILE the mock return: the sandbox validates the token and returns a signed sandbox receipt (altinn_receipt_id, audit_log_id, an HMAC-SHA256 signature) carrying an explicit not-a-real-government-response marker. This demonstrates the staged, human-gated, audited execution story end to end with no binding write. The action is permanently fixed to mva_melding (VAT) — this tool cannot submit any other filing type. Use only the reserved synthetic sandbox org numbers. Required scope: read:actions (the same read scope as the dry-run validator — the tool never holds or needs a write or act scope, because the human approval gate, not the agent, authorises the mock filing). Failure modes: VALIDATION_FAILED on a non-9-digit org_number, an oversized payload, or a malformed approval_token; AUTH_EXPIRED_TOKEN from the route when a supplied token does not validate. To dry-run-validate a PRODUCTION action without filing, use validate_action instead.
Parameters (4)
org_numberstringrequired
A reserved synthetic SANDBOX org number (plain 9-digit; the synthetic orgs deliberately fail MOD-11). No real organisation is ever contacted.
actionstringrequired
Permanently fixed to `mva_melding` (VAT). Omit it — the tool cannot submit any other filing type.
payloadobjectrequired
The VAT-return (MVA-melding) payload. Free-shape and fixture-keyed in the sandbox; size-capped to the sandbox route's body limit.
approval_tokenstring
ABSENT → PREVIEW (dry-run, files nothing). PRESENT → FILE the mock return. A single-use sandbox approval token a human operator issues out-of-band; the tool never mints or derives it.
Hardened thin npm proxy that connects local MCP clients (Claude Desktop, Cursor, Zed, Codex) to Apier's hosted Norwegian compliance MCP server at https://www.apier.no/api/mcp.
Published as @apier-no/mcp. The @apier scope was unavailable, so this package ships under the @apier-no scope.