{
  "info": {
    "name": "RiskRouter API",
    "description": "RiskRouter is infrastructure for insurance distributors: it prices a configuration server-side and, when a distributor key is presented, records the quote in an append-only, SHA-256 hash-chained ledger whose head is signed (ECDSA P-256) so anyone can verify it offline.\n\nStatus, stated plainly: this is a validation build. Prices come from a published mock rating matrix, no carrier, bank or payment rail is contacted, and no insurance cover is in force. RiskRouter does not sell insurance and never contacts the policyholder.\n\nPricing needs no authentication. Recording needs a key; a sandbox key can be taken on the spot from POST /api/v1/sandbox/keys. Keys are sent as `Authorization: Bearer <key>` or `X-RiskRouter-Key: <key>`. Only the SHA-256 of a key is ever stored.\n\nHuman-readable reference: https://riskrouter.eu/docs. Offline verifier: https://github.com/aniljangrabe-dev/riskrouter-verify.\n\nGenerated from https://riskrouter.eu/openapi.json.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.riskrouter.eu"
    },
    {
      "key": "apiKey",
      "value": "",
      "description": "Filled in by request 1. Only its SHA-256 is ever stored by RiskRouter."
    }
  ],
  "item": [
    {
      "name": "1. Take a sandbox key (stored in {{apiKey}} for the rest)",
      "request": {
        "method": "POST",
        "auth": {
          "type": "noauth"
        },
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"acknowledge_permanent\": true\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{baseUrl}}/api/v1/sandbox/keys",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "sandbox",
            "keys"
          ]
        },
        "description": "Shown once. Entries you record with it can never be deleted, which is why acknowledge_permanent is required. The test script saves the key into this collection's apiKey variable."
      },
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const body = pm.response.json();",
              "if (body.ok && body.key) {",
              "  pm.collectionVariables.set(\"apiKey\", body.key);",
              "  console.log(\"Sandbox key saved to {{apiKey}}. It is shown once; keep it if you need it elsewhere.\");",
              "}"
            ]
          }
        }
      ]
    },
    {
      "name": "2. Price a configuration (no key: priced, not recorded)",
      "request": {
        "method": "POST",
        "auth": {
          "type": "noauth"
        },
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"active_vertical\": \"mobility\",\n  \"selected_components\": {\n    \"commuter_roadside\": true\n  }\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{baseUrl}}/api/v1/quote",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "quote"
          ]
        },
        "description": "Pricing needs no key. Nothing is written."
      }
    },
    {
      "name": "3. Price and record it (your key, idempotent)",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{$guid}}",
            "description": "Fresh on every send. Resend with the same value and you get the first entry back, never a second one."
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"active_vertical\": \"mobility\",\n  \"selected_components\": {\n    \"commuter_roadside\": true\n  }\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{baseUrl}}/api/v1/quote",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "quote"
          ]
        },
        "description": "Recorded against your key. Check persistence.persisted: a 200 prices the quote even when the ledger refused the write."
      }
    },
    {
      "name": "The published rating matrix",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/verticals",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "verticals"
          ]
        },
        "description": "Every vertical, its mandatory base layer and optional add-ons, with monthly premiums in EUR as two-decimal strings. The single source of truth a UI should render from."
      }
    },
    {
      "name": "Your entries, the chain skeleton, and the signed head",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/ledger/export",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "ledger",
            "export"
          ]
        },
        "description": "Everything needed to verify offline, forever: your own entries in full, (chain_index, row_hash, prev_hash) for every entry in the ledger, and the signed attestation. Check it at https://riskrouter.eu/verify#check or with the offline verifier."
      }
    },
    {
      "name": "Signed entry count and head hash",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/ledger/attestation",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "ledger",
            "attestation"
          ]
        },
        "description": "Save the whole response. The signature covers `riskrouter-ledger-attestation|v1|as_of|entries|head_hash`, so none of the three can be changed afterwards without it failing."
      }
    },
    {
      "name": "The public half of the attestation key",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/ledger/pubkey",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "ledger",
            "pubkey"
          ]
        },
        "description": "Convenience only. Verify against the copy in the public repository (anchors/signing-key.json) or one you saved earlier, not a key handed to you at the moment you check."
      }
    },
    {
      "name": "Liveness and binding readiness",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/health",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "health"
          ]
        },
        "description": "`binding_configured: false` means quotes still price but nothing is recorded. `build.commit` names the commit CI deployed, so what answers can be tied to a reviewed version; it is null for a deployment CI did not make."
      }
    },
    {
      "name": "How much is recorded, and by whom, as counts",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/usage",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v1",
            "usage"
          ]
        },
        "description": "Entries in the quote ledger and the evidence log: totals, the last 7 and 28 days, twelve ISO weeks, and `outside`, the entries recorded with keys that are not RiskRouter's own (self-serve sandbox keys counted separately). Public: nothing but numbers and week dates is returned. Cached for five minutes at the edge. Answers 413 when the logs exceed the single-request counting ceiling, and 502/503 rather than a guess when the ledger cannot be read."
      }
    },
    {
      "name": "Record the digest of any regulated decision",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"record_digest\": \"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\",\n  \"kind\": \"ai.decision\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence"
          ]
        },
        "description": "The client hashes its own salted record and sends only the SHA-256; the record never reaches RiskRouter. The entry becomes a leaf of an RFC 6962 Merkle tree. A refused write answers 503 with recorded: false, never a success. Specification: https://riskrouter.eu/spec Optionally the client signs its own claim (signer_key_id, claimed_at, client_signature, all three or none): the signature is verified against a registered key before anything is written and then sits inside the leaf (leaf_version 3). See /spec#signed."
      }
    },
    {
      "name": "Record 1 to 500 digests in one transaction",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"entries\": [\n    {\n      \"record_digest\": \"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\",\n      \"kind\": \"ai.decision\"\n    }\n  ]\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/batch",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "batch"
          ]
        },
        "description": "The entries are recorded in the order sent, in one transaction, under the same checks and ceilings as a single record; if any entry is refused nothing is written. The body may be up to 131072 bytes. A refused write answers 503 with recorded: false, never a success."
      }
    },
    {
      "name": "The signed tree head of the evidence log",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/head",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "head"
          ]
        },
        "description": "Save it: every later head must be consistent with it."
      }
    },
    {
      "name": "Inclusion proof for one of your entries",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/proof",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "proof"
          ]
        },
        "description": "RFC 9162 audit path from the entry's leaf hash to the root of a tree of tree_size leaves. Take tree_size and root_hash from the same signed head."
      }
    },
    {
      "name": "Proof that an earlier head is a prefix of a later one",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/consistency",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "consistency"
          ]
        },
        "description": "RFC 9162 consistency proof. Check it against the root in the head you saved for first, never a root the service supplies."
      }
    },
    {
      "name": "What the log holds in one completeness chain, signed",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/chain",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "chain"
          ]
        },
        "description": "The length of the chain and, for each position from..to (at most 1,000 a page), the leaf index, the time it was sealed and the record digest, as of the current signed head, signed over riskrouter-evidence-chain|v1|chain_tag|length|tree_size|root_hash|timestamp|from|to|links_digest. Public: the tag is derived from a secret the firm keeps. Names no distributor and holds no record."
      }
    },
    {
      "name": "Register a SCITT Signed Statement and get its COSE Receipt",
      "request": {
        "method": "POST",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/statement",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "statement"
          ]
        },
        "description": "IETF SCITT registration under the riskrouter-scitt-profile|1 policy: a COSE_Sign1 hash envelope (protected 258 = -16, 32-byte payload), ES256, kid = the id of a key registered with POST /api/v2/evidence/keys, CWT claims iss and sub. The log keeps one leaf holding SHA-256 of the statement with its unprotected header emptied. Returns an RFC 9942 COSE Receipt and the Transparent Statement, base64."
      }
    },
    {
      "name": "An RFC 9942 COSE Receipt of inclusion for an entry you recorded",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/receipt",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "receipt"
          ]
        },
        "description": ""
      }
    },
    {
      "name": "The evidence log's head as a C2SP checkpoint",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/tlog/evidence-v2/checkpoint",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "tlog",
            "evidence-v2",
            "checkpoint"
          ]
        },
        "description": "A signed note (c2sp.org/tlog-checkpoint): origin api.riskrouter.eu/tlog/evidence-v2, tree size, base64 root, signed with the log's Ed25519 key. The same tree as GET /api/v2/evidence/head. The tree's hash tiles are served beside it at /tlog/evidence-v2/tile/<L>/<N>[.p/<W>] (c2sp.org/tlog-tiles); entry bundles are not published."
      }
    },
    {
      "name": "Register the public key a distributor signs its claims with",
      "request": {
        "method": "POST",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/keys",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "keys"
          ]
        },
        "description": "Once per key. Idempotent for the same key and distributor (200); a new key answers 201; a key id already registered to another distributor answers 409. Keys are never removed, so leaves signed before a rotation stay verifiable. The key is public and served to anyone by GET; publish it under your own control too."
      }
    },
    {
      "name": "A registered signing key, by id",
      "request": {
        "method": "GET",
        "auth": {
          "type": "noauth"
        },
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v2/evidence/keys",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "v2",
            "evidence",
            "keys"
          ]
        },
        "description": "Public: a public key is public, and a verifier of a v3 leaf needs it. Answers the key and when it was registered, never whose it is."
      }
    }
  ]
}
