---
title: "Operator telemetry analysis (data-moat v1)"
method: GET
path: "/api/v1/admin/telemetry"
tags: ["Admin"]
---

# Operator telemetry analysis (data-moat v1)

`GET /api/v1/admin/telemetry`

## Request

- Base URL: `https://www.apier.no`
- URL: `https://www.apier.no/api/v1/admin/telemetry`
- Auth: HTTP bearer

Operator-only, READ-ONLY analysis over telemetry that already exists — it introduces no new capture path. Over an Europe/Oslo-aligned trailing window it aggregates the existing operational tables (task_success_log, audit_log, api_usage, mcp_query_log) into four signals that show what is failing and where the contract is incomplete: recurring error codes, government-rejection shapes, latency outliers, and error shapes the Compliance Explainer does not yet document. WHY this exists: surfacing these patterns is the feedback signal that tells the team which rules, explanations, and upstream handlers to harden next — the analytical core of the product's data advantage. Auth is ADMIN_API_KEY (the same guard as the key-management endpoints); there is deliberately no zero-auth variant because this reads cross-consumer operational data. Each underlying read fails soft and is reported in source_reads, so a single table being unavailable degrades that one section rather than the whole response.

## Query parameters

- `window_days` integer

## Response `200`

The telemetry analysis report. Always a 200 envelope when authenticated — a fully-empty report (no rows, or every read failed soft) is empty arrays, never an error, so an operator dashboard can render unconditionally.

- object
  - `success` true: Always true on success.
  - `data` object: The aggregated analysis over the requested window.
    - `window` object: The resolved analysis window. WHY echoed back: the caller passes window_days, but the concrete from/to instants are computed server-side with Oslo-midnight alignment, so returning them removes any ambiguity about exactly which slice the numbers cover.
      - `from` string, date-time: UTC instant of Oslo-local midnight window_days ago — the inclusive start of the scan.
      - `to` string, date-time: UTC instant the report was generated — the end of the scan.
      - `window_days` integer: The window length actually used (echoes the validated query param).
      - `timezone` 'Europe/Oslo': The zone the window boundary is aligned to — Norwegian deadlines and operations are defined in Oslo local time.
    - `generated_at` string, date-time: When this report was produced; equal to window.to.
    - `top_error_codes` object[]: Most frequent structured error codes from task_success_log over the window, descending by count. WHY: the leading recurring failures are the highest-leverage candidates for a rule or handler fix.
      - `error_code` string: The recorded error_code identifier.
      - `count` integer: Occurrences of this code in the window.
    - `government_rejections` object[]: Government API rejections from audit_log (gov_api_response_status >= 400), grouped by (action, status), descending by count. WHY: clusters of a given upstream status against a given action reveal where Apier's pre-submission validation is letting bad payloads through to Altinn/Skatteetaten.
      - `action` string: The audited action that drew the upstream rejection.
      - `gov_status` integer: The HTTP status the government API returned (>= 400).
      - `count` integer: Occurrences of this (action, status) pair in the window.
    - `latency_by_endpoint` object[]: Response-time distribution per endpoint from api_usage, descending by p95. WHY p95 ordering: the tail, not the median, is what agents experience as 'slow' — surfacing the worst tails first points at the endpoints to profile.
      - `endpoint` string: The endpoint path recorded in api_usage.
      - `sample_size` integer: Number of timed requests in the window for this endpoint.
      - `p50_ms` integer: Median response time in milliseconds (PERCENTILE_CONT, matching the existing success-rate view).
      - `p95_ms` integer: 95th-percentile response time in milliseconds — the tail-latency signal.
      - `max_ms` integer: Slowest observed response time in milliseconds.
    - `candidate_undocumented_edge_cases` object[]: Error shapes observed in telemetry (task_success_log error codes + scrubbed mcp_query_log failure reasons) that are NOT in the Compliance Explainer catalogue, descending by occurrences. WHY: each entry is a real failure an agent hit that Apier cannot yet explain in plain Norwegian — the direct work-list for growing the Explainer and rulebook.
      - `shape` string: The observed error code or scrubbed+truncated failure reason. Secrets are redacted and the string is bounded before it appears here.
      - `occurrences` integer: How many times this shape was seen in the window.
      - `source` 'task_success_log' | 'mcp_query_log' | 'both': Which telemetry table(s) surfaced this shape.
      - `in_explainer` false: Always false — by construction this list is the shapes the Explainer does not document.
    - `source_reads` object: Per-source read outcome. WHY surfaced: the report never throws on a partial read, so this block is how the operator distinguishes 'genuinely no rows' from 'this source failed or was capped'. ok=false means that section is empty because the read errored (detail is in Sentry); capped=true means the window held more rows than were scanned and the aggregate is over the most-recent scanned rows.
      - `task_success_log` TelemetryReadStatus: Outcome of one underlying telemetry-table read in the operator analysis report. Surfaced per source so a partial read is visible rather than silently mistaken for 'no data'.
        - `ok` boolean, required: False when this source's read errored and its section was emitted empty (the cause is captured to Sentry, never returned to the caller).
        - `rows_scanned` integer, required: How many rows from this source fed the aggregate. Zero when the read failed or the window was empty.
        - `capped` boolean, required: True when the window held more rows than the per-source scan cap (READ_CAP or PostgREST's server-side max-rows cap), so the aggregate is over the most-recent scanned rows only — flagged rather than silently truncated. When count_exact is false the read's completeness could not be verified, so capped is reported true (possibly-truncated) rather than a falsely-complete false.
        - `count_exact` boolean, required: True when PostgREST returned an exact row count for this read, so capped reflects a verified comparison of the true total against the rows scanned. False when no exact count was returned (completeness unverifiable): a null count is never coerced to the rows-returned value, which would mask a truncated read as a full window.
      - `audit_log` TelemetryReadStatus: Outcome of one underlying telemetry-table read in the operator analysis report. Surfaced per source so a partial read is visible rather than silently mistaken for 'no data'.
        - `ok` boolean, required: False when this source's read errored and its section was emitted empty (the cause is captured to Sentry, never returned to the caller).
        - `rows_scanned` integer, required: How many rows from this source fed the aggregate. Zero when the read failed or the window was empty.
        - `capped` boolean, required: True when the window held more rows than the per-source scan cap (READ_CAP or PostgREST's server-side max-rows cap), so the aggregate is over the most-recent scanned rows only — flagged rather than silently truncated. When count_exact is false the read's completeness could not be verified, so capped is reported true (possibly-truncated) rather than a falsely-complete false.
        - `count_exact` boolean, required: True when PostgREST returned an exact row count for this read, so capped reflects a verified comparison of the true total against the rows scanned. False when no exact count was returned (completeness unverifiable): a null count is never coerced to the rows-returned value, which would mask a truncated read as a full window.
      - `api_usage` TelemetryReadStatus: Outcome of one underlying telemetry-table read in the operator analysis report. Surfaced per source so a partial read is visible rather than silently mistaken for 'no data'.
        - `ok` boolean, required: False when this source's read errored and its section was emitted empty (the cause is captured to Sentry, never returned to the caller).
        - `rows_scanned` integer, required: How many rows from this source fed the aggregate. Zero when the read failed or the window was empty.
        - `capped` boolean, required: True when the window held more rows than the per-source scan cap (READ_CAP or PostgREST's server-side max-rows cap), so the aggregate is over the most-recent scanned rows only — flagged rather than silently truncated. When count_exact is false the read's completeness could not be verified, so capped is reported true (possibly-truncated) rather than a falsely-complete false.
        - `count_exact` boolean, required: True when PostgREST returned an exact row count for this read, so capped reflects a verified comparison of the true total against the rows scanned. False when no exact count was returned (completeness unverifiable): a null count is never coerced to the rows-returned value, which would mask a truncated read as a full window.
      - `mcp_query_log` TelemetryReadStatus: Outcome of one underlying telemetry-table read in the operator analysis report. Surfaced per source so a partial read is visible rather than silently mistaken for 'no data'.
        - `ok` boolean, required: False when this source's read errored and its section was emitted empty (the cause is captured to Sentry, never returned to the caller).
        - `rows_scanned` integer, required: How many rows from this source fed the aggregate. Zero when the read failed or the window was empty.
        - `capped` boolean, required: True when the window held more rows than the per-source scan cap (READ_CAP or PostgREST's server-side max-rows cap), so the aggregate is over the most-recent scanned rows only — flagged rather than silently truncated. When count_exact is false the read's completeness could not be verified, so capped is reported true (possibly-truncated) rather than a falsely-complete false.
        - `count_exact` boolean, required: True when PostgREST returned an exact row count for this read, so capped reflects a verified comparison of the true total against the rows scanned. False when no exact count was returned (completeness unverifiable): a null count is never coerced to the rows-returned value, which would mask a truncated read as a full window.
    - `deployment_modes` object: The resolved deployment-mode table, read from server env at request time (NOT the telemetry tables), so an operator sees on this same admin surface whether any government adapter is still serving fixtures in production and whether the Stripe keys are a consistent test/live pair. Modes only — never any key bytes.
      - `vercel_env` string: The raw VERCEL_ENV value ('production' | 'preview' | 'development' | ...), or 'unset' when absent. 'production' is the only value that arms the mock-in-production warnings and the Stripe hard-fail.
      - `is_production` boolean: True iff vercel_env === 'production' — the gate for the boot-time mock-in-production warnings and the Stripe consistency fatal.
      - `government_adapters` object: Effective mode of each government-API adapter (mock | live, plus 'sandbox' for Altinn). A 'mock' value while is_production=true means that adapter is answering with fixtures, not real upstream data.
        - `maskinporten` 'mock' | 'live': MASKINPORTEN_MODE effective value (mock | live).
        - `altinn` 'mock' | 'live' | 'sandbox': ALTINN_MODE effective value (mock | live | sandbox).
        - `altinn_ingestion` 'mock' | 'live': ALTINN_INGESTION_MODE effective value (mock | live).
        - `skatteetaten` 'mock' | 'live': SKATTEETATEN_MODE effective value (mock | live).
        - `nav` 'mock' | 'live': NAV_MODE effective value (mock | live).
        - `brreg` 'mock' | 'live': BRREG_MODE effective value (mock | live).
      - `stripe` object: Stripe key-mode consistency — modes only, never key bytes.
        - `secret_key_mode` 'test' | 'live' | 'unknown' | 'unset': Mode inferred from the STRIPE_SECRET_KEY prefix (sk_/rk_). 'unknown' = configured but no test/live prefix; 'unset' = not configured.
        - `publishable_key_mode` 'test' | 'live' | 'unknown' | 'unset': Mode inferred from the NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY prefix (pk_).
        - `configured_price_ids` integer: How many of the six STRIPE_PRICE_* vars are set. Price ids carry no test/live marker, so only the count is surfaced.
        - `consistent` boolean: True unless the known key modes (secret + publishable) disagree — a sk_test_ paired with pk_live_ (or vice-versa). A mismatch fails the boot in production and is a warning outside it.
      - `billing_live` boolean: Resolved BILLING_LIVE state. False while the beta gate is active — POST /api/billing/checkout returns 503 BILLING_NOT_LIVE and the pricing page suppresses the checkout CTA; true once payments are accepted. Reported for operator visibility, never warned on: beta-off in production is the expected launch state, not a misconfiguration.
      - `credits_live` boolean: Resolved CREDITS_LIVE state. False while the prepaid-credit gate on the metered Rulebook read endpoints runs in shadow mode — would-be debits are logged, responses carry X-Credit-Check: shadow, and a 402 is impossible; true once enforcement is live. Reported for operator visibility, never warned on: shadow-in-production is the deliberate dark-launch state, not a misconfiguration.
      - `mock_in_production` string[]: Env-var names of adapters resolving to 'mock' while is_production=true — the same set the boot guard emits Sentry warnings for. Empty outside production.
  - `_meta` TrustMetadata: Metadata included in every response for trust and verifiability.
    - `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

- `400`: Validation failed — window_days is not an integer in 1..30.
- `401`: Authentication failed — missing, malformed, invalid, or revoked API key.
- `500`: Unexpected failure building the report (no internal detail is leaked; the cause is captured to Sentry).
- `503`: Admin authentication is not configured on this deployment (ADMIN_API_KEY unset).

---

[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)
