SignedReceipt
HMAC-signed government submission receipt. Returned by `/api/v1/actions/execute` when an action submitted to Altinn / Skatteetaten / NAV produces a receipt. Persisted to the append-only `receipts` table so a future re-verify can confirm Apier issued exactly these bytes at exactly this signing time. Frame this as an integrity receipt, not a proof of legal correctness — Apier signs the wrapper, not the upstream's truth claim. The `government_response_raw` field carries the upstream's response VERBATIM (minimally normalised: timestamps converted from Oslo-local to ISO 8601 with explicit Europe/Oslo offset, keys case-preserved, byte-level content otherwise preserved). Apier does not interpret this payload — it is preserved for defensibility. When the canonicalised form exceeds 256KB the field carries a `LargeGovernmentResponse` pointer instead, with the full bytes on `large_government_responses` joinable via the persisted `large_response_id` column (the join is server-side; the wire form is the same union shape). The `signature` is HMAC-SHA256 over `canonicalJSON(receipt-without-signature)` using the operator-side `RECEIPT_HMAC_SECRET`. The hashed domain INCLUDES `signature_algorithm` — flipping the algorithm tag without recomputing the signature is a downgrade attack and fails verification.
Properties
| Name | Type | Description |
|---|---|---|
| altinn_receipt_id | string | Upstream-issued receipt id (Altinn / Skatteetaten / NAV). Forwarded verbatim from the gov API response. |
| audit_log_id | string | UUID of the `audit_log` row for the action that produced this receipt. Hard FK in the database; the receipt is always preceded by its audit row. |
| org_number | string | 9-digit Norwegian organisation number the receipt belongs to. |
| filing_type | string | Stable machine-readable filing-type identifier (e.g. `mva-melding`, `a-melding`, `skattemelding`). Free TEXT in v1; a future closed enum will be additive. |
| rule_version | string | Rulebook version active at signing time. Frozen on the receipt so a re-verify always reasons against the original rules — not whatever Rulebook version is current at re-verification. |
| correlation_id | string | Request-scope UUID v4. Joins `audit_log`, `provenance_log`, `evaluation_snapshots`, and `compliance_state_events` on the same forensic axis. |
| government_response_raw | object | The exact JSON received from Altinn / Skatteetaten / NAV on submission. Minimally normalised: timestamps in Norwegian local-time form (`YYYY-MM-DD[ T]HH:mm:ss`) are converted to ISO 8601 with explicit |
| government_response_hash | string | SHA-256 of `canonicalJSON(normalised payload)`, prefixed `sha256:`. Computed against the FULL normalised payload (not the truncated projection) so re-verification can rehash from `large_government_res |
| signed_at | string | RFC 3339 / ISO 8601 timestamp of when the receipt was signed. Caller-supplied (will pass the route's frozen time-source) so the signature is deterministic across retries. |
| signature_algorithm | object | |
| signature | string | HMAC-SHA256 hex (64 chars). Computed over `canonicalJSON(receipt-without-signature)` using the operator-side `RECEIPT_HMAC_SECRET`. INCLUDES `signature_algorithm` in the hashed domain — downgrade-atta |
| normalization_rules_applied | array | Diagnostic record of which `normalizeGovernmentResponse` rules fired during signing. Included in the HMAC domain (part of `canonicalJSON(receipt-without-signature)`) so an intermediary cannot rewrite |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/apier-no/json-schema/apier-no-signed-receipt-schema.json",
"title": "SignedReceipt",
"description": "HMAC-signed government submission receipt. Returned by `/api/v1/actions/execute` when an action submitted to Altinn / Skatteetaten / NAV produces a receipt. Persisted to the append-only `receipts` table so a future re-verify can confirm Apier issued exactly these bytes at exactly this signing time. Frame this as an integrity receipt, not a proof of legal correctness — Apier signs the wrapper, not the upstream's truth claim.\n\nThe `government_response_raw` field carries the upstream's response VERBATIM (minimally normalised: timestamps converted from Oslo-local to ISO 8601 with explicit Europe/Oslo offset, keys case-preserved, byte-level content otherwise preserved). Apier does not interpret this payload — it is preserved for defensibility. When the canonicalised form exceeds 256KB the field carries a `LargeGovernmentResponse` pointer instead, with the full bytes on `large_government_responses` joinable via the persisted `large_response_id` column (the join is server-side; the wire form is the same union shape).\n\nThe `signature` is HMAC-SHA256 over `canonicalJSON(receipt-without-signature)` using the operator-side `RECEIPT_HMAC_SECRET`. The hashed domain INCLUDES `signature_algorithm` — flipping the algorithm tag without recomputing the signature is a downgrade attack and fails verification.",
"x-generated": "2026-11-01",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/apier-no-openapi.json#/components/schemas/SignedReceipt",
"type": "object",
"required": [
"altinn_receipt_id",
"audit_log_id",
"org_number",
"filing_type",
"rule_version",
"correlation_id",
"government_response_raw",
"government_response_hash",
"signed_at",
"signature_algorithm",
"signature",
"normalization_rules_applied"
],
"additionalProperties": false,
"properties": {
"altinn_receipt_id": {
"type": "string",
"minLength": 1,
"maxLength": 256,
"description": "Upstream-issued receipt id (Altinn / Skatteetaten / NAV). Forwarded verbatim from the gov API response."
},
"audit_log_id": {
"type": "string",
"format": "uuid",
"description": "UUID of the `audit_log` row for the action that produced this receipt. Hard FK in the database; the receipt is always preceded by its audit row."
},
"org_number": {
"type": "string",
"pattern": "^[0-9]{9}$",
"description": "9-digit Norwegian organisation number the receipt belongs to."
},
"filing_type": {
"type": "string",
"minLength": 1,
"maxLength": 128,
"description": "Stable machine-readable filing-type identifier (e.g. `mva-melding`, `a-melding`, `skattemelding`). Free TEXT in v1; a future closed enum will be additive."
},
"rule_version": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"description": "Rulebook version active at signing time. Frozen on the receipt so a re-verify always reasons against the original rules — not whatever Rulebook version is current at re-verification."
},
"correlation_id": {
"type": "string",
"format": "uuid",
"description": "Request-scope UUID v4. Joins `audit_log`, `provenance_log`, `evaluation_snapshots`, and `compliance_state_events` on the same forensic axis."
},
"government_response_raw": {
"description": "The exact JSON received from Altinn / Skatteetaten / NAV on submission. Minimally normalised: timestamps in Norwegian local-time form (`YYYY-MM-DD[ T]HH:mm:ss`) are converted to ISO 8601 with explicit Europe/Oslo offset (`+02:00` CEST / `+01:00` CET, DST-aware via date-fns-tz, never hardcoded). Keys are case-preserved (`MvaPeriode` stays `MvaPeriode`). All other byte-level value content is preserved. Apier does not interpret this payload — it is preserved verbatim for defensibility. When the canonicalised form is >256KB the receipt carries the spill-bucket `LargeGovernmentResponse` pointer here instead; consumers must inspect the shape via the `truncated` discriminator.\n\nThe inline branch accepts any JSON root (object, array, string, number, boolean, null) — Skatteetaten and Altinn endpoints occasionally return top-level arrays or primitives, and the lib treats `government_response_raw` as `unknown` (preserves verbatim). The branches use `anyOf` (not `oneOf`) because a `LargeGovernmentResponse` instance is also a generic object and would match BOTH branches, failing `oneOf`'s exactly-one constraint — the discriminator the consumer parses is `truncated`, not the JSON-Schema branch. When this receipt was produced by a mock submission (Apier's `ALTINN_MODE=mock` default — see the `/api/v1/actions/execute` operation description), the object carries a nested `_mock: true` boolean as the discoverable signal that no real government system was contacted.",
"anyOf": [
{
"type": "object",
"additionalProperties": true
},
{
"type": "array",
"items": {}
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
},
{
"$ref": "#/$defs/LargeGovernmentResponse"
}
]
},
"government_response_hash": {
"type": "string",
"pattern": "^sha256:[0-9a-f]{64}$",
"description": "SHA-256 of `canonicalJSON(normalised payload)`, prefixed `sha256:`. Computed against the FULL normalised payload (not the truncated projection) so re-verification can rehash from `large_government_responses.full_payload`."
},
"signed_at": {
"type": "string",
"format": "date-time",
"description": "RFC 3339 / ISO 8601 timestamp of when the receipt was signed. Caller-supplied (will pass the route's frozen time-source) so the signature is deterministic across retries."
},
"signature_algorithm": {
"$ref": "#/$defs/ReceiptSignatureAlgorithm"
},
"signature": {
"type": "string",
"pattern": "^[0-9a-f]{64}$",
"description": "HMAC-SHA256 hex (64 chars). Computed over `canonicalJSON(receipt-without-signature)` using the operator-side `RECEIPT_HMAC_SECRET`. INCLUDES `signature_algorithm` in the hashed domain — downgrade-attack defence."
},
"normalization_rules_applied": {
"type": "array",
"description": "Diagnostic record of which `normalizeGovernmentResponse` rules fired during signing. Included in the HMAC domain (part of `canonicalJSON(receipt-without-signature)`) so an intermediary cannot rewrite normalization metadata silently — tampering with this list breaks signature verification (Major). Echoed verbatim on the wire for forensic transparency.",
"items": {
"type": "string",
"enum": [
"oslo_timestamp_normalised"
]
}
}
},
"$defs": {
"LargeGovernmentResponse": {
"type": "object",
"description": "Compact pointer the receipt row carries on `government_response_raw` when the canonicalised normalised payload exceeded 256KB and was spilled into the `large_government_responses` table. The full bytes live one JOIN away on `large_government_responses.full_payload`; this sentinel is what a forensic peek at the receipt itself sees without joining. Stable shape regardless of upstream payload structure.",
"required": [
"truncated",
"byte_length",
"inline_projection_byte_budget",
"hash",
"note"
],
"additionalProperties": false,
"properties": {
"truncated": {
"type": "boolean",
"enum": [
true
],
"description": "Discriminator: always true. A non-truncated receipt carries the verbatim payload on `government_response_raw` instead of this sentinel."
},
"byte_length": {
"type": "integer",
"minimum": 262145,
"description": "Byte length of the canonicalised normalised payload at signing time. Spill happens only when the canonical form is STRICTLY >256KB; exactly 256KB stays inline. Minimum 262145 (256KB + 1 byte) reflects this invariant — under-threshold payloads cannot legitimately appear in a `LargeGovernmentResponse`."
},
"inline_projection_byte_budget": {
"type": "integer",
"minimum": 1,
"description": "Soft cap on the inline projection size (echoed for transparency). Today: 65536 (64 KB)."
},
"hash": {
"type": "string",
"pattern": "^sha256:[0-9a-f]{64}$",
"description": "SHA-256 of canonicalJSON(normalised payload), prefixed `sha256:`. Joins to `large_government_responses.response_hash` and matches `receipts.government_response_hash`."
},
"note": {
"type": "string",
"description": "Static guidance pointing at the spill-bucket join — instructive for a human reading the row in isolation."
}
}
},
"ReceiptSignatureAlgorithm": {
"type": "string",
"enum": [
"HMAC-SHA256-v1"
],
"description": "Versioned algorithm tag for signed submission receipts. v1 today: HMAC-SHA256 over the canonical-JSON form of the receipt body (with the `signature` field excluded; `signature_algorithm` itself IS in the hashed domain — downgrade-attack defence). A future rotation introduces a new value (`HMAC-SHA256-v2` on secret rotation, `Ed25519-v1` on asymmetric migration); historical receipts continue to verify under the algorithm they were signed with because the verifier branches on this column at read time."
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
curl "https://apis.io/api/v1/json-schemas/apier-no-signed-receipt"
curl "https://apis.io/api/v1/json-schemas?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.