Skip to content
Apier
Apier.no
Guides

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_id is the upstream submission id. On the sandbox the receipt also carries _sandbox_marker: "SANDBOX_NOT_REAL_GOV_RESPONSE" (top-level and nested inside government_response_raw) so a parser can never mistake a rehearsal for a real government response.
  • audit_log_id ties the receipt to its audit row.
  • signature lets 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:

  1. Keep the receipt (data.receipt) as the durable proof.
  2. Log the X-Correlation-ID from the response header.
  3. Read GET …/audit to confirm the action landed and see its initiated_by.
  4. On production, pivot on the correlation_id to pull the matching rule-evaluation snapshot when you need the why.

Read next: Quick start · Going live · Idempotency and safe retries · Fixtures reference.