Skip to content
Apier

Can an AI agent query and interact with Altinn APIs?

Querying and validating, yes, against real data, today. Binding submission, no. An agent can read a company's registry facts, obligations, deadlines, signing authority and filing history, and it can dry-run a filing payload against the real rule set and get back a per-check verdict. What it cannot do yet is put a filing into a government system: that path runs against a sandbox and a mock adapter, and the approvals that would make it real are outstanding. This page says so plainly because building on the other assumption is expensive to discover late.

An AI agent connects to three stages in sequence. Read, described as live against real registry data. Validate, described as a dry run with no side effects. Submit, described as sandbox or gated. A dashed vertical line sits before the submit stage, labelled: no live government write past this line.AI agentReadlive, real registry dataValidatedry run, no side effectsSubmitsandbox or gatedno live government write past this line
The first two stages answer against production data. The dashed line is where the honest answer changes, and everything to its right is either synthetic or waiting on an approval.

What can an agent do today versus what is gated?

The read surface is live and answers against real registry data. An agent can resolve a company from a name, pull its context, ask what it must file and when the next deadlines fall, resolve who holds signing authority, and read its filing history. Those are ordinary authenticated calls, they return a normalised schema across upstreams, and each response carries the rule version and data freshness it was produced under.

Validation is live too, with a narrower meaning than it sounds. Calling the execute endpoint with dry_run=true runs a real payload for a real company through the rule engine and reports each check individually. It produces no upstream side effect, which is why it is gated on a read-prefixed scope despite sitting on a write-shaped path. A 200 response carrying all_passed: false is the success case: the dry run ran and the verdicts are in the body.

Binding submission is the gated one. Two external approvals stand in front of it, a production Maskinporten client and an Altinn scope approval, and neither has landed. Until they do, the credential adapters ship in mock mode, so an execute call that is not a dry run resolves through a deterministic mock rather than a government endpoint. One action type is not wired for live submission at all and answers with an explicit refusal rather than a stub success, which is the behaviour you want from something this consequential.

What an AI agent can do against Altinn through Apier right now, by operation, with the current operational state of each.
OperationCurrent stateWhat that means in practice
Read company dataLive, against real registry data.Context, obligations, deadlines, signing authority and filing history all answer normally with an API key.
Validate a filing (dry run)Live, and validation only.A real payload is checked against the real rule set and every check is reported. Nothing is submitted and no upstream is called.
Submit through the sandboxLive, and synthetic.A local state transition against fixtures. Deterministic, testable, and it never reaches Altinn, Maskinporten or Skatteetaten.
Submit for real (binding)Gated.Waiting on a production Maskinporten client and an Altinn scope approval. Until both land, no filing leaves the system.
Approve a binding actionReserved, not assignable.The approval scope cannot be granted to an API key, so an agent cannot release its own binding action even in principle.

How does a dry run differ from a submission?

A dry run answers “would this be accepted”. It takes the same request body a submission would take, for the same company and period, and runs it through the checks: whether the data format is right, whether the obligation applies, whether the delegation covering it is in place, whether the period is one you may still file for. Each check comes back individually, so a failure tells you which condition is unmet rather than that something went wrong.

A submission answers “do it”, and the difference is not a flag on the same operation so much as a different risk profile. Submission is idempotency-keyed, because a retried filing that submits twice is a materially worse outcome than one that fails once. Its contract has it consume a single-use approval token, though the enforcement that stages an unapproved write ships switched off today (see the next section). And it is the only one of the two that could ever produce a consequence outside your own system, which is precisely why it is the one still behind a gate.

For agent design the useful consequence is that the dry run is safe to call speculatively and the submission is not. An agent that validates before it proposes gives a user something concrete to approve. The MVA filing walkthrough in the docs runs the whole sequence end to end, from obligation discovery through validation to the gated submission contract.

How do you keep a human in the loop on a binding filing?

By making approval a credential the agent cannot hold. The scope that releases a binding action sits in a reserved prefix that is not assignable to any API key, and the middleware refuses it regardless of what else the key carries. That is a structural answer rather than a policy one: there is no configuration in which an agent's own key approves its own filing, so the question of whether you trusted it correctly never arises.

On top of that there is a suspension mechanism. When it is enabled, a binding write arriving without an approval token is staged rather than executed, and the caller gets back a pending action with an approval link built from server configuration rather than from the inbound request. That last detail matters more than it looks: building the link from a request header would let an attacker point the approval screen wherever they liked.

The mechanism ships switched off, and given that binding submission itself is gated, that is the coherent default rather than an oversight. What it means for you is that the human-in-the-loop shape is already decided and you can build your product flow around it now: the agent prepares and validates, a person approves, the approval is consumed exactly once. Only the last step is waiting on somebody else's approval process.

Make the first call

The first request needs no key and submits nothing: it plans a VAT return against the sandbox. The second is the dry run against real rules, and the field to read first is outcome.all_passed.

# Zero-auth sandbox: plan a VAT return without submitting anything.
curl -s https://www.apier.no/api/v1/sandbox/public/actions/plan \
  -H "content-type: application/json" \
  -d '{"org_number":"999999999","action":"mva_melding"}'
// Dry run against the real rule set. No upstream side effects.
const res = await fetch(
  "https://www.apier.no/api/v1/actions/execute?dry_run=true",
  {
    method: "POST",
    headers: {
      "content-type": "application/json",
      Authorization: `Bearer ${process.env.APIER_API_KEY}`,
    },
    body: JSON.stringify({
      org_number: "999999999",
      action_type: "mva_melding",
      period: "2026-T1",
      payload: {},
    }),
  },
);

// 200 with all_passed: false is the SUCCESS path. Failed checks are
// content, not transport: the dry run ran and reported verdicts.
const { data } = await res.json();
console.log(data.outcome.all_passed, data.outcome.checks);

Frequently asked questions

Can an AI agent submit a form to Altinn today?
Not as a binding government submission. The call shape exists and the sandbox will accept it, but live filing submission is gated behind a production Maskinporten client and an Altinn scope approval that are not in place yet. Reading and validating are live against real data. Treat submission as a contract you can build against rather than a capability you can ship on.
What does an agent get from a sandbox submission then?
Proof that your code path is correct. The sandbox answers the production response shape from synthetic fixtures, deterministically, so you can assert on it in a test suite, and it injects failure cases on request so your error handling is exercised. What it cannot give you is any evidence about a real filing, because the sandbox never calls a government system on any verb.
How is a dry run different from a sandbox call?
A dry run evaluates a real payload for a real company against the real rule set and reports which checks passed. A sandbox call runs against synthetic fixtures for a reserved test organisation number. The dry run tells you whether this filing would be accepted; the sandbox tells you whether your client is wired correctly. Both stop short of submitting.
Can an agent approve its own filing?
No, and that is enforced rather than merely recommended. The approval scope sits in a reserved prefix that is not assignable to any API key, so a key presenting it is refused regardless of what else it holds. An agent can prepare and validate a binding action; a separate human decision is required to release it.
How do I know which capability is live right now?
Two sources, and they agree by construction. GET /api/v1/capabilities returns a machine-readable status field of live, gated or dry-run on every capability, which is the one to read if you are a machine. The capability status page in the docs is the human-readable equivalent and is explicit that it may lag the API.