Inspecting actions with the audit trail
Agents have no dashboard. Use the signed receipt, the audit endpoint, correlation_id, and initiated_by to reconstruct exactly what an action did — on the sandbox today, on production later.
[Cite this as: Apier.no Docs v0.1.0 — last updated 2026-06-04]
A human operator opens a dashboard to see what happened. An autonomous
agent has no dashboard — so Apier gives it the same answer as data: a
signed receipt on every write, an audit trail it can read back,
and two fields — correlation_id and initiated_by — that let it
reconstruct a single action end to end. This guide is the agent-side
substitute for clicking around a UI.
Everything here works identically on the sandbox (where the data is synthetic and deterministic) and on production (where it is real). Build the inspection habit against the sandbox; it carries over unchanged.
The receipt — proof an action ran
A successful execute returns a receipt under data.receipt:
{
"altinn_receipt_id": "…",
"audit_log_id": "…",
"timestamp": "2026-05-04T12:00:00.000+02:00",
"org_number": "999999999",
"filing_type": "mva_melding",
"rule_version": "…",
"signature": "…",
"signature_algorithm": "HMAC-SHA256-v1"
}altinn_receipt_idis the upstream submission id. On the sandbox the receipt also carries_sandbox_marker: "SANDBOX_NOT_REAL_GOV_RESPONSE"(top-level and nested insidegovernment_response_raw) so a parser can never mistake a rehearsal for a real government response.audit_log_idties the receipt to its audit row.signaturelets you verify the receipt was minted by Apier and not altered in transit.
Persist the receipt. It is the durable record that the side effect happened; the audit endpoint below is how you query for it later.
The audit endpoint — read back what happened
GET /api/v1/company/{org}/audit returns the action history for an org,
newest first. On the sandbox you can hit the zero-auth public mirror for
the discovery org 999999999:
curl "https://apier.no/api/v1/sandbox/public/company/999999999/audit"…or read the richer fixture set with the synthetic bearer:
curl -H "Authorization: Bearer apier_sandbox_test_<uuid>" \
"https://apier.no/api/v1/sandbox/company/{org}/audit"On production the same shape comes from GET /api/v1/company/{org}/audit
with a real key. Each entry carries:
{
"action": "delegation.create",
"initiated_by": "agent",
"correlation_id": "…",
"schema_version": "…",
"timestamp": "…"
}You can narrow the history with query parameters — action,
initiated_by, since, until, and limit (with before / before_id
for keyset pagination). On the sandbox the deterministic fixture is
returned in full regardless of the filters; on production they bound the
result set.
correlation_id — one id, the whole slice
Every /api/v1/* request carries an X-Correlation-ID. Send your own
(a UUID v4) and Apier reuses it; omit it and Apier mints one. Either way
the canonical id is echoed back on the response header — log it.
On production that single id threads the entire slice of history one HTTP call produced:
- the audit_log row for the action,
- the rule-evaluation snapshot that produced the verdict, and
- the receipt the filing returned.
So when you need to answer "what exactly did that filing do, and why?",
you query each surface by the one correlation_id and reassemble the
full story — request → rule evaluation → receipt → audit — without a
dashboard. Thread it into your own trace system and a support
conversation collapses to a single id.
On the sandbox the entries are synthetic fixtures and write no real
database rows, so the forensic joins above are a production capability —
but the X-Correlation-ID response header behaves identically, so you
can wire and test the plumbing against the sandbox first.
initiated_by — who triggered it
Every audit row is classified so you (or an operator reviewing your agent) can answer "which rows came from a human, an agent, a scheduled job, or an internal service":
human— a write that carried an approval token, i.e. a person confirmed it at the approval step.agent— a recognised agent/SDK client, or any unattended write without an approval token. This is the conservative default for autonomous calls.cron— a scheduled job authenticated with the cron secret.system— reserved for internal service-to-service calls.unknown— the fallback when no signal identifies the caller (for example a plain read).
For an agent the practical rule is: your unattended writes show up as
agent; the moment a write goes through the human-in-the-loop approval
gate, it is recorded as human. That distinction is what makes the
audit trail a usable record of who — not just what.
Putting it together
After a dry-run or execute:
- Keep the receipt (
data.receipt) as the durable proof. - Log the
X-Correlation-IDfrom the response header. - Read
GET …/auditto confirm the action landed and see itsinitiated_by. - On production, pivot on the
correlation_idto pull the matching rule-evaluation snapshot when you need the why.
Read next: Quick start · Going live · Idempotency and safe retries · Fixtures reference.
Idempotency and safe retries
Make write requests retry-safe with the Idempotency-Key header — at-most-once execution, a 24-hour replay window, and the four reservation outcomes an agent must handle.
Webhook subscriptions
Subscribe to change-archive deltas via signed HTTPS webhooks. SSRF-resistant, exponential-backoff retries, HMAC-SHA256 verification.