{
  "openapi": "3.1.0",
  "info": {
    "title": "KYTRIX public API",
    "version": "2026-09-01",
    "summary": "Ingestion, canonical reads, posture and webhook management.",
    "description": "Generated from the frozen zod schemas in @kytrix/contracts — the same schemas the edge validates against — plus a route table checked against the source files that register each path. Only the surfaces reachable on api.<domain> are described; the console APIs under /console/v1/* are OIDC-session APIs and are not part of this document.",
    "contact": {
      "name": "KYTRIX integration support"
    }
  },
  "servers": [
    {
      "url": "https://api.{domain}",
      "description": "The public API host. Substitute your KYTRIX domain.",
      "variables": {
        "domain": {
          "default": "kytrix.example",
          "description": "Your KYTRIX domain, as issued with your credentials."
        }
      }
    }
  ],
  "tags": [
    {
      "name": "ingestion",
      "description": "The six event families, the batch endpoint and the dry-run. Every write here is behind the single-transaction acknowledgment of invariant I6."
    },
    {
      "name": "event-status",
      "description": "Where is event X — answerable from the moment of the 202."
    },
    {
      "name": "reads",
      "description": "What KYTRIX made of what you sent, and the band-only posture read. Eventually consistent: the 202 acknowledges the inbox commit, canonicalization happens after it."
    },
    {
      "name": "webhooks",
      "description": "Register, list, disable, test and rotate the endpoints KYTRIX delivers to."
    },
    {
      "name": "reconciliation",
      "description": "Customer-declared control totals, compared against what KYTRIX observed."
    },
    {
      "name": "imports",
      "description": "The Backfill stage, not the Connect stage. Rows are committed by the same acceptEvents transaction the live edge uses."
    },
    {
      "name": "health",
      "description": "Unauthenticated liveness of the API host."
    }
  ],
  "security": [
    {
      "KytrixHmacSha256": []
    }
  ],
  "paths": {
    "/v1/parties": {
      "post": {
        "operationId": "submit-party",
        "summary": "Submit one party event",
        "description": "A customer, business, agent or institution you have onboarded. The body is one envelope validated by `EVENT_SCHEMAS.party`; unknown members are rejected rather than dropped. The 202 is returned only after one Postgres transaction has committed both the raw event and its processing obligation (invariant I6) — there is no acknowledged-but-lost state.\n\nEntities are versioned upserts: the dedup key is (tenant, object, `external_id`, `sequence`). Send a strictly higher `sequence` for each new version; the same `sequence` with different content is `409 kytrix:sequence/conflict`, never a silent overwrite.\n\nAn exact resubmission (same identity, same canonical body) is acknowledged as a duplicate and coalesced onto the ORIGINAL `event_id`, with `idempotent_replay: true`.",
        "tags": [
          "ingestion"
        ],
        "responses": {
          "202": {
            "description": "Accepted and committed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestReceipt"
                },
                "example": {
                  "event_id": "evt_01k4f2b9m7q0z8t3d5r6y7w8xc",
                  "object": "party",
                  "external_id": "party-001",
                  "received_at": "2026-09-05T14:22:11.412Z",
                  "idempotent_replay": false
                }
              }
            }
          },
          "400": {
            "description": "The payload does not match the schema — `kytrix:validation/*` with field paths.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed — `kytrix:auth/*`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope — `kytrix:auth/insufficient_scope`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key reuse with a different body, or a sequence conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Body above the payload cap — `kytrix:request/payload_too_large`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Per-tenant rate limit — `kytrix:rate_limit/exceeded`, with `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "05 G.1",
          "05 G.3",
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "1–255 characters, scoped to (tenant, endpoint, key) and retained ≥ 24 h. Send one per logical event so a retry replays instead of double-posting.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Correlation-Id",
            "in": "header",
            "required": false,
            "description": "Your trace id; recorded on the inbox row and every KYTRIX log line for it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartyEvent"
              },
              "example": {
                "external_id": "party-001",
                "schema_version": "2026-09-01",
                "occurred_at": "2026-08-01T09:30:00-04:00",
                "sequence": 1,
                "data": {
                  "type": "person",
                  "status": "active",
                  "created_at": "2026-08-01T09:30:00-04:00",
                  "legal_names": [
                    "Ana Pérez"
                  ],
                  "identifiers": [
                    {
                      "type": "national_id",
                      "value": "001-1234567-8",
                      "verification_status": "verified"
                    }
                  ],
                  "jurisdictions": {
                    "nationality": "DO",
                    "residency": "DO"
                  },
                  "expected_profile": {
                    "declared_monthly_volume": {
                      "value": "5000000",
                      "asset": "DOP",
                      "scale": 2
                    },
                    "corridors": [
                      "US"
                    ],
                    "cash_intensity": "medium"
                  },
                  "kyc": {
                    "tier": "tier2",
                    "updated_at": "2026-08-01T09:30:00-04:00"
                  },
                  "segment": "consumer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/accounts": {
      "post": {
        "operationId": "submit-account",
        "summary": "Submit one account event",
        "description": "A wallet or ledger account held by a party. The body is one envelope validated by `EVENT_SCHEMAS.account`; unknown members are rejected rather than dropped. The 202 is returned only after one Postgres transaction has committed both the raw event and its processing obligation (invariant I6) — there is no acknowledged-but-lost state.\n\nEntities are versioned upserts: the dedup key is (tenant, object, `external_id`, `sequence`). Send a strictly higher `sequence` for each new version; the same `sequence` with different content is `409 kytrix:sequence/conflict`, never a silent overwrite.\n\nAn exact resubmission (same identity, same canonical body) is acknowledged as a duplicate and coalesced onto the ORIGINAL `event_id`, with `idempotent_replay: true`.",
        "tags": [
          "ingestion"
        ],
        "responses": {
          "202": {
            "description": "Accepted and committed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestReceipt"
                },
                "example": {
                  "event_id": "evt_01k4f2b9m7q0z8t3d5r6y7w8xc",
                  "object": "account",
                  "external_id": "acct-001",
                  "received_at": "2026-09-05T14:22:11.412Z",
                  "idempotent_replay": false
                }
              }
            }
          },
          "400": {
            "description": "The payload does not match the schema — `kytrix:validation/*` with field paths.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed — `kytrix:auth/*`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope — `kytrix:auth/insufficient_scope`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key reuse with a different body, or a sequence conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Body above the payload cap — `kytrix:request/payload_too_large`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Per-tenant rate limit — `kytrix:rate_limit/exceeded`, with `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "05 G.1",
          "05 G.3",
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "1–255 characters, scoped to (tenant, endpoint, key) and retained ≥ 24 h. Send one per logical event so a retry replays instead of double-posting.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Correlation-Id",
            "in": "header",
            "required": false,
            "description": "Your trace id; recorded on the inbox row and every KYTRIX log line for it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountEvent"
              },
              "example": {
                "external_id": "acct-001",
                "schema_version": "2026-09-01",
                "occurred_at": "2026-08-01T09:30:00-04:00",
                "sequence": 1,
                "data": {
                  "type": "wallet",
                  "holder_party_id": "party-001",
                  "asset": "DOP",
                  "status": "active",
                  "opened_at": "2026-08-01T09:30:00-04:00",
                  "product_code": "wallet-basic"
                }
              }
            }
          }
        }
      }
    },
    "/v1/instruments": {
      "post": {
        "operationId": "submit-instrument",
        "summary": "Submit one instrument event",
        "description": "A card token, device, phone number or other payment instrument. The body is one envelope validated by `EVENT_SCHEMAS.instrument`; unknown members are rejected rather than dropped. The 202 is returned only after one Postgres transaction has committed both the raw event and its processing obligation (invariant I6) — there is no acknowledged-but-lost state.\n\nEntities are versioned upserts: the dedup key is (tenant, object, `external_id`, `sequence`). Send a strictly higher `sequence` for each new version; the same `sequence` with different content is `409 kytrix:sequence/conflict`, never a silent overwrite.\n\nAn exact resubmission (same identity, same canonical body) is acknowledged as a duplicate and coalesced onto the ORIGINAL `event_id`, with `idempotent_replay: true`.",
        "tags": [
          "ingestion"
        ],
        "responses": {
          "202": {
            "description": "Accepted and committed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestReceipt"
                },
                "example": {
                  "event_id": "evt_01k4f2b9m7q0z8t3d5r6y7w8xc",
                  "object": "instrument",
                  "external_id": "inst-001",
                  "received_at": "2026-09-05T14:22:11.412Z",
                  "idempotent_replay": false
                }
              }
            }
          },
          "400": {
            "description": "The payload does not match the schema — `kytrix:validation/*` with field paths.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed — `kytrix:auth/*`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope — `kytrix:auth/insufficient_scope`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key reuse with a different body, or a sequence conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Body above the payload cap — `kytrix:request/payload_too_large`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Per-tenant rate limit — `kytrix:rate_limit/exceeded`, with `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "05 G.1",
          "05 G.3",
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "1–255 characters, scoped to (tenant, endpoint, key) and retained ≥ 24 h. Send one per logical event so a retry replays instead of double-posting.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Correlation-Id",
            "in": "header",
            "required": false,
            "description": "Your trace id; recorded on the inbox row and every KYTRIX log line for it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InstrumentEvent"
              },
              "example": {
                "external_id": "inst-001",
                "schema_version": "2026-09-01",
                "occurred_at": "2026-08-01T09:30:00-04:00",
                "sequence": 1,
                "data": {
                  "type": "card_token",
                  "status": "active",
                  "first_seen_at": "2026-08-01T09:30:00-04:00",
                  "issuer_ref": "BPD",
                  "masked_identifier": "411111******1111",
                  "country": "DO",
                  "verification_status": "verified",
                  "fingerprint": "fp_9c1e2d"
                }
              }
            }
          }
        }
      }
    },
    "/v1/movements": {
      "post": {
        "operationId": "submit-movement",
        "summary": "Submit one movement event",
        "description": "A value transfer — including failed, pending and reversed ones. The body is one envelope validated by `EVENT_SCHEMAS.movement`; unknown members are rejected rather than dropped. The 202 is returned only after one Postgres transaction has committed both the raw event and its processing obligation (invariant I6) — there is no acknowledged-but-lost state.\n\nFacts are immutable: the dedup key is (tenant, object, `external_id`) with no `sequence`. Any differing resubmission of the same `external_id` is `409 kytrix:sequence/conflict` — corrections are NEW events carrying `links.correction_of` and a `correction_reason`.\n\nAn exact resubmission is acknowledged as a duplicate and coalesced onto the ORIGINAL `event_id`, with `idempotent_replay: true`.",
        "tags": [
          "ingestion"
        ],
        "responses": {
          "202": {
            "description": "Accepted and committed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestReceipt"
                },
                "example": {
                  "event_id": "evt_01k4f2b9m7q0z8t3d5r6y7w8xc",
                  "object": "movement",
                  "external_id": "mov-001",
                  "received_at": "2026-09-05T14:22:11.412Z",
                  "idempotent_replay": false
                }
              }
            }
          },
          "400": {
            "description": "The payload does not match the schema — `kytrix:validation/*` with field paths.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed — `kytrix:auth/*`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope — `kytrix:auth/insufficient_scope`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key reuse with a different body, or a sequence conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Body above the payload cap — `kytrix:request/payload_too_large`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Per-tenant rate limit — `kytrix:rate_limit/exceeded`, with `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "05 G.1",
          "05 G.3",
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "1–255 characters, scoped to (tenant, endpoint, key) and retained ≥ 24 h. Send one per logical event so a retry replays instead of double-posting.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Correlation-Id",
            "in": "header",
            "required": false,
            "description": "Your trace id; recorded on the inbox row and every KYTRIX log line for it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MovementEvent"
              },
              "example": {
                "external_id": "mov-001",
                "schema_version": "2026-09-01",
                "occurred_at": "2026-08-30T12:00:00-04:00",
                "recorded_at": "2026-08-30T12:00:00-04:00",
                "data": {
                  "type": "p2p",
                  "status": "completed",
                  "amount": {
                    "value": "18000000",
                    "asset": "DOP",
                    "scale": 2
                  },
                  "debit": {
                    "account_id": "acct-001",
                    "party_id": "party-001"
                  },
                  "credit": {
                    "counterparty": {
                      "institution": "BPD",
                      "country": "DO",
                      "name_as_given": "J. Gómez"
                    }
                  },
                  "cash": false,
                  "memo": "rent august",
                  "channel": "app",
                  "rail": "internal",
                  "ip": "190.166.1.10",
                  "geo": {
                    "country": "DO",
                    "lat": 18.47,
                    "lon": -69.9
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/relationships": {
      "post": {
        "operationId": "submit-relationship",
        "summary": "Submit one relationship event",
        "description": "A declared link between two entities (ownership, signatory, device sharing). The body is one envelope validated by `EVENT_SCHEMAS.relationship`; unknown members are rejected rather than dropped. The 202 is returned only after one Postgres transaction has committed both the raw event and its processing obligation (invariant I6) — there is no acknowledged-but-lost state.\n\nEntities are versioned upserts: the dedup key is (tenant, object, `external_id`, `sequence`). Send a strictly higher `sequence` for each new version; the same `sequence` with different content is `409 kytrix:sequence/conflict`, never a silent overwrite.\n\nAn exact resubmission (same identity, same canonical body) is acknowledged as a duplicate and coalesced onto the ORIGINAL `event_id`, with `idempotent_replay: true`.",
        "tags": [
          "ingestion"
        ],
        "responses": {
          "202": {
            "description": "Accepted and committed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestReceipt"
                },
                "example": {
                  "event_id": "evt_01k4f2b9m7q0z8t3d5r6y7w8xc",
                  "object": "relationship",
                  "external_id": "rel-001",
                  "received_at": "2026-09-05T14:22:11.412Z",
                  "idempotent_replay": false
                }
              }
            }
          },
          "400": {
            "description": "The payload does not match the schema — `kytrix:validation/*` with field paths.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed — `kytrix:auth/*`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope — `kytrix:auth/insufficient_scope`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key reuse with a different body, or a sequence conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Body above the payload cap — `kytrix:request/payload_too_large`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Per-tenant rate limit — `kytrix:rate_limit/exceeded`, with `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "05 G.1",
          "05 G.3",
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "1–255 characters, scoped to (tenant, endpoint, key) and retained ≥ 24 h. Send one per logical event so a retry replays instead of double-posting.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Correlation-Id",
            "in": "header",
            "required": false,
            "description": "Your trace id; recorded on the inbox row and every KYTRIX log line for it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RelationshipEvent"
              },
              "example": {
                "external_id": "rel-001",
                "schema_version": "2026-09-01",
                "occurred_at": "2026-08-01T09:30:00-04:00",
                "sequence": 1,
                "data": {
                  "type": "owns_instrument",
                  "from": {
                    "kind": "party",
                    "external_id": "party-001"
                  },
                  "to": {
                    "kind": "instrument",
                    "external_id": "inst-001"
                  },
                  "valid_from": "2026-08-01T09:30:00-04:00",
                  "source": "kyc",
                  "confidence": 1
                }
              }
            }
          }
        }
      }
    },
    "/v1/control-events": {
      "post": {
        "operationId": "submit-control_event",
        "summary": "Submit one control event event",
        "description": "Something your own controls did: a blocked withdrawal, a limit hit, a manual review. The body is one envelope validated by `EVENT_SCHEMAS.control_event`; unknown members are rejected rather than dropped. The 202 is returned only after one Postgres transaction has committed both the raw event and its processing obligation (invariant I6) — there is no acknowledged-but-lost state.\n\nFacts are immutable: the dedup key is (tenant, object, `external_id`) with no `sequence`. Any differing resubmission of the same `external_id` is `409 kytrix:sequence/conflict` — corrections are NEW events carrying `links.correction_of` and a `correction_reason`.\n\nAn exact resubmission is acknowledged as a duplicate and coalesced onto the ORIGINAL `event_id`, with `idempotent_replay: true`.",
        "tags": [
          "ingestion"
        ],
        "responses": {
          "202": {
            "description": "Accepted and committed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestReceipt"
                },
                "example": {
                  "event_id": "evt_01k4f2b9m7q0z8t3d5r6y7w8xc",
                  "object": "control_event",
                  "external_id": "ctl-001",
                  "received_at": "2026-09-05T14:22:11.412Z",
                  "idempotent_replay": false
                }
              }
            }
          },
          "400": {
            "description": "The payload does not match the schema — `kytrix:validation/*` with field paths.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed — `kytrix:auth/*`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope — `kytrix:auth/insufficient_scope`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key reuse with a different body, or a sequence conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Body above the payload cap — `kytrix:request/payload_too_large`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Per-tenant rate limit — `kytrix:rate_limit/exceeded`, with `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "05 G.1",
          "05 G.3",
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "1–255 characters, scoped to (tenant, endpoint, key) and retained ≥ 24 h. Send one per logical event so a retry replays instead of double-posting.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Correlation-Id",
            "in": "header",
            "required": false,
            "description": "Your trace id; recorded on the inbox row and every KYTRIX log line for it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ControlEventEvent"
              },
              "example": {
                "external_id": "ctl-001",
                "schema_version": "2026-09-01",
                "occurred_at": "2026-08-30T12:00:00-04:00",
                "data": {
                  "type": "withdrawal.blocked",
                  "subject": {
                    "kind": "account",
                    "external_id": "acct-001"
                  },
                  "outcome": "blocked",
                  "reason_code": "daily_limit",
                  "actor_kind": "customer_system",
                  "customer_severity": "medium",
                  "linked_movement_id": "mov-001"
                }
              }
            }
          }
        }
      }
    },
    "/v1/batches": {
      "post": {
        "operationId": "batches",
        "summary": "Submit up to 1,000 mixed events",
        "description": "Acceptance is atomic, validation is per item: one malformed event becomes its own `rejected` result instead of failing the request, so a bad row never loses the other 999. Duplicates count as accepted and carry `idempotent_replay: true`. The rate-limit cost is the number of submitted events, so one 1,000-event batch and 1,000 single submits are throttled identically.\n\nCheck `results[i].outcome` for every item. A 202 does NOT mean every event landed.\n\nAn `Idempotency-Key` on a batch covers the batch acceptance; per-event dedup still applies through the external ids.",
        "tags": [
          "ingestion"
        ],
        "responses": {
          "202": {
            "description": "At least one item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResponse"
                },
                "example": {
                  "accepted": 1,
                  "rejected": 1,
                  "results": [
                    {
                      "index": 0,
                      "outcome": "accepted",
                      "receipt": {
                        "event_id": "evt_01k4f2b9m7q0z8t3d5r6y7w8xc",
                        "object": "party",
                        "external_id": "party-001",
                        "received_at": "2026-09-05T14:22:11.412Z",
                        "idempotent_replay": false
                      }
                    },
                    {
                      "index": 1,
                      "outcome": "rejected",
                      "problem": {
                        "type": "kytrix:validation/schema",
                        "title": "Request does not match the schema",
                        "status": 400,
                        "code": "kytrix:validation/schema",
                        "detail": "event.data.amount: Required",
                        "errors": [
                          {
                            "path": "event.data.amount",
                            "code": "kytrix:validation/schema",
                            "message": "Required"
                          }
                        ]
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The batch envelope itself is malformed (`events` missing or empty).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key reuse with a different body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "More than 1,000 events (`kytrix:batch/too_large`) or an oversized body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Every item was rejected — the same `BatchResponse` body with `accepted: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResponse"
                }
              }
            }
          },
          "429": {
            "description": "Per-tenant rate limit.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "1–255 characters, scoped to (tenant, endpoint, key) and retained ≥ 24 h. Send one per logical event so a retry replays instead of double-posting.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Correlation-Id",
            "in": "header",
            "required": false,
            "description": "Your trace id; recorded on the inbox row and every KYTRIX log line for it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRequest"
              },
              "example": {
                "events": [
                  {
                    "object": "party",
                    "event": {
                      "external_id": "party-001",
                      "schema_version": "2026-09-01",
                      "occurred_at": "2026-08-01T09:30:00-04:00",
                      "sequence": 1,
                      "data": {
                        "type": "person",
                        "status": "active",
                        "created_at": "2026-08-01T09:30:00-04:00",
                        "legal_names": [
                          "Ana Pérez"
                        ],
                        "identifiers": [
                          {
                            "type": "national_id",
                            "value": "001-1234567-8",
                            "verification_status": "verified"
                          }
                        ],
                        "jurisdictions": {
                          "nationality": "DO",
                          "residency": "DO"
                        },
                        "expected_profile": {
                          "declared_monthly_volume": {
                            "value": "5000000",
                            "asset": "DOP",
                            "scale": 2
                          },
                          "corridors": [
                            "US"
                          ],
                          "cash_intensity": "medium"
                        },
                        "kyc": {
                          "tier": "tier2",
                          "updated_at": "2026-08-01T09:30:00-04:00"
                        },
                        "segment": "consumer"
                      }
                    }
                  },
                  {
                    "object": "movement",
                    "event": {
                      "external_id": "mov-001",
                      "schema_version": "2026-09-01",
                      "occurred_at": "2026-08-30T12:00:00-04:00",
                      "recorded_at": "2026-08-30T12:00:00-04:00",
                      "data": {
                        "type": "p2p",
                        "status": "completed",
                        "amount": {
                          "value": "18000000",
                          "asset": "DOP",
                          "scale": 2
                        },
                        "debit": {
                          "account_id": "acct-001",
                          "party_id": "party-001"
                        },
                        "credit": {
                          "counterparty": {
                            "institution": "BPD",
                            "country": "DO",
                            "name_as_given": "J. Gómez"
                          }
                        },
                        "cash": false,
                        "memo": "rent august",
                        "channel": "app",
                        "rail": "internal",
                        "ip": "190.166.1.10",
                        "geo": {
                          "country": "DO",
                          "lat": 18.47,
                          "lon": -69.9
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/v1/validate": {
      "post": {
        "operationId": "validate",
        "summary": "Dry-run: full validation, nothing stored",
        "description": "Takes either a batch body (`{ events: [...] }`) or a single `{ object, event }` item and runs exactly the validation the live endpoints run. No transaction is opened on this path at all, so nothing is written: no inbox row, no obligation, no idempotency record. This is the mapping-iteration loop — run it until `valid` is true before you send anything real.\n\nA dry-run is not a reservation. It proves the shape is right; it does not hold an `external_id` or promise the live submit will not hit a sequence conflict.",
        "tags": [
          "ingestion"
        ],
        "responses": {
          "200": {
            "description": "Every item validated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Mirrored from the ValidateResponse interface in packages/ingest/src/routes.ts — not a contracts schema.",
                  "required": [
                    "valid",
                    "checked",
                    "accepted",
                    "rejected",
                    "results"
                  ],
                  "properties": {
                    "valid": {
                      "type": "boolean",
                      "description": "true only when every item validated."
                    },
                    "checked": {
                      "type": "integer"
                    },
                    "accepted": {
                      "type": "integer",
                      "description": "Items that would be accepted. Nothing is stored."
                    },
                    "rejected": {
                      "type": "integer"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "index",
                          "outcome"
                        ],
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "outcome": {
                            "type": "string",
                            "enum": [
                              "valid",
                              "rejected"
                            ]
                          },
                          "object": {
                            "type": "string",
                            "enum": [
                              "party",
                              "account",
                              "instrument",
                              "movement",
                              "relationship",
                              "control_event"
                            ]
                          },
                          "external_id": {
                            "type": "string"
                          },
                          "problem": {
                            "$ref": "#/components/schemas/ProblemDetails"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "valid": true,
                  "checked": 1,
                  "accepted": 1,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "outcome": "valid",
                      "object": "movement",
                      "external_id": "mov-001"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential has neither the `ingest` nor the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "More than 1,000 items, or an oversized body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "At least one item is invalid — same body, `valid: false`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Mirrored from the ValidateResponse interface in packages/ingest/src/routes.ts — not a contracts schema.",
                  "required": [
                    "valid",
                    "checked",
                    "accepted",
                    "rejected",
                    "results"
                  ],
                  "properties": {
                    "valid": {
                      "type": "boolean",
                      "description": "true only when every item validated."
                    },
                    "checked": {
                      "type": "integer"
                    },
                    "accepted": {
                      "type": "integer",
                      "description": "Items that would be accepted. Nothing is stored."
                    },
                    "rejected": {
                      "type": "integer"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "index",
                          "outcome"
                        ],
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "outcome": {
                            "type": "string",
                            "enum": [
                              "valid",
                              "rejected"
                            ]
                          },
                          "object": {
                            "type": "string",
                            "enum": [
                              "party",
                              "account",
                              "instrument",
                              "movement",
                              "relationship",
                              "control_event"
                            ]
                          },
                          "external_id": {
                            "type": "string"
                          },
                          "problem": {
                            "$ref": "#/components/schemas/ProblemDetails"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Per-tenant rate limit.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1",
          "05 G.2"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/events/{event_id}": {
      "get": {
        "operationId": "event-status",
        "summary": "Where is this event",
        "description": "Answers from the moment of the 202: the ingest transaction writes a `received` stage ledger row, so there is never a window where a receipt exists but the event is \"not found\". `stage_history` is the processing trail; `rejection` is the structured reason to resubmit on.\n\n`sequence` is `null` for movements and control events: immutable facts have no version.",
        "tags": [
          "event-status"
        ],
        "responses": {
          "200": {
            "description": "The inbox record and its stage history.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Mirrored from eventStatusBody() in packages/ingest/src/routes.ts — not a contracts schema.",
                  "required": [
                    "event_id",
                    "object",
                    "external_id",
                    "sequence",
                    "status",
                    "rejection",
                    "status_reason",
                    "attempts",
                    "received_at",
                    "occurred_at",
                    "terminal_at",
                    "historical",
                    "import_id",
                    "content_hash",
                    "stage_history"
                  ],
                  "properties": {
                    "event_id": {
                      "type": "string",
                      "pattern": "^evt_[0-9A-Za-z-]{8,64}$"
                    },
                    "object": {
                      "type": "string",
                      "enum": [
                        "party",
                        "account",
                        "instrument",
                        "movement",
                        "relationship",
                        "control_event"
                      ]
                    },
                    "external_id": {
                      "type": "string"
                    },
                    "sequence": {
                      "type": [
                        "integer",
                        "null"
                      ],
                      "description": "null for movements and control events (immutable facts carry no sequence)."
                    },
                    "status": {
                      "type": "string",
                      "description": "ingest.inbox_events.status, e.g. pending, rejected."
                    },
                    "rejection": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "The structured reject reason; null unless status is rejected."
                    },
                    "status_reason": {
                      "type": [
                        "object",
                        "null"
                      ]
                    },
                    "attempts": {
                      "type": "integer"
                    },
                    "received_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "occurred_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "terminal_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "historical": {
                      "type": "boolean"
                    },
                    "import_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "content_hash": {
                      "type": "string",
                      "pattern": "^sha256:[0-9a-f]{64}$"
                    },
                    "stage_history": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "stage",
                          "status",
                          "at",
                          "worker",
                          "duration_ms",
                          "detail"
                        ],
                        "properties": {
                          "stage": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "worker": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "duration_ms": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "detail": {
                            "type": [
                              "object",
                              "null"
                            ]
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "event_id": "evt_01k4f2b9m7q0z8t3d5r6y7w8xc",
                  "object": "movement",
                  "external_id": "mov-001",
                  "sequence": null,
                  "status": "pending",
                  "rejection": null,
                  "status_reason": null,
                  "attempts": 0,
                  "received_at": "2026-09-05T14:22:11.412Z",
                  "occurred_at": "2026-08-30T12:00:00-04:00",
                  "terminal_at": null,
                  "historical": false,
                  "import_id": null,
                  "content_hash": "sha256:0f5c…",
                  "stage_history": [
                    {
                      "stage": "received",
                      "status": "ok",
                      "at": "2026-09-05T14:22:11.412Z",
                      "worker": null,
                      "duration_ms": null,
                      "detail": null
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No such event in this tenant, or the id is not a KYTRIX event id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/ingest/src/routes.ts",
        "x-kytrix-doc-refs": [
          "05 G.2"
        ],
        "parameters": [
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "description": "The `evt_…` id from the receipt. A bare uuid and `evt_<uuid>` are also accepted. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/parties/{external_id}": {
      "get": {
        "operationId": "get-party",
        "summary": "Read the canonical party",
        "description": "What KYTRIX made of the party events you sent, at the current version. The response is the `PartyView` **TypeScript interface** in `packages/contracts/src/views.ts` — a type, not a zod schema — so it is not in the generated schema section below and the SDK does not validate it either. Identifiers come back as keyed hashes, never as the raw values you sent.\n\nEventually consistent. The 202 acknowledges the inbox commit; canonicalization runs after it. Do not poll this in a loop straight after a submit — use `GET /v1/events/{event_id}` to follow processing.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "`PartyView` (see `packages/contracts/src/views.ts`)."
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Unknown in this tenant — a governed 404 problem, never an empty 200.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/canonical/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1",
          "03 §3.7"
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "description": "Your id for the party, exactly as submitted. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/accounts/{external_id}": {
      "get": {
        "operationId": "get-account",
        "summary": "Read the canonical account",
        "description": "Response body is the `AccountView` interface in `packages/contracts/src/views.ts`.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "`AccountView`."
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Unknown in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/canonical/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "description": "Your account id. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/instruments/{external_id}": {
      "get": {
        "operationId": "get-instrument",
        "summary": "Read the canonical instrument",
        "description": "Response body is the `InstrumentView` interface in `packages/contracts/src/views.ts`.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "`InstrumentView`."
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Unknown in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/canonical/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "description": "Your instrument id. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/movements/{external_id}": {
      "get": {
        "operationId": "get-movement",
        "summary": "Read the canonical movement",
        "description": "Response body is the `MovementView` interface in `packages/contracts/src/views.ts`. It carries your `amount` plus, when the tenant base asset differs, a `normalized` amount with its complete FX provenance record.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "`MovementView`."
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Unknown in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/canonical/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1",
          "03 §3.2"
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "description": "Your movement id. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/parties/{external_id}/movements": {
      "get": {
        "operationId": "list-party-movements",
        "summary": "List a party’s movements",
        "description": "Cursor-paginated page of `MovementView`. Cursors are opaque — pass `next_cursor` back verbatim and never construct one.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "`{ data: MovementView[], has_more: boolean, next_cursor?: string }`."
          },
          "400": {
            "description": "Malformed cursor, limit, direction or time range.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Unknown party in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/canonical/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.2"
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "description": "Your party id. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from a previous page. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. (integer (1–200, default 50))",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "required": false,
            "description": "`in` = the party is on the credit side (value arriving), `out` = the debit side (value leaving), `both` = either. (`in` \\| `out` \\| `both`)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Lower bound on the movement time. (RFC 3339)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Upper bound on the movement time. (RFC 3339)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/posture/parties/{external_id}": {
      "get": {
        "operationId": "posture-party",
        "summary": "Party posture — band only",
        "description": "The one risk read an operational system may have: a band, when it was computed, how stale it is, and the coverage state behind it. There are deliberately **no** reasons, typologies, detector names or narratives here — putting those in an operational system is a tipping-off risk (14 P.5).\n\n`unknown` and `incomplete` are real answers, not errors — they mean \"no basis\" and \"gaps in the data behind this band\". Treat them as safely ignorable, never as \"blocked\" (invariant I7).\n\nKYTRIX advises; you enforce. Nothing in this API writes your account status.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "The posture.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostureResponse"
                },
                "example": {
                  "subject": {
                    "kind": "party",
                    "external_id": "party-001"
                  },
                  "risk_state": "watch",
                  "as_of": "2026-09-05T14:20:00Z",
                  "freshness_seconds": 131,
                  "coverage_state": "complete"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Unknown party in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/alerts/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1",
          "14 P.5",
          "08 J.1"
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "description": "Your party id. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/posture/accounts/{external_id}": {
      "get": {
        "operationId": "posture-account",
        "summary": "Account posture — band only",
        "description": "As above, for an account.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "The posture.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Unknown account in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/alerts/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1",
          "14 P.5"
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "description": "Your account id. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/alerts": {
      "get": {
        "operationId": "list-alerts",
        "summary": "List alerts",
        "description": "Restricted AML content: every alert is `classification: \"restricted_aml\"`. Keep it out of operational systems, support tooling and status pages.\n\nThe served resource widens the contracts `Alert` in one place: `ruleset_version_id` may be `null` for firings produced before ruleset provenance was stamped. Inventing one would be a fabricated fact.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "`{ data: Alert[], has_more: boolean, next_cursor?: string }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "400": {
            "description": "Bad query parameter.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/alerts/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1",
          "10 L.5",
          "14 P.5"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Alert status filter. (string (≤64))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Only alerts opened at or after this instant. (RFC 3339)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor. (string (≤4096))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. (integer (1–200, default 50))",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/alerts/{alert_id}": {
      "get": {
        "operationId": "get-alert",
        "summary": "Read one alert",
        "description": "The full alert resource, including observed values, thresholds and the coverage stamp.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "The alert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No such alert in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/alerts/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "required": true,
            "description": "The alert id. (string (`alrt_…`))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/episodes": {
      "get": {
        "operationId": "list-episodes",
        "summary": "List episodes",
        "description": "An episode is the investigation unit: related alerts about one subject, grouped so an analyst sees one thing to work rather than forty.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "`{ data: Episode[], has_more: boolean, next_cursor?: string }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Episode"
                }
              }
            }
          },
          "400": {
            "description": "Bad query parameter.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/alerts/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1",
          "10 L.5"
        ],
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Episode state filter. (EpisodeState)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Lower bound on time. (RFC 3339)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor. (string (≤4096))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. (integer (1–200, default 50))",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/episodes/{episode_id}": {
      "get": {
        "operationId": "get-episode",
        "summary": "Read one episode",
        "description": "The episode with its state and escalation history.",
        "tags": [
          "reads"
        ],
        "responses": {
          "200": {
            "description": "The episode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Episode"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `read` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No such episode in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/alerts/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "episode_id",
            "in": "path",
            "required": true,
            "description": "The episode id. (string (`epsd_…`))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/webhook-endpoints": {
      "post": {
        "operationId": "create-webhook-endpoint",
        "summary": "Register an endpoint",
        "description": "Registers a delivery target and returns its signing secret **once**. Endpoint management is its own scope so an ingest-only key cannot repoint your egress. The `channel` is a compliance control, not a preference: `compliance` endpoints receive restricted AML content, `operational` endpoints receive only sanitized events.\n\nThis endpoint does not honour `Idempotency-Key` — only the ingest endpoints implement the idempotency matrix today, so the SDK sends no automatic key here and never retries it.",
        "tags": [
          "webhooks"
        ],
        "responses": {
          "201": {
            "description": "Registered. `secret` is present in this response and never again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "A WebhookEndpoint plus the plaintext `secret`. Mirrored from the POST handler in packages/webhooks/src/routes.ts. The secret exists in this response and never again.",
                  "required": [
                    "endpoint_id",
                    "tenant_id",
                    "url",
                    "channel",
                    "event_types",
                    "status",
                    "created_at",
                    "secret"
                  ],
                  "properties": {
                    "endpoint_id": {
                      "type": "string",
                      "pattern": "^whk_[0-9A-Za-z-]{8,64}$"
                    },
                    "tenant_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "channel": {
                      "type": "string",
                      "enum": [
                        "compliance",
                        "operational"
                      ]
                    },
                    "event_types": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "disabled"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "secret": {
                      "type": "string",
                      "description": "base64url, 32 bytes. Store it in your secret manager immediately."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not HTTPS, a private/link-local/metadata address, or a restricted event type on an `operational` channel — `kytrix:webhook/invalid_endpoint`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `webhook_mgmt` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/webhooks/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1",
          "06 H.6",
          "14 P.5"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Mirrored from CreateBodySchema in packages/webhooks/src/routes.ts (a route-local zod schema, not exported from contracts).",
                "additionalProperties": false,
                "required": [
                  "url",
                  "channel"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000,
                    "description": "HTTPS only. Private, link-local and cloud-metadata ranges are refused with kytrix:webhook/invalid_endpoint (06 H.6 SSRF posture, AT-23)."
                  },
                  "channel": {
                    "type": "string",
                    "enum": [
                      "compliance",
                      "operational"
                    ]
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 1000
                  },
                  "event_types": {
                    "type": "array",
                    "maxItems": 64,
                    "items": {
                      "type": "string"
                    },
                    "description": "Subset of the catalog deliverable on this channel; omit or leave empty for all deliverable events. Subscribing a restricted_aml event on an operational endpoint is refused."
                  }
                }
              },
              "example": {
                "url": "https://paydoly.example/kytrix/webhooks",
                "channel": "compliance",
                "event_types": [
                  "alert.opened",
                  "episode.escalated"
                ]
              }
            }
          }
        }
      },
      "get": {
        "operationId": "list-webhook-endpoints",
        "summary": "List endpoints",
        "description": "Every endpoint of the tenant. Secrets are never returned.",
        "tags": [
          "webhooks"
        ],
        "responses": {
          "200": {
            "description": "`{ endpoints: WebhookEndpoint[] }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `webhook_mgmt` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/webhooks/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/webhook-endpoints/{id}": {
      "get": {
        "operationId": "get-webhook-endpoint",
        "summary": "Read one endpoint",
        "description": "One endpoint, without its secret.",
        "tags": [
          "webhooks"
        ],
        "responses": {
          "200": {
            "description": "The endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `webhook_mgmt` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/webhooks/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.1"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The endpoint id. (string (`whk_…`))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "delete": {
        "operationId": "disable-webhook-endpoint",
        "summary": "Disable an endpoint",
        "description": "Endpoints are **disabled, never deleted** — their delivery history has to stay auditable. The response is the endpoint with `status: \"disabled\"`.",
        "tags": [
          "webhooks"
        ],
        "responses": {
          "200": {
            "description": "The disabled endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `webhook_mgmt` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/webhooks/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.6"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The endpoint id. (string (`whk_…`))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/webhook-endpoints/{id}/rotate-secret": {
      "post": {
        "operationId": "rotate-webhook-secret",
        "summary": "Rotate the signing secret",
        "description": "Issues a new secret and keeps the previous one valid until `previous_secret_valid_until`. During the overlap KYTRIX signs every delivery with **both** secrets (two `v1=` entries), so a receiver that verifies against `[new, previous]` never drops a message.",
        "tags": [
          "webhooks"
        ],
        "responses": {
          "200": {
            "description": "Rotated. The new `secret` is present here and never again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Mirrored from the rotate-secret handler in packages/webhooks/src/routes.ts (the RotatedWebhookEndpoint returned by WebhookEndpointService.rotateSecret).",
                  "required": [
                    "endpoint_id",
                    "tenant_id",
                    "url",
                    "channel",
                    "event_types",
                    "status",
                    "created_at",
                    "secret",
                    "previous_secret_valid_until"
                  ],
                  "properties": {
                    "endpoint_id": {
                      "type": "string",
                      "pattern": "^whk_[0-9A-Za-z-]{8,64}$"
                    },
                    "tenant_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "channel": {
                      "type": "string",
                      "enum": [
                        "compliance",
                        "operational"
                      ]
                    },
                    "event_types": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "disabled"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "secret": {
                      "type": "string",
                      "description": "base64url, 32 bytes. Store it in your secret manager immediately."
                    },
                    "previous_secret_valid_until": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Until this instant BOTH secrets sign every delivery, so verify with both. The overlap is the webhooks package `secret_rotation_overlap_hours` config surface."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `webhook_mgmt` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/webhooks/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.6"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The endpoint id. (string (`whk_…`))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/webhook-endpoints/{id}/test": {
      "post": {
        "operationId": "test-webhook-endpoint",
        "summary": "Send a `webhook.test` event",
        "description": "Delivers a real, signed `webhook.test` envelope through the ordinary delivery path — same envelope builder, same signature, same SSRF checks, same delivery row. A test that took a shortcut would verify nothing. `webhook.test` is classified `operational` and is deliverable on both channels, so it can verify a compliance endpoint without carrying AML content.\n\nKNOWN DEPLOYMENT LIMITATION: this is the only route on the API host that makes an outbound request, and in the current VPS deployment the edge container is attached to the internal network only. Until egress is granted it fails visibly with a transport error (502). Documented in `apps/edge/src/app.ts`; verify signatures against the published webhook test vectors in the meantime.",
        "tags": [
          "webhooks"
        ],
        "responses": {
          "200": {
            "description": "Your endpoint answered 2xx (`verified: true`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Mirrored from TestEventResult in packages/webhooks/src/test-event.ts.",
                  "required": [
                    "endpoint_id",
                    "delivery_id",
                    "event_id",
                    "disposition",
                    "response_status",
                    "error",
                    "verified"
                  ],
                  "properties": {
                    "endpoint_id": {
                      "type": "string"
                    },
                    "delivery_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "event_id": {
                      "type": "string"
                    },
                    "disposition": {
                      "type": "string",
                      "enum": [
                        "delivered",
                        "retry_scheduled",
                        "dead",
                        "skipped_duplicate",
                        "not_deliverable"
                      ]
                    },
                    "response_status": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "error": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "verified": {
                      "type": "boolean",
                      "description": "true when your endpoint answered 2xx."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `webhook_mgmt` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint in this tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "The delivery attempt did not succeed. The body is the same `TestEventResult`, with the status code or transport reason — the failure is reported, never hidden.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Mirrored from TestEventResult in packages/webhooks/src/test-event.ts.",
                  "required": [
                    "endpoint_id",
                    "delivery_id",
                    "event_id",
                    "disposition",
                    "response_status",
                    "error",
                    "verified"
                  ],
                  "properties": {
                    "endpoint_id": {
                      "type": "string"
                    },
                    "delivery_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "event_id": {
                      "type": "string"
                    },
                    "disposition": {
                      "type": "string",
                      "enum": [
                        "delivered",
                        "retry_scheduled",
                        "dead",
                        "skipped_duplicate",
                        "not_deliverable"
                      ]
                    },
                    "response_status": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "error": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "verified": {
                      "type": "boolean",
                      "description": "true when your endpoint answered 2xx."
                    }
                  }
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/webhooks/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.6",
          "A10"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The endpoint id. (string (`whk_…`))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/webhook-deliveries": {
      "get": {
        "operationId": "list-webhook-deliveries",
        "summary": "List delivery attempts",
        "description": "Every attempt, newest first, with response status, latency and the next scheduled retry. Keyset-paginated over `(created_at, delivery_id)`, so the page is stable under concurrent writes.",
        "tags": [
          "webhooks"
        ],
        "responses": {
          "200": {
            "description": "`{ deliveries: WebhookDelivery[], next_cursor: string | null }`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Mirrored from deliveryJson() in packages/webhooks/src/routes.ts.",
                  "required": [
                    "delivery_id",
                    "endpoint_id",
                    "event_id",
                    "event_type",
                    "classification",
                    "attempt",
                    "status",
                    "response_status",
                    "latency_ms",
                    "error",
                    "next_attempt_at",
                    "created_at",
                    "delivered_at"
                  ],
                  "properties": {
                    "delivery_id": {
                      "type": "string"
                    },
                    "endpoint_id": {
                      "type": "string",
                      "pattern": "^whk_[0-9A-Za-z-]{8,64}$"
                    },
                    "event_id": {
                      "type": "string"
                    },
                    "event_type": {
                      "type": "string"
                    },
                    "classification": {
                      "type": "string",
                      "enum": [
                        "restricted_aml",
                        "advisory",
                        "operational"
                      ]
                    },
                    "attempt": {
                      "type": "integer"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "pending",
                        "in_flight",
                        "delivered",
                        "failed",
                        "dead"
                      ]
                    },
                    "response_status": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "latency_ms": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "error": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "next_attempt_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "delivered_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Malformed cursor or query parameter.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `webhook_mgmt` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/webhooks/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.6"
        ],
        "parameters": [
          {
            "name": "endpoint",
            "in": "query",
            "required": false,
            "description": "Filter to one endpoint. (string (`whk_…`))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Delivery status filter. (`pending` \\| `in_flight` \\| `delivered` \\| `failed` \\| `dead`)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event_type",
            "in": "query",
            "required": false,
            "description": "Filter to one event type. (WebhookEventType)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from `next_cursor`. (string (≤512))",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. (integer (1–200, default 50))",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/webhook-deliveries/{id}/replay": {
      "post": {
        "operationId": "replay-webhook-delivery",
        "summary": "Re-deliver an envelope",
        "description": "Rebuilds the same envelope id from the retained source and delivers it again. Your consumer will see a duplicate `id` — dedupe on it, do not treat it as new.",
        "tags": [
          "webhooks"
        ],
        "responses": {
          "202": {
            "description": "`{ replay_of, delivery_id, event_id, disposition, response_status, error }` (mirrored from `ReplayResult` in `packages/webhooks/src/replay.ts`)."
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `webhook_mgmt` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Unknown delivery, an endpoint that no longer exists, or a source payload that is no longer retained.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/webhooks/src/routes.ts",
        "x-kytrix-doc-refs": [
          "06 H.6"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The delivery id to replay. (string)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/reconciliations": {
      "post": {
        "operationId": "reconciliations",
        "summary": "Submit control totals",
        "description": "Declare what you believe you sent for a feed and a window — record count and/or monetary total. KYTRIX compares it against what it observed in the next coverage sweep; a delta opens a coverage finding rather than silently disappearing. This is how a silently broken feed gets noticed.\n\n`monetary_total` is `Money` — an integer string of minor units, like every other amount.",
        "tags": [
          "reconciliation"
        ],
        "responses": {
          "202": {
            "description": "Recorded; reconciliation happens in the next coverage sweep.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Mirrored from the POST /v1/reconciliations handler in packages/coverage/src/routes.ts.",
                  "required": [
                    "submission_id",
                    "feed",
                    "window_from",
                    "window_to",
                    "status",
                    "detail"
                  ],
                  "properties": {
                    "submission_id": {
                      "type": "string"
                    },
                    "feed": {
                      "type": "string"
                    },
                    "window_from": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "window_to": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "status": {
                      "type": "string"
                    },
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Body does not match the schema.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/coverage/src/routes.ts",
        "x-kytrix-doc-refs": [
          "17 S.2",
          "22 X.2"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Mirrored from ReconciliationBodySchema in packages/coverage/src/routes.ts (a route-local zod schema, not exported from contracts).",
                "additionalProperties": false,
                "required": [
                  "feed",
                  "window_from",
                  "window_to"
                ],
                "properties": {
                  "feed": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "object_type": {
                    "type": "string",
                    "enum": [
                      "party",
                      "account",
                      "instrument",
                      "movement",
                      "relationship",
                      "control_event"
                    ]
                  },
                  "window_from": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "window_to": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "record_count": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "monetary_total": {
                    "$ref": "#/components/schemas/Money"
                  }
                }
              },
              "example": {
                "feed": "core-banking-movements",
                "object_type": "movement",
                "window_from": "2026-09-04T00:00:00-04:00",
                "window_to": "2026-09-05T00:00:00-04:00",
                "record_count": 184233,
                "monetary_total": {
                  "value": "918442300",
                  "asset": "DOP",
                  "scale": 2
                }
              }
            }
          }
        }
      }
    },
    "/v1/imports": {
      "post": {
        "operationId": "imports",
        "summary": "Create a historical import",
        "description": "Opens an import for a mapping and a family. The rest of the flow is chunk upload (`PUT /v1/imports/{id}/chunks/{n}`), dry-run, `submit`, and the reject report. Every imported row is committed by the same `acceptEvents` transaction the live edge uses — there is no second ingestion path. See the field-mapping worksheet for the mapping file.\n\nThe import surface is documented here as a pointer, not in full: it is the Backfill stage, not the Connect gate, the SDK has no typed methods for it yet, and the conformance CLI does not certify it. `packages/imports/README.md` is the reference.",
        "tags": [
          "imports"
        ],
        "responses": {
          "201": {
            "description": "The import view (status `open`)."
          },
          "400": {
            "description": "The mapping is invalid — unknown target paths are named, with the nearby real fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Signature missing, wrong, stale or replayed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential lacks the `ingest` scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "x-kytrix-source": "packages/imports/src/routes.ts",
        "x-kytrix-doc-refs": [
          "05 G.7",
          "22 X.2"
        ],
        "parameters": [
          {
            "name": "Kytrix-Key-Id",
            "in": "header",
            "required": true,
            "description": "Your API key id (`kx_test_…`/`kx_live_…`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix seconds, decimal. ±300 s of KYTRIX time.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Nonce",
            "in": "header",
            "required": true,
            "description": "1–64 chars of `A-Za-z0-9._~-`, single-use for 600 s per key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kytrix-Signature",
            "in": "header",
            "required": true,
            "description": "`v1=<lower-hex HMAC-SHA256>` over the canonical string.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/healthz": {
      "get": {
        "operationId": "healthz",
        "summary": "Liveness",
        "description": "Answers 2xx once the database and Redis are reachable. Do not sign this request.",
        "tags": [
          "health"
        ],
        "responses": {
          "200": {
            "description": "Healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthzResponse"
                },
                "example": {
                  "status": "ok",
                  "checks": {
                    "db": true,
                    "redis": true
                  }
                }
              }
            }
          },
          "503": {
            "description": "A dependency is unreachable."
          }
        },
        "x-kytrix-source": "apps/edge/src/health.ts",
        "x-kytrix-doc-refs": [
          "20 V"
        ],
        "security": []
      }
    }
  },
  "components": {
    "securitySchemes": {
      "KytrixHmacSha256": {
        "type": "apiKey",
        "in": "header",
        "name": "Kytrix-Signature",
        "description": "Every request except GET /healthz is signed with KYTRIX-HMAC-SHA256 (06 H.3). Four headers are required together: Kytrix-Key-Id, Kytrix-Timestamp, Kytrix-Nonce and Kytrix-Signature. The signature is hex(HMAC-SHA256(secret_bytes, canonical_string)) where the canonical string is eight lines joined by \"\\n\": the literal KYTRIX-HMAC-SHA256, the upper-cased method, the normalized path, the canonical query, the lower-hex SHA-256 of the raw body bytes, the timestamp, the nonce and the key id. OpenAPI cannot express a request-signing scheme, so it is declared here as a header credential and documented in full at /integration.html#signing."
      }
    },
    "schemas": {
      "AccountEvent": {
        "type": "object",
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "x-kytrix-refined": true
          },
          "schema_version": {
            "type": "string",
            "const": "2026-09-01"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "sequence": {
            "type": "integer",
            "minimum": 0
          },
          "data": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "wallet",
                  "checking",
                  "savings",
                  "merchant",
                  "settlement",
                  "stored_value",
                  "loan",
                  "remittance",
                  "other"
                ]
              },
              "holder_party_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "asset": {
                "type": "string",
                "pattern": "^[A-Z]{3}$|^X-[A-Z0-9]{2,10}$"
              },
              "status": {
                "type": "string",
                "enum": [
                  "active",
                  "dormant",
                  "closed",
                  "restricted",
                  "frozen",
                  "unrestricted",
                  "withdrawals_restricted",
                  "account_restricted",
                  "transfers_suspended"
                ]
              },
              "opened_at": {
                "type": "string",
                "format": "date-time",
                "x-kytrix-refined": true
              },
              "product_code": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "purpose": {
                "type": "string",
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "expected_use": {
                "type": "string",
                "maxLength": 512,
                "x-kytrix-refined": true
              },
              "agent_of_opening_party_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "jurisdiction": {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              "closed_at": {
                "type": "string",
                "format": "date-time",
                "x-kytrix-refined": true
              },
              "closure_reason": {
                "type": "string",
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "external_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              },
              "correction_reason": {
                "type": "string",
                "maxLength": 256,
                "x-kytrix-refined": true
              }
            },
            "required": [
              "type",
              "holder_party_id",
              "asset",
              "status",
              "opened_at"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "external_id",
          "schema_version",
          "occurred_at",
          "data"
        ],
        "additionalProperties": false
      },
      "Alert": {
        "type": "object",
        "properties": {
          "alert_id": {
            "type": "string",
            "pattern": "^alrt_[0-9A-Za-z-]{8,64}$"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "subject": {
            "$ref": "#/components/schemas/EntityRef"
          },
          "entity_refs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EntityRef"
            }
          },
          "detectors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "pattern": "^[A-Z]{3}-\\d{3}$"
                },
                "version": {
                  "type": "string",
                  "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-[0-9A-Za-z.-]+)?$"
                }
              },
              "required": [
                "id",
                "version"
              ]
            },
            "minItems": 1
          },
          "signal_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^sig_[0-9A-Za-z-]{8,64}$"
            },
            "minItems": 1
          },
          "episode_id": {
            "type": "string",
            "pattern": "^epsd_[0-9A-Za-z-]{8,64}$"
          },
          "family": {
            "type": "string",
            "enum": [
              "AMT",
              "VEL",
              "STR",
              "FAN",
              "FLW",
              "NID",
              "BCH",
              "CTL"
            ]
          },
          "typology": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "severity": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high",
              "critical"
            ]
          },
          "confidence": {
            "type": "object",
            "properties": {
              "band": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ]
              },
              "factors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "factor": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 128
                    },
                    "weight": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "note": {
                      "type": "string",
                      "maxLength": 500
                    }
                  },
                  "required": [
                    "factor",
                    "weight"
                  ]
                }
              }
            },
            "required": [
              "band",
              "factors"
            ]
          },
          "evidence_bundle_hash": {
            "type": "string",
            "pattern": "^sha256:[0-9a-f]{64}$"
          },
          "movement_refs": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256,
              "x-kytrix-refined": true
            }
          },
          "control_event_refs": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256,
              "x-kytrix-refined": true
            }
          },
          "graph_paths": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "nodes": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "party",
                          "account",
                          "instrument",
                          "device",
                          "external_entity"
                        ]
                      },
                      "ref": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "required": [
                      "kind",
                      "ref"
                    ]
                  },
                  "minItems": 1
                },
                "edges": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "movement",
                          "ownership",
                          "authorized_control",
                          "beneficial_ownership",
                          "shared_instrument",
                          "shared_device",
                          "shared_identifier",
                          "referral",
                          "onboarding",
                          "counterparty",
                          "same_as"
                        ]
                      },
                      "from_idx": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "to_idx": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "occurred_at": {
                        "type": "string",
                        "format": "date-time",
                        "x-kytrix-refined": true
                      },
                      "amount": {
                        "$ref": "#/components/schemas/Money"
                      },
                      "confidence": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "reliability_class": {
                        "type": "string",
                        "enum": [
                          "high",
                          "medium",
                          "low"
                        ]
                      },
                      "supporting_refs": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 256,
                          "x-kytrix-refined": true
                        }
                      }
                    },
                    "required": [
                      "type",
                      "from_idx",
                      "to_idx"
                    ]
                  }
                },
                "span_seconds": {
                  "type": "integer",
                  "minimum": 0
                },
                "total_amount": {
                  "$ref": "#/components/schemas/Money"
                }
              },
              "required": [
                "nodes",
                "edges"
              ],
              "x-kytrix-refined": true
            }
          },
          "observed_values": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {}
          },
          "thresholds": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {}
          },
          "ruleset_version_id": {
            "type": "string",
            "pattern": "^rsv_[0-9A-Za-z-]{8,64}$"
          },
          "coverage_stamp": {
            "type": "object",
            "properties": {
              "state": {
                "type": "string",
                "enum": [
                  "complete",
                  "degraded",
                  "unknown"
                ]
              },
              "detail": {
                "type": "string",
                "maxLength": 1000
              }
            },
            "required": [
              "state"
            ]
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "evaluated_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "opened_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "recommended_action": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "review_withdrawal_capability",
                  "review_account",
                  "enhanced_due_diligence",
                  "monitor"
                ]
              },
              "severity": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high",
                  "critical"
                ]
              }
            },
            "required": [
              "code",
              "severity"
            ]
          },
          "classification": {
            "type": "string",
            "const": "restricted_aml"
          }
        },
        "required": [
          "alert_id",
          "tenant_id",
          "subject",
          "entity_refs",
          "detectors",
          "signal_ids",
          "family",
          "typology",
          "severity",
          "confidence",
          "evidence_bundle_hash",
          "movement_refs",
          "control_event_refs",
          "observed_values",
          "thresholds",
          "ruleset_version_id",
          "coverage_stamp",
          "occurred_at",
          "evaluated_at",
          "opened_at",
          "classification"
        ]
      },
      "BatchRequest": {
        "type": "object",
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "party"
                    },
                    "event": {
                      "$ref": "#/components/schemas/PartyEvent"
                    }
                  },
                  "required": [
                    "object",
                    "event"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "account"
                    },
                    "event": {
                      "$ref": "#/components/schemas/AccountEvent"
                    }
                  },
                  "required": [
                    "object",
                    "event"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "instrument"
                    },
                    "event": {
                      "$ref": "#/components/schemas/InstrumentEvent"
                    }
                  },
                  "required": [
                    "object",
                    "event"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "movement"
                    },
                    "event": {
                      "$ref": "#/components/schemas/MovementEvent"
                    }
                  },
                  "required": [
                    "object",
                    "event"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "relationship"
                    },
                    "event": {
                      "$ref": "#/components/schemas/RelationshipEvent"
                    }
                  },
                  "required": [
                    "object",
                    "event"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "control_event"
                    },
                    "event": {
                      "$ref": "#/components/schemas/ControlEventEvent"
                    }
                  },
                  "required": [
                    "object",
                    "event"
                  ],
                  "additionalProperties": false
                }
              ],
              "x-kytrix-discriminator": "object"
            },
            "minItems": 1,
            "maxItems": 1000
          }
        },
        "required": [
          "events"
        ],
        "additionalProperties": false
      },
      "BatchResponse": {
        "type": "object",
        "properties": {
          "accepted": {
            "type": "integer",
            "minimum": 0
          },
          "rejected": {
            "type": "integer",
            "minimum": 0
          },
          "results": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "index": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "outcome": {
                      "type": "string",
                      "const": "accepted"
                    },
                    "receipt": {
                      "$ref": "#/components/schemas/IngestReceipt"
                    }
                  },
                  "required": [
                    "index",
                    "outcome",
                    "receipt"
                  ]
                },
                {
                  "type": "object",
                  "properties": {
                    "index": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "outcome": {
                      "type": "string",
                      "const": "rejected"
                    },
                    "problem": {
                      "$ref": "#/components/schemas/ProblemDetails"
                    }
                  },
                  "required": [
                    "index",
                    "outcome",
                    "problem"
                  ]
                }
              ],
              "x-kytrix-discriminator": "outcome"
            }
          }
        },
        "required": [
          "accepted",
          "rejected",
          "results"
        ]
      },
      "ControlEventEvent": {
        "type": "object",
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "x-kytrix-refined": true
          },
          "schema_version": {
            "type": "string",
            "const": "2026-09-01"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "sequence": {
            "type": "integer",
            "minimum": 0
          },
          "data": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "transfer.failed",
                  "withdrawal.blocked",
                  "velocity_check.failed",
                  "sanctions.hit_reported",
                  "screening.status_changed",
                  "kyc.upgraded",
                  "kyc.downgraded",
                  "kyc.verification_failed",
                  "auth.failed",
                  "auth.suspicious_login",
                  "device.changed",
                  "password.reset",
                  "beneficiary.added",
                  "account.restricted_by_customer",
                  "transfer.retried_repeatedly",
                  "limit.changed"
                ]
              },
              "subject": {
                "$ref": "#/components/schemas/EntityRef"
              },
              "outcome": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "reason_code": {
                "type": "string",
                "minLength": 1,
                "maxLength": 128
              },
              "device_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              },
              "ip": {
                "type": "string",
                "format": "ip"
              },
              "actor_kind": {
                "type": "string",
                "enum": [
                  "customer_system",
                  "end_user"
                ]
              },
              "customer_severity": {
                "type": "string",
                "minLength": 1,
                "maxLength": 32
              },
              "linked_movement_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "external_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              }
            },
            "required": [
              "type",
              "subject"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "external_id",
          "schema_version",
          "occurred_at",
          "data"
        ],
        "additionalProperties": false
      },
      "EntityRef": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "party",
              "account",
              "instrument"
            ]
          },
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "x-kytrix-refined": true
          }
        },
        "required": [
          "kind",
          "external_id"
        ],
        "additionalProperties": false
      },
      "Episode": {
        "type": "object",
        "properties": {
          "episode_id": {
            "type": "string",
            "pattern": "^epsd_[0-9A-Za-z-]{8,64}$"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "key": {
            "type": "object",
            "properties": {
              "subject": {
                "$ref": "#/components/schemas/EntityRef"
              },
              "typology_family": {
                "type": "string",
                "enum": [
                  "AMT",
                  "VEL",
                  "STR",
                  "FAN",
                  "FLW",
                  "NID",
                  "BCH",
                  "CTL"
                ]
              },
              "correlation_group_id": {
                "type": "string",
                "minLength": 1
              }
            },
            "required": [
              "subject",
              "typology_family",
              "correlation_group_id"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "opened",
              "updated",
              "materially_escalated",
              "linked_to_case",
              "resolved",
              "reopened",
              "continuing_activity"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high",
              "critical"
            ]
          },
          "member_signal_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^sig_[0-9A-Za-z-]{8,64}$"
            }
          },
          "alert_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^alrt_[0-9A-Za-z-]{8,64}$"
            }
          },
          "escalation_events": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "trigger": {
                  "type": "string",
                  "enum": [
                    "severity_increase",
                    "participant_threshold",
                    "new_signal_family",
                    "cash_exit",
                    "amount_band_jump"
                  ]
                },
                "at": {
                  "type": "string",
                  "format": "date-time",
                  "x-kytrix-refined": true
                },
                "delta": {
                  "type": "object",
                  "propertyNames": {
                    "type": "string"
                  },
                  "additionalProperties": {}
                }
              },
              "required": [
                "trigger",
                "at",
                "delta"
              ]
            }
          },
          "case_id": {
            "type": "string",
            "pattern": "^case_[0-9A-Za-z-]{8,64}$"
          },
          "continuation_window": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "rolling"
                  },
                  "duration": {
                    "type": "string",
                    "pattern": "^P(?!$)(?:\\d+Y)?(?:\\d+M)?(?:\\d+W)?(?:\\d+D)?(?:T(?=\\d)(?:\\d+H)?(?:\\d+M)?(?:\\d+(?:\\.\\d+)?S)?)?$"
                  }
                },
                "required": [
                  "kind",
                  "duration"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "calendar"
                  },
                  "unit": {
                    "type": "string",
                    "enum": [
                      "day",
                      "month"
                    ]
                  },
                  "tz": {
                    "type": "string",
                    "minLength": 1,
                    "x-kytrix-refined": true
                  }
                },
                "required": [
                  "kind",
                  "unit",
                  "tz"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "business"
                  },
                  "calendar_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 128
                  }
                },
                "required": [
                  "kind",
                  "calendar_id"
                ],
                "additionalProperties": false
              }
            ],
            "x-kytrix-discriminator": "kind"
          },
          "opened_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "last_activity_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "reopened_from": {
            "type": "object",
            "properties": {
              "resolved_at": {
                "type": "string",
                "format": "date-time",
                "x-kytrix-refined": true
              },
              "case_id": {
                "type": "string",
                "pattern": "^case_[0-9A-Za-z-]{8,64}$"
              }
            },
            "required": [
              "resolved_at"
            ]
          },
          "classification": {
            "type": "string",
            "const": "restricted_aml"
          }
        },
        "required": [
          "episode_id",
          "tenant_id",
          "key",
          "state",
          "severity",
          "member_signal_ids",
          "alert_ids",
          "escalation_events",
          "continuation_window",
          "opened_at",
          "last_activity_at",
          "classification"
        ]
      },
      "FieldError": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": [
              "kytrix:validation/schema",
              "kytrix:validation/pan_detected",
              "kytrix:validation/money_scale_mismatch",
              "kytrix:validation/timestamp_out_of_range",
              "kytrix:validation/unsupported_schema_version",
              "kytrix:idempotency/key_conflict",
              "kytrix:idempotency/in_flight",
              "kytrix:auth/invalid_signature",
              "kytrix:auth/timestamp_skew",
              "kytrix:auth/nonce_replayed",
              "kytrix:auth/unknown_key",
              "kytrix:auth/key_revoked",
              "kytrix:auth/key_expired",
              "kytrix:auth/insufficient_scope",
              "kytrix:auth/unauthenticated",
              "kytrix:authz/forbidden",
              "kytrix:reference/unknown_party",
              "kytrix:reference/unknown_account",
              "kytrix:reference/unknown_instrument",
              "kytrix:reference/unknown_movement",
              "kytrix:sequence/conflict",
              "kytrix:sequence/stale",
              "kytrix:rate_limit/exceeded",
              "kytrix:batch/too_large",
              "kytrix:import/invalid_chunk",
              "kytrix:import/not_found",
              "kytrix:governance/approval_required",
              "kytrix:governance/maker_checker_violation",
              "kytrix:governance/immutable",
              "kytrix:governance/invalid_transition",
              "kytrix:tenant/unknown",
              "kytrix:tenant/suspended",
              "kytrix:webhook/invalid_endpoint",
              "kytrix:request/payload_too_large",
              "kytrix:conflict/resource",
              "kytrix:not_found/resource",
              "kytrix:service/unavailable",
              "kytrix:internal/error"
            ]
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "path",
          "code",
          "message"
        ]
      },
      "HealthzResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded"
            ]
          },
          "checks": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": "boolean"
            }
          }
        },
        "required": [
          "status",
          "checks"
        ]
      },
      "IngestReceipt": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "pattern": "^evt_[0-9A-Za-z-]{8,64}$"
          },
          "object": {
            "type": "string",
            "enum": [
              "party",
              "account",
              "instrument",
              "movement",
              "relationship",
              "control_event"
            ]
          },
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "x-kytrix-refined": true
          },
          "received_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "idempotent_replay": {
            "type": "boolean"
          },
          "import_id": {
            "type": "string",
            "pattern": "^imp_[0-9A-Za-z-]{8,64}$"
          }
        },
        "required": [
          "event_id",
          "object",
          "external_id",
          "received_at",
          "idempotent_replay"
        ]
      },
      "InstrumentEvent": {
        "type": "object",
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "x-kytrix-refined": true
          },
          "schema_version": {
            "type": "string",
            "const": "2026-09-01"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "sequence": {
            "type": "integer",
            "minimum": 0
          },
          "data": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "external_bank_account",
                  "card_token",
                  "mobile_wallet",
                  "payment_credential",
                  "virtual_account",
                  "other"
                ]
              },
              "status": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "first_seen_at": {
                "type": "string",
                "format": "date-time",
                "x-kytrix-refined": true
              },
              "issuer_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 128
              },
              "masked_identifier": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64,
                "x-kytrix-refined": true
              },
              "country": {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              "holder_name_as_entered": {
                "type": "string",
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "verification_status": {
                "type": "string",
                "enum": [
                  "verified",
                  "unverified",
                  "pending",
                  "failed"
                ]
              },
              "fingerprint": {
                "type": "string",
                "minLength": 1,
                "maxLength": 128
              },
              "external_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              }
            },
            "required": [
              "type",
              "status",
              "first_seen_at"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "external_id",
          "schema_version",
          "occurred_at",
          "data"
        ],
        "additionalProperties": false
      },
      "Money": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string",
            "pattern": "^-?\\d+$"
          },
          "asset": {
            "type": "string",
            "pattern": "^[A-Z]{3}$|^X-[A-Z0-9]{2,10}$"
          },
          "scale": {
            "type": "integer",
            "minimum": 0,
            "maximum": 18
          }
        },
        "required": [
          "value",
          "asset",
          "scale"
        ]
      },
      "MovementEvent": {
        "type": "object",
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "x-kytrix-refined": true
          },
          "schema_version": {
            "type": "string",
            "const": "2026-09-01"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "sequence": {
            "type": "integer",
            "minimum": 0
          },
          "data": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "p2p",
                  "merchant_payment",
                  "deposit",
                  "withdrawal",
                  "cash_in",
                  "cash_out",
                  "remittance",
                  "ach",
                  "wire",
                  "refund",
                  "reversal",
                  "settlement",
                  "internal_transfer",
                  "other"
                ]
              },
              "status": {
                "type": "string",
                "enum": [
                  "completed",
                  "pending",
                  "failed",
                  "reversed"
                ]
              },
              "amount": {
                "$ref": "#/components/schemas/Money"
              },
              "debit": {
                "type": "object",
                "properties": {
                  "account_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  },
                  "party_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  },
                  "counterparty": {
                    "type": "object",
                    "properties": {
                      "institution": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 128
                      },
                      "country": {
                        "type": "string",
                        "pattern": "^[A-Z]{2}$"
                      },
                      "name_as_given": {
                        "type": "string",
                        "maxLength": 256,
                        "x-kytrix-refined": true
                      },
                      "instrument_ref": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 256
                      }
                    },
                    "additionalProperties": false
                  }
                },
                "additionalProperties": false,
                "x-kytrix-refined": true
              },
              "credit": {
                "type": "object",
                "properties": {
                  "account_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  },
                  "party_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  },
                  "counterparty": {
                    "type": "object",
                    "properties": {
                      "institution": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 128
                      },
                      "country": {
                        "type": "string",
                        "pattern": "^[A-Z]{2}$"
                      },
                      "name_as_given": {
                        "type": "string",
                        "maxLength": 256,
                        "x-kytrix-refined": true
                      },
                      "instrument_ref": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 256
                      }
                    },
                    "additionalProperties": false
                  }
                },
                "additionalProperties": false,
                "x-kytrix-refined": true
              },
              "links": {
                "type": "object",
                "properties": {
                  "reverses": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  },
                  "refunds": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  },
                  "settles": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  },
                  "part_of_batch": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  },
                  "correction_of": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256,
                    "x-kytrix-refined": true
                  }
                },
                "additionalProperties": false
              },
              "cash": {
                "type": "boolean"
              },
              "memo": {
                "type": "string",
                "maxLength": 1000,
                "x-kytrix-refined": true
              },
              "channel": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "rail": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "product": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "agent_party_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "instrument_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "device_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              },
              "ip": {
                "type": "string",
                "format": "ip"
              },
              "geo": {
                "type": "object",
                "properties": {
                  "country": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "region": {
                    "type": "string",
                    "maxLength": 128,
                    "x-kytrix-refined": true
                  },
                  "lat": {
                    "type": "number",
                    "minimum": -90,
                    "maximum": 90
                  },
                  "lon": {
                    "type": "number",
                    "minimum": -180,
                    "maximum": 180
                  }
                },
                "additionalProperties": false
              },
              "fees": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Money"
                },
                "maxItems": 20
              },
              "external_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              },
              "correction_reason": {
                "type": "string",
                "maxLength": 256,
                "x-kytrix-refined": true
              }
            },
            "required": [
              "type",
              "status",
              "amount",
              "debit",
              "credit"
            ],
            "additionalProperties": false,
            "x-kytrix-refined": true
          }
        },
        "required": [
          "external_id",
          "schema_version",
          "occurred_at",
          "data"
        ],
        "additionalProperties": false
      },
      "PartyEvent": {
        "type": "object",
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "x-kytrix-refined": true
          },
          "schema_version": {
            "type": "string",
            "const": "2026-09-01"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "sequence": {
            "type": "integer",
            "minimum": 0
          },
          "data": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "person",
                  "business",
                  "merchant",
                  "agent",
                  "financial_institution",
                  "internal",
                  "government",
                  "ngo",
                  "trust",
                  "other"
                ]
              },
              "status": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              "created_at": {
                "type": "string",
                "format": "date-time",
                "x-kytrix-refined": true
              },
              "legal_names": {
                "type": "array",
                "items": {
                  "type": "string",
                  "maxLength": 256,
                  "x-kytrix-refined": true
                },
                "maxItems": 20
              },
              "birth_or_inc_date": {
                "type": "string",
                "format": "date"
              },
              "identifiers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "enum": [
                        "national_id",
                        "tax_id",
                        "passport",
                        "phone",
                        "email",
                        "other"
                      ]
                    },
                    "value": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 256
                    },
                    "verification_status": {
                      "type": "string",
                      "enum": [
                        "verified",
                        "unverified",
                        "pending",
                        "failed"
                      ]
                    }
                  },
                  "required": [
                    "type",
                    "value"
                  ],
                  "additionalProperties": false
                },
                "maxItems": 50
              },
              "jurisdictions": {
                "type": "object",
                "properties": {
                  "nationality": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "residency": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "registration": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  }
                },
                "additionalProperties": false
              },
              "addresses": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "line1": {
                      "type": "string",
                      "maxLength": 256,
                      "x-kytrix-refined": true
                    },
                    "line2": {
                      "type": "string",
                      "maxLength": 256,
                      "x-kytrix-refined": true
                    },
                    "city": {
                      "type": "string",
                      "maxLength": 128,
                      "x-kytrix-refined": true
                    },
                    "region": {
                      "type": "string",
                      "maxLength": 128,
                      "x-kytrix-refined": true
                    },
                    "postal_code": {
                      "type": "string",
                      "maxLength": 32
                    },
                    "country": {
                      "type": "string",
                      "pattern": "^[A-Z]{2}$"
                    }
                  },
                  "additionalProperties": false
                },
                "maxItems": 20
              },
              "occupation": {
                "type": "string",
                "maxLength": 256,
                "x-kytrix-refined": true
              },
              "industry_code": {
                "type": "string",
                "maxLength": 32
              },
              "expected_profile": {
                "type": "object",
                "properties": {
                  "declared_monthly_volume": {
                    "$ref": "#/components/schemas/Money"
                  },
                  "corridors": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^[A-Z]{2}$"
                    },
                    "maxItems": 50
                  },
                  "cash_intensity": {
                    "type": "string",
                    "enum": [
                      "low",
                      "medium",
                      "high"
                    ]
                  }
                },
                "additionalProperties": false
              },
              "kyc": {
                "type": "object",
                "properties": {
                  "tier": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  },
                  "updated_at": {
                    "type": "string",
                    "format": "date-time",
                    "x-kytrix-refined": true
                  }
                },
                "additionalProperties": false
              },
              "screening_status_reported": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "clear",
                      "potential_match",
                      "confirmed_match",
                      "pending",
                      "unknown"
                    ]
                  },
                  "pep": {
                    "type": "boolean"
                  },
                  "as_of": {
                    "type": "string",
                    "format": "date-time",
                    "x-kytrix-refined": true
                  },
                  "provider": {
                    "type": "string",
                    "maxLength": 128
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              },
              "segment": {
                "type": "string",
                "enum": [
                  "consumer",
                  "merchant",
                  "remittance_agent",
                  "cash_agent",
                  "payroll",
                  "marketplace",
                  "financial_institution",
                  "other"
                ]
              },
              "external_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              },
              "correction_reason": {
                "type": "string",
                "maxLength": 256,
                "x-kytrix-refined": true
              }
            },
            "required": [
              "type",
              "status",
              "created_at"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "external_id",
          "schema_version",
          "occurred_at",
          "data"
        ],
        "additionalProperties": false
      },
      "PostureResponse": {
        "type": "object",
        "properties": {
          "subject": {
            "$ref": "#/components/schemas/EntityRef"
          },
          "risk_state": {
            "type": "string",
            "enum": [
              "clear",
              "watch",
              "elevated",
              "critical",
              "unknown",
              "incomplete"
            ]
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "freshness_seconds": {
            "type": "integer",
            "minimum": 0
          },
          "coverage_state": {
            "type": "string",
            "enum": [
              "complete",
              "degraded",
              "unknown"
            ]
          }
        },
        "required": [
          "subject",
          "risk_state",
          "as_of",
          "freshness_seconds",
          "coverage_state"
        ],
        "additionalProperties": false
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": [
              "kytrix:validation/schema",
              "kytrix:validation/pan_detected",
              "kytrix:validation/money_scale_mismatch",
              "kytrix:validation/timestamp_out_of_range",
              "kytrix:validation/unsupported_schema_version",
              "kytrix:idempotency/key_conflict",
              "kytrix:idempotency/in_flight",
              "kytrix:auth/invalid_signature",
              "kytrix:auth/timestamp_skew",
              "kytrix:auth/nonce_replayed",
              "kytrix:auth/unknown_key",
              "kytrix:auth/key_revoked",
              "kytrix:auth/key_expired",
              "kytrix:auth/insufficient_scope",
              "kytrix:auth/unauthenticated",
              "kytrix:authz/forbidden",
              "kytrix:reference/unknown_party",
              "kytrix:reference/unknown_account",
              "kytrix:reference/unknown_instrument",
              "kytrix:reference/unknown_movement",
              "kytrix:sequence/conflict",
              "kytrix:sequence/stale",
              "kytrix:rate_limit/exceeded",
              "kytrix:batch/too_large",
              "kytrix:import/invalid_chunk",
              "kytrix:import/not_found",
              "kytrix:governance/approval_required",
              "kytrix:governance/maker_checker_violation",
              "kytrix:governance/immutable",
              "kytrix:governance/invalid_transition",
              "kytrix:tenant/unknown",
              "kytrix:tenant/suspended",
              "kytrix:webhook/invalid_endpoint",
              "kytrix:request/payload_too_large",
              "kytrix:conflict/resource",
              "kytrix:not_found/resource",
              "kytrix:service/unavailable",
              "kytrix:internal/error"
            ]
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldError"
            }
          },
          "correlation_id": {
            "type": "string"
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "additionalProperties": true
      },
      "RelationshipEvent": {
        "type": "object",
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "x-kytrix-refined": true
          },
          "schema_version": {
            "type": "string",
            "const": "2026-09-01"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "sequence": {
            "type": "integer",
            "minimum": 0
          },
          "data": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "beneficial_owner",
                  "authorized_signer",
                  "joint_holder",
                  "employer",
                  "household_member",
                  "parent_org",
                  "merchant_owner",
                  "agent",
                  "referral",
                  "onboarding",
                  "owns_instrument",
                  "funds_account",
                  "same_as",
                  "other"
                ]
              },
              "from": {
                "$ref": "#/components/schemas/EntityRef"
              },
              "to": {
                "$ref": "#/components/schemas/EntityRef"
              },
              "valid_from": {
                "type": "string",
                "format": "date-time",
                "x-kytrix-refined": true
              },
              "valid_to": {
                "type": "string",
                "format": "date-time",
                "x-kytrix-refined": true
              },
              "ownership_pct": {
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              "source": {
                "type": "string",
                "enum": [
                  "kyc",
                  "declared",
                  "derived_by_customer"
                ]
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "external_ref": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              },
              "correction_reason": {
                "type": "string",
                "maxLength": 256,
                "x-kytrix-refined": true
              }
            },
            "required": [
              "type",
              "from",
              "to",
              "valid_from"
            ],
            "additionalProperties": false,
            "x-kytrix-refined": true
          }
        },
        "required": [
          "external_id",
          "schema_version",
          "occurred_at",
          "data"
        ],
        "additionalProperties": false
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "endpoint_id": {
            "type": "string",
            "pattern": "^whk_[0-9A-Za-z-]{8,64}$"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://"
          },
          "channel": {
            "type": "string",
            "enum": [
              "compliance",
              "operational"
            ]
          },
          "event_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "alert.opened",
                "episode.updated",
                "episode.escalated",
                "episode.resolved",
                "episode.reopened",
                "case.status_changed",
                "case.disposed",
                "risk_state.changed",
                "recommendation.issued",
                "coverage.degraded",
                "coverage.recovered",
                "import.progress",
                "import.completed",
                "import.failed",
                "ruleset.candidate_ready",
                "ruleset.activated",
                "ruleset.rolled_back",
                "conformance.drift_detected",
                "webhook.test"
              ]
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          }
        },
        "required": [
          "endpoint_id",
          "tenant_id",
          "url",
          "channel",
          "event_types",
          "status",
          "created_at"
        ]
      },
      "WebhookEnvelope": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^whe_[0-9A-Za-z-]{8,64}$"
          },
          "type": {
            "type": "string",
            "enum": [
              "alert.opened",
              "episode.updated",
              "episode.escalated",
              "episode.resolved",
              "episode.reopened",
              "case.status_changed",
              "case.disposed",
              "risk_state.changed",
              "recommendation.issued",
              "coverage.degraded",
              "coverage.recovered",
              "import.progress",
              "import.completed",
              "import.failed",
              "ruleset.candidate_ready",
              "ruleset.activated",
              "ruleset.rolled_back",
              "conformance.drift_detected",
              "webhook.test"
            ]
          },
          "classification": {
            "type": "string",
            "enum": [
              "restricted_aml",
              "advisory",
              "operational"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "x-kytrix-refined": true
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "data": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {}
          },
          "delivery": {
            "type": "object",
            "properties": {
              "attempt": {
                "type": "integer",
                "minimum": 1
              },
              "delivery_id": {
                "type": "string",
                "pattern": "^whd_[0-9A-Za-z-]{8,64}$"
              }
            },
            "required": [
              "attempt",
              "delivery_id"
            ]
          }
        },
        "required": [
          "id",
          "type",
          "classification",
          "created_at",
          "tenant_id",
          "data"
        ],
        "x-kytrix-refined": true
      }
    }
  }
}
