{
 "key_id": "appealsdesk-answer-2026-08-31",
 "alg": "Ed25519",
 "public_key_spki_b64": "MCowBQYDK2VwAyEAvV+dYf+fRT/4BVhTJc5xA/EgFF84FJ9dI/NOqykNI4k=",
 "public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAvV+dYf+fRT/4BVhTJc5xA/EgFF84FJ9dI/NOqykNI4k=\n-----END PUBLIC KEY-----",
 "created": "2026-08-31",
 "policy": "axion-receipt/v1: sha256 over the body minus this receipt, dataset <stamp>, fields as served",
 "policy_note": "Every receipt carries this line as `policy` with its own dataset stamp filled in — what the signature covers, stated on the receipt. Descriptive only: the signed message below is unchanged and does not include it.",
 "signs": "Answer API responses on https://appealsdesk.co.uk — each carries a receipt field with a detached signature",
 "signed_message_format": "answer-receipt/v0|<key_id>|<payload_sha256>|<signed_at>|<dataset_version>",
 "verify_endpoint": "https://appealsdesk.co.uk/api/verify-receipt",
 "offline_recipe": [
  "1. Take the raw response text. Parse it. Remove the `receipt` field.",
  "2. Re-serialize with JSON.stringify(obj, null, 1) — JSON.parse preserves key order, so this reproduces the signed bytes exactly.",
  "3. SHA-256 the result; the hex digest must equal receipt.payload_sha256.",
  "4. Rebuild `answer-receipt/v0|key_id|payload_sha256|signed_at|dataset_version` from the receipt fields; it must equal receipt.signed_message.",
  "5. Verify receipt.sig (base64) over that message with this Ed25519 public key."
 ],
 "rotation": "If this key is ever rotated, the old key stays listed here under previous_keys with its retirement date so old receipts remain verifiable.",
 "contact": "hello@getaxionlabs.com"
}