{
  "openapi": "3.1.1",
  "info": {
    "title": "FIClynx API",
    "description": "FICA / KYC verification. Authenticate with an organisation API key in the X-Api-Key header. Every key belongs to a member of the organisation and acts as them: cases, decisions, notes, re-checks and client links made through the API are recorded as that person with the key as the channel (e.g. \"Thandi Mokoena via API key flx_ab12cd34…\") in the audit trail, decision records and audit pack. A key's effective permissions are the intersection of its role (Operator or ComplianceOfficer) and its owner's current role, evaluated on every request, so a key never does more than its user; four-eyes applies per person across the dashboard and API. If the owner is disabled or leaves the organisation the key is suspended (401, code api_key_suspended) until an Owner reassigns it. GET /api/v1/me shows the key's user and effective permissions.",
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://ficlynx.co.za/"
    }
  ],
  "paths": {
    "/api/v1/billing/balance": {
      "get": {
        "tags": [
          "BillingApi"
        ],
        "summary": "The organisation's balance.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BillingBalanceDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingBalanceDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingBalanceDto"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/ledger": {
      "get": {
        "tags": [
          "BillingApi"
        ],
        "summary": "The ledger, newest first.",
        "parameters": [
          {
            "name": "kind",
            "in": "query",
            "description": "all, credits, charges or holds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "month",
            "in": "query",
            "description": "A month, yyyy-MM (SAST).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "caseReference",
            "in": "query",
            "description": "Only entries of this case (FLX-…).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "1-based page.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "1 to 200.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfLedgerEntryDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfLedgerEntryDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfLedgerEntryDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/usage": {
      "get": {
        "tags": [
          "BillingApi"
        ],
        "summary": "Monthly usage: charges per check with case references (no personal information), credits and balances.",
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "description": "yyyy-MM (SAST); default the current month.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UsageDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/subjects/{idNumber}/enrolment": {
      "get": {
        "tags": [
          "BiometricsApi"
        ],
        "summary": "The subject's enrolment in this organisation (active first, else pending, else the latest).",
        "parameters": [
          {
            "name": "idNumber",
            "in": "path",
            "description": "SA ID number.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/EnrolmentDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrolmentDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrolmentDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "BiometricsApi"
        ],
        "summary": "Deletes the subject's stored biometrics in this organisation (every enrolment and template) and\r\nwithdraws their biometric consent, e.g. on the client's request or at the end of the relationship.",
        "parameters": [
          {
            "name": "idNumber",
            "in": "path",
            "description": "SA ID number.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/enrolment": {
      "post": {
        "tags": [
          "BiometricsApi"
        ],
        "summary": "Enrols the case's client for future re-verification from the templates held after a\r\nDHA-verified check (requires the client's biometric consent on that case).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/EnrolmentDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrolmentDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrolmentDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases": {
      "post": {
        "tags": [
          "CasesApi"
        ],
        "summary": "    Creates a case and runs its checks; returns the case. Checks a provider answers asynchronously\r\n    (bank account verification) come back with status AwaitingProvider and a `pending` ETA, and\r\n    the case with status AwaitingProvider: poll `GET /api/v1/cases/{id}` until it is final. With an\r\n    `invitation` (channel, destination, expiresInHours) the case is instead sent to the\r\n    client: identity and face match are added, every check waits until the client finishes on\r\n    their phone, and the response (status AwaitingClient) includes the invitation.\r\n    Send an Idempotency-Key header (1 to 255 printable ASCII characters, e.g. a UUID) to\r\nretry safely: a repeat with the same key and body within 24 hours creates nothing and runs or\r\nbills nothing again; it answers 201 with the same case in its current state and the header\r\nIdempotent-Replayed: true. The same key with a different body is 409. A request that is\r\nrejected with 400 does not use up its key.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional. 1 to 255 printable ASCII characters (e.g. a UUID), unique per request, remembered for 24 hours per organisation. A repeat with the same key and body creates, runs, sends and bills nothing again and answers with the first request's resource in its current state (header Idempotent-Replayed: true). The same key with a different body is 409 Conflict. A malformed key, or a request rejected with 400, does not use up the key. Concurrent duplicates: exactly one creates the resource; the others wait for it to be saved and replay it.",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Subject details and the checks to run.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewCaseRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/NewCaseRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/NewCaseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "headers": {
              "Idempotent-Replayed": {
                "description": "true when this response replays an earlier request with the same Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance: the organisation's prepaid credit does not cover the checks. Nothing was created or charged. The problem (application/problem+json, code insufficient_balance) has required, available and topUpUrl. Each check reserves its price when the case is created and is charged only when it returns a result (GET /api/v1/billing/balance)."
          }
        }
      },
      "get": {
        "tags": [
          "CasesApi"
        ],
        "summary": "Lists the organisation's cases, newest first.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Only this status.",
            "schema": {
              "$ref": "#/components/schemas/CaseStatus"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Search reference, your reference, name, ID or registration number.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "1-based page.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Page size, 1 to 100.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 25
            }
          },
          {
            "name": "due",
            "in": "query",
            "description": "Ongoing monitoring: only approved cases whose next review date has passed and that have not been re-checked, most overdue first.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfCaseSummaryDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfCaseSummaryDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfCaseSummaryDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}": {
      "get": {
        "tags": [
          "CasesApi"
        ],
        "summary": "Gets one case of the key's organisation.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/decision": {
      "post": {
        "tags": [
          "CaseWorkflowApi"
        ],
        "summary": "Records a sign-off decision: Approve, Decline or MoreInformation, with a risk rating (Low, Standard, High).\r\nA `reason` is required to decline, to ask for more information and to approve despite a Review, Failed\r\nor Incomplete system verdict (an override); a `riskReason` when the rating differs from the suggested one\r\n(`GET …/decisions`). Decisions are never edited: a new decision is a new record that supersedes the\r\nprevious one. With the organisation's four-eyes setting, a High risk approval is `AwaitingSecondApproval`\r\nuntil a different Owner or Compliance Officer approves it at High risk too. An approval in force sets\r\n`nextReviewAt` from the rating; the same person cannot give both approvals, whether in the dashboard or\r\nthrough API keys that act as them. The decision is recorded as the key's owner \"via API key\" (`decidedBy`,\r\n`channel`, `apiKeyPrefix`). Needs an API key with the Compliance Officer role whose owner may sign off\r\n(403 otherwise); 409 while checks are still running. Honours `Idempotency-Key`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional. 1 to 255 printable ASCII characters (e.g. a UUID), unique per request, remembered for 24 hours per organisation. A repeat with the same key and body creates, runs, sends and bills nothing again and answers with the first request's resource in its current state (header Idempotent-Replayed: true). The same key with a different body is 409 Conflict. A malformed key, or a request rejected with 400, does not use up the key. Concurrent duplicates: exactly one creates the resource; the others wait for it to be saved and replay it.",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Cancellation.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Idempotent-Replayed": {
                "description": "true when this response replays an earlier request with the same Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/decisions": {
      "get": {
        "tags": [
          "CaseWorkflowApi"
        ],
        "summary": "The decision in force, the suggested risk rating and every decision record, oldest first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDecisionsDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDecisionsDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDecisionsDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/notes": {
      "post": {
        "tags": [
          "CaseWorkflowApi"
        ],
        "summary": "Adds an internal note to the case (append-only; never shown to the client). Honours `Idempotency-Key`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional. 1 to 255 printable ASCII characters (e.g. a UUID), unique per request, remembered for 24 hours per organisation. A repeat with the same key and body creates, runs, sends and bills nothing again and answers with the first request's resource in its current state (header Idempotent-Replayed: true). The same key with a different body is 409 Conflict. A malformed key, or a request rejected with 400, does not use up the key. Concurrent duplicates: exactly one creates the resource; the others wait for it to be saved and replay it.",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Cancellation.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NoteRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/NoteRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/NoteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Idempotent-Replayed": {
                "description": "true when this response replays an earlier request with the same Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "CaseWorkflowApi"
        ],
        "summary": "The case's internal notes, oldest first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NoteDto"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NoteDto"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NoteDto"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/audit-pack": {
      "get": {
        "tags": [
          "CaseWorkflowApi"
        ],
        "summary": "The case's audit pack for an FIC inspection (PDF): subject, checks and findings, sources and timings,\r\nconsent records, client-link events, decision history, risk rating, notes, access log, retention date\r\nand an integrity reference. Identifiers are masked; `identifiers=full` prints them in full for\r\nCompliance Officer keys. Every download is audited (headers `X-Audit-Pack-Reference` and\r\n`X-Audit-Pack-Sha256` carry the reference and the file hash).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "identifiers",
            "in": "query",
            "description": "`masked` (default) or `full`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "$ref": "#/components/schemas/FileContentResult"
                }
              },
              "application/problem+json": { }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/pdf": { }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/pdf": { }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/recheck": {
      "post": {
        "tags": [
          "CaseWorkflowApi"
        ],
        "summary": "\"Re-check now\": creates a new case for the same subject, linked to this one, and runs the checks that can run\r\nagain from what the case stores (identity, PEP and sanctions, CIPC, B-BBEE, address by ID). It is a new case\r\nand is billed like one. Bank, face and fingerprint checks need fresh details (send the client a link from the\r\nnew case). A case can be re-checked once (409 afterwards: re-check the newest case). Honours `Idempotency-Key`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional. 1 to 255 printable ASCII characters (e.g. a UUID), unique per request, remembered for 24 hours per organisation. A repeat with the same key and body creates, runs, sends and bills nothing again and answers with the first request's resource in its current state (header Idempotent-Replayed: true). The same key with a different body is 409 Conflict. A malformed key, or a request rejected with 400, does not use up the key. Concurrent duplicates: exactly one creates the resource; the others wait for it to be saved and replay it.",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "responses": {
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "headers": {
              "Idempotent-Replayed": {
                "description": "true when this response replays an earlier request with the same Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance: the organisation's prepaid credit does not cover the checks. Nothing was created or charged. The problem (application/problem+json, code insufficient_balance) has required, available and topUpUrl. Each check reserves its price when the case is created and is charged only when it returns a result (GET /api/v1/billing/balance)."
          }
        }
      }
    },
    "/api/v1/checks/types": {
      "get": {
        "tags": [
          "ChecksApi"
        ],
        "summary": "Every check type with the subject kinds it applies to and the fields it needs.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CheckTypeInfo"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CheckTypeInfo"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CheckTypeInfo"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "tags": [
          "HealthApi"
        ],
        "summary": "Database reachability and the source chain (neutral names).",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/HealthDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthDto"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/HealthDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthDto"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/invitations": {
      "post": {
        "tags": [
          "InvitationsApi"
        ],
        "summary": "Sends the case's subject a verification link (SMS, WhatsApp or email). Identity and face match\r\nare added as pending checks if the case lacks them; they run when the client finishes. With an\r\n`Idempotency-Key` header a repeat sends nothing again and answers 201 with the same\r\ninvitation (see `POST /api/v1/cases`).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional. 1 to 255 printable ASCII characters (e.g. a UUID), unique per request, remembered for 24 hours per organisation. A repeat with the same key and body creates, runs, sends and bills nothing again and answers with the first request's resource in its current state (header Idempotent-Replayed: true). The same key with a different body is 409 Conflict. A malformed key, or a request rejected with 400, does not use up the key. Concurrent duplicates: exactly one creates the resource; the others wait for it to be saved and replay it.",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Cancellation.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientInvitationRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientInvitationRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ClientInvitationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "headers": {
              "Idempotent-Replayed": {
                "description": "true when this response replays an earlier request with the same Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance: the organisation's prepaid credit does not cover the checks. Nothing was created or charged. The problem (application/problem+json, code insufficient_balance) has required, available and topUpUrl. Each check reserves its price when the case is created and is charged only when it returns a result (GET /api/v1/billing/balance)."
          }
        }
      },
      "get": {
        "tags": [
          "InvitationsApi"
        ],
        "summary": "The case's invitations, newest first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InvitationDto"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InvitationDto"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InvitationDto"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/invitations/{invitationId}/resend": {
      "post": {
        "tags": [
          "InvitationsApi"
        ],
        "summary": "Re-sends the link with a fresh token (the old link stops working) and a new expiry. With an\r\n`Idempotency-Key` header a repeat sends nothing again and answers 200 with the invitation.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "invitationId",
            "in": "path",
            "description": "Invitation id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional. 1 to 255 printable ASCII characters (e.g. a UUID), unique per request, remembered for 24 hours per organisation. A repeat with the same key and body creates, runs, sends and bills nothing again and answers with the first request's resource in its current state (header Idempotent-Replayed: true). The same key with a different body is 409 Conflict. A malformed key, or a request rejected with 400, does not use up the key. Concurrent duplicates: exactly one creates the resource; the others wait for it to be saved and replay it.",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "responses": {
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "headers": {
              "Idempotent-Replayed": {
                "description": "true when this response replays an earlier request with the same Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cases/{id}/invitations/{invitationId}/revoke": {
      "post": {
        "tags": [
          "InvitationsApi"
        ],
        "summary": "Revokes the link.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Case id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "invitationId",
            "in": "path",
            "description": "Invitation id.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/me": {
      "get": {
        "tags": [
          "MeApi"
        ],
        "summary": "The calling key, the user it belongs to and acts as, and its effective permissions now. Every key belongs to a\r\nmember of its organisation: what it does (cases, decisions, notes, re-checks, client links) is recorded as that\r\nperson with the key as the channel, e.g. `\"Thandi Mokoena via API key flx_ab12cd34…\"`, in the audit trail,\r\ndecision records and audit pack. The key's effective role is the lower of its own role (Operator or\r\nComplianceOfficer) and the owner's current role, worked out on every request: a key never does more than its\r\nuser. If the owner is disabled or leaves the organisation, every request (this one included) gets 401 with\r\n`code: \"api_key_suspended\"` until an Owner reassigns the key in Settings, API keys.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/MeDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/event-types": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "The event types you can subscribe to.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEventTypeDto"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEventTypeDto"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEventTypeDto"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "The organisation's endpoints.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEndpointDto"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEndpointDto"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEndpointDto"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Creates an endpoint. The response carries the signing secret once; store it safely.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "One endpoint.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Changes an endpoint's URL, events, label or enabled flag.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Deletes an endpoint and its delivery log.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/rotate-secret": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Issues a new signing secret (returned once). The previous secret also signs for 24 hours, so you can switch over.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Sends a `ping` test event to the endpoint.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/deliveries": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "The endpoint's recent deliveries (newest first) with every attempt and its response code.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDeliveryDto"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDeliveryDto"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDeliveryDto"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/deliveries/{deliveryId}/redeliver": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Sends a delivery again (same event id and payload, fresh signature).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryDto"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryDto"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ActionChannel": {
        "type": "integer",
        "description": "How a person acted: in the dashboard, or through an API key that acts as them."
      },
      "ApiKeyPermissions": {
        "required": [
          "readCases",
          "runChecks",
          "addNotes",
          "recordDecisions",
          "fullIdentifiers"
        ],
        "type": "object",
        "properties": {
          "readCases": {
            "type": "boolean",
            "description": "Read cases, checks, decisions, notes and audit packs (masked identifiers)."
          },
          "runChecks": {
            "type": "boolean",
            "description": "Create cases, send client links, re-check and manage biometric enrolments."
          },
          "addNotes": {
            "type": "boolean",
            "description": "Add internal case notes."
          },
          "recordDecisions": {
            "type": "boolean",
            "description": "Record sign-off decisions."
          },
          "fullIdentifiers": {
            "type": "boolean",
            "description": "Download audit packs with full ID numbers."
          }
        },
        "description": "What an API key may do now (the intersection of its scope and its owner's role)."
      },
      "AttemptDto": {
        "required": [
          "sequence",
          "source",
          "sourceName",
          "startedAt",
          "finishedAt",
          "latencyMs",
          "outcome",
          "errorKind",
          "errorMessage",
          "providerReference",
          "fellBack",
          "skipped"
        ],
        "type": "object",
        "properties": {
          "sequence": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Position in the chain.",
            "format": "int32"
          },
          "source": {
            "type": "string",
            "description": "The source: `primary`, `backup` or `local`."
          },
          "sourceName": {
            "type": "string",
            "description": "Its neutral name, e.g. \"Backup source (sandbox)\"."
          },
          "startedAt": {
            "type": "string",
            "description": "Started.",
            "format": "date-time"
          },
          "finishedAt": {
            "type": "string",
            "description": "Finished.",
            "format": "date-time"
          },
          "latencyMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Latency.",
            "format": "int64"
          },
          "outcome": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Verdict when answered.",
                "$ref": "#/components/schemas/CheckOutcome"
              }
            ]
          },
          "errorKind": {
            "description": "Error class.",
            "$ref": "#/components/schemas/ProviderErrorKind"
          },
          "errorMessage": {
            "type": [
              "null",
              "string"
            ],
            "description": "Error detail (source names neutral)."
          },
          "providerReference": {
            "type": [
              "null",
              "string"
            ],
            "description": "The source's transaction reference."
          },
          "fellBack": {
            "type": "boolean",
            "description": "The next source was tried after this one."
          },
          "skipped": {
            "type": "boolean",
            "description": "Not called: the source does not offer the check."
          },
          "pending": {
            "type": "boolean",
            "description": "The source accepted the check and answers asynchronously (a later attempt records the answer).",
            "default": false
          },
          "local": {
            "type": "boolean",
            "description": "True for an unbilled \"FIClynx Local\" biometric match (docs/biometrics.md), not a provider call."
          }
        },
        "description": "One source attempt (raw responses and supplier names are not exposed over the API)."
      },
      "BillingBalanceDto": {
        "required": [
          "currency",
          "balance",
          "held",
          "available",
          "creditLimit",
          "lowBalanceThreshold",
          "isLow",
          "spentThisMonth",
          "plan",
          "discountPercent",
          "prices",
          "topUpUrl"
        ],
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "description": "Always ZAR."
          },
          "balance": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Credit bought and granted minus charges.",
            "format": "double"
          },
          "held": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Reserved for checks still running or waiting (charged only if they return a result).",
            "format": "double"
          },
          "available": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Balance − held: what new checks can use.",
            "format": "double"
          },
          "creditLimit": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "How far below zero the available balance may go (0 for prepaid).",
            "format": "double"
          },
          "lowBalanceThreshold": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "The organisation's alert threshold.",
            "format": "double"
          },
          "isLow": {
            "type": "boolean",
            "description": "Available is below the threshold."
          },
          "spentThisMonth": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Charges this calendar month (SAST), net of refunds.",
            "format": "double"
          },
          "plan": {
            "description": "Starter, Practice or Enterprise.",
            "$ref": "#/components/schemas/BillingPlan"
          },
          "discountPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Discount on list prices.",
            "format": "double"
          },
          "prices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillingPriceDto"
            },
            "description": "This organisation's price per check."
          },
          "topUpUrl": {
            "type": "string",
            "description": "Where an Owner tops up."
          }
        },
        "description": "`GET /api/v1/billing/balance`. Rand, excluding VAT."
      },
      "BillingPlan": {
        "type": "integer",
        "description": "An organisation's plan. It only sets the per-check discount today; monthly bundles (included credit) can be\r\nadded later without changing the ledger (a bundle is a LedgerEntryKind.Promotional grant)."
      },
      "BillingPriceDto": {
        "required": [
          "check",
          "price"
        ],
        "type": "object",
        "properties": {
          "check": {
            "description": "Check type.",
            "$ref": "#/components/schemas/CheckType"
          },
          "price": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Rand, excluding VAT.",
            "format": "double"
          }
        },
        "description": "A price."
      },
      "BiometricEnrolmentStatus": {
        "type": "integer",
        "description": "Lifecycle of a BiometricEnrolment."
      },
      "BiometricModality": {
        "type": "integer",
        "description": "A kind of biometric template."
      },
      "CaseDecisionsDto": {
        "required": [
          "decision",
          "riskRating",
          "nextReviewAt",
          "suggestedRiskRating",
          "suggestedRiskReasons",
          "requiresSecondApprovalForEdd",
          "items"
        ],
        "type": "object",
        "properties": {
          "decision": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The state in force, null until decided.",
                "$ref": "#/components/schemas/CaseDecisionState"
              }
            ]
          },
          "riskRating": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Latest risk rating.",
                "$ref": "#/components/schemas/RiskRating"
              }
            ]
          },
          "nextReviewAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Next review date (UTC).",
            "format": "date-time"
          },
          "suggestedRiskRating": {
            "description": "The rating suggested from the current findings.",
            "$ref": "#/components/schemas/RiskRating"
          },
          "suggestedRiskReasons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why."
          },
          "requiresSecondApprovalForEdd": {
            "type": "boolean",
            "description": "The organisation's four-eyes setting for High risk approvals."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DecisionDto"
            },
            "description": "Every record, oldest first."
          }
        },
        "description": "`GET /api/v1/cases/{id}/decisions`: the decision in force and the full history."
      },
      "CaseDecisionState": {
        "type": "integer"
      },
      "CaseDto": {
        "required": [
          "id",
          "reference",
          "externalReference",
          "status",
          "subject",
          "source",
          "createdAt",
          "completedAt",
          "checks"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Case id.",
            "format": "uuid"
          },
          "reference": {
            "type": "string",
            "description": "FIClynx reference, e.g. FLX-7K2M9Q."
          },
          "externalReference": {
            "type": [
              "null",
              "string"
            ],
            "description": "Your reference."
          },
          "status": {
            "description": "Rolled-up status.",
            "$ref": "#/components/schemas/CaseStatus"
          },
          "subject": {
            "description": "The subject (ID numbers masked).",
            "$ref": "#/components/schemas/SubjectDto"
          },
          "source": {
            "description": "Dashboard or Api.",
            "$ref": "#/components/schemas/CaseSource"
          },
          "createdAt": {
            "type": "string",
            "description": "Created (UTC).",
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Completed (UTC).",
            "format": "date-time"
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckDto"
            },
            "description": "The checks with findings and the provider audit trail."
          },
          "decision": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The sign-off in force (null until decided): Approved, Declined, MoreInformation or AwaitingSecondApproval. History: `GET /api/v1/cases/{id}/decisions`.",
                "$ref": "#/components/schemas/CaseDecisionState"
              }
            ]
          },
          "riskRating": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Risk rating of the latest decision: Low, Standard or High (enhanced due diligence).",
                "$ref": "#/components/schemas/RiskRating"
              }
            ]
          },
          "decidedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the latest decision was made (UTC).",
            "format": "date-time"
          },
          "nextReviewAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the approved client is due for review (UTC); list the due ones with `GET /api/v1/cases?due=true`.",
            "format": "date-time"
          },
          "recheckOfCaseId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The case this one re-checks (\"Re-check now\"), if any.",
            "format": "uuid"
          },
          "invitations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvitationDto"
            },
            "description": "Client verification links for the case, newest first (empty when none were sent)."
          },
          "enrolment": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Re-verification with stored biometrics for this case's subject (null for entities); see docs/biometrics.md.",
                "$ref": "#/components/schemas/CaseEnrolmentDto"
              }
            ]
          }
        },
        "description": "A case as returned by `/api/v1/cases`."
      },
      "CaseEnrolmentDto": {
        "required": [
          "reverificationEnabled",
          "consentGiven",
          "canEnrol",
          "blockers",
          "subject",
          "localMatches"
        ],
        "type": "object",
        "properties": {
          "reverificationEnabled": {
            "type": "boolean",
            "description": "The organisation has re-verification on."
          },
          "consentGiven": {
            "type": "boolean",
            "description": "The client gave the separate biometric consent for this case (and it is not withdrawn)."
          },
          "canEnrol": {
            "type": "boolean",
            "description": "Templates are held from this case and `POST /api/v1/cases/{id}/enrolment` would enrol the client."
          },
          "blockers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why the client cannot be enrolled from this case."
          },
          "subject": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The subject's current enrolment in this organisation, if any.",
                "$ref": "#/components/schemas/EnrolmentDto"
              }
            ]
          },
          "localMatches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocalMatchDto"
            },
            "description": "Local match attempts in this case: modality, matched, score and threshold."
          }
        },
        "description": "Enrolment state on a case response."
      },
      "CaseSource": {
        "type": "integer",
        "description": "Where a case was created."
      },
      "CaseStatus": {
        "type": "integer",
        "description": "Lifecycle and rolled-up verdict of a case."
      },
      "CaseSummaryDto": {
        "required": [
          "id",
          "reference",
          "externalReference",
          "status",
          "subjectKind",
          "subjectName",
          "checks",
          "createdAt",
          "completedAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Case id.",
            "format": "uuid"
          },
          "reference": {
            "type": "string",
            "description": "FIClynx reference."
          },
          "externalReference": {
            "type": [
              "null",
              "string"
            ],
            "description": "Your reference."
          },
          "status": {
            "description": "Status.",
            "$ref": "#/components/schemas/CaseStatus"
          },
          "subjectKind": {
            "description": "Person or Entity.",
            "$ref": "#/components/schemas/SubjectKind"
          },
          "subjectName": {
            "type": "string",
            "description": "Name."
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckType"
            },
            "description": "Check types."
          },
          "createdAt": {
            "type": "string",
            "description": "Created.",
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Completed.",
            "format": "date-time"
          },
          "decision": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The sign-off in force, null until decided.",
                "$ref": "#/components/schemas/CaseDecisionState"
              }
            ]
          },
          "riskRating": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Risk rating of the latest decision.",
                "$ref": "#/components/schemas/RiskRating"
              }
            ]
          },
          "nextReviewAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the approved client is due for review (UTC).",
            "format": "date-time"
          }
        },
        "description": "A row in `GET /api/v1/cases`."
      },
      "CheckDto": {
        "required": [
          "id",
          "type",
          "status",
          "outcome",
          "summary",
          "answeredBy",
          "usedFallback",
          "findings",
          "attempts"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Check id.",
            "format": "uuid"
          },
          "type": {
            "description": "Check type.",
            "$ref": "#/components/schemas/CheckType"
          },
          "status": {
            "description": "Lifecycle state.",
            "$ref": "#/components/schemas/CheckStatus"
          },
          "outcome": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Verdict.",
                "$ref": "#/components/schemas/CheckOutcome"
              }
            ]
          },
          "summary": {
            "type": [
              "null",
              "string"
            ],
            "description": "Explanation, mainly for errors."
          },
          "answeredBy": {
            "type": [
              "null",
              "string"
            ],
            "description": "The source that answered, by its neutral name, e.g. \"Primary source\" or \"Backup source (sandbox)\"."
          },
          "usedFallback": {
            "type": "boolean",
            "description": "True when the backup source answered after the primary did not."
          },
          "findings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckFinding"
            },
            "description": "Facts produced."
          },
          "attempts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AttemptDto"
            },
            "description": "Source attempts in order."
          },
          "source": {
            "type": [
              "null",
              "string"
            ],
            "description": "The answering source: `primary`, `backup` or `local` (FIClynx re-verification); null until answered."
          },
          "pending": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Set while the check waits in the background for its provider (status `AwaitingProvider`, e.g. a\r\nbank verification job): when it was submitted, when it is checked next and when it falls back. Poll\r\n`GET /api/v1/cases/{id}` until the case status is final.",
                "$ref": "#/components/schemas/PendingCheckDto"
              }
            ]
          }
        },
        "description": "A check inside a case."
      },
      "CheckFinding": {
        "required": [
          "key",
          "label",
          "value",
          "status"
        ],
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "value": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/FindingStatus"
          }
        },
        "description": "One labelled fact a check produced, rendered uniformly by the UI and the API."
      },
      "CheckOutcome": {
        "type": "integer"
      },
      "CheckStatus": {
        "type": "integer",
        "description": "Lifecycle of a check (the verdict is CheckOutcome? Check.Outcome)."
      },
      "CheckType": {
        "type": "integer",
        "description": "The kinds of verification a case can contain."
      },
      "CheckTypeInfo": {
        "required": [
          "type",
          "displayName",
          "description",
          "appliesTo",
          "requiredFields"
        ],
        "type": "object",
        "properties": {
          "type": {
            "description": "The check type.",
            "$ref": "#/components/schemas/CheckType"
          },
          "displayName": {
            "type": "string",
            "description": "Short name, e.g. \"Identity (Home Affairs)\"."
          },
          "description": {
            "type": "string",
            "description": "One-sentence description."
          },
          "appliesTo": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SubjectKind"
            },
            "description": "Subject kinds the check can run against."
          },
          "requiredFields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Request fields (camelCase, as in the API) the check needs beyond the subject basics."
          }
        },
        "description": "Describes a check type for the UI and the `GET /api/v1/checks/types` endpoint."
      },
      "ClientInvitationRequest": {
        "type": "object",
        "properties": {
          "channel": {
            "description": "SMS, WhatsApp or Email.",
            "$ref": "#/components/schemas/InvitationChannel"
          },
          "destination": {
            "type": [
              "null",
              "string"
            ],
            "description": "Mobile number or email. Defaults to the case's phone (SMS, WhatsApp) or email."
          },
          "expiresInHours": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Link lifetime in hours; defaults to int RemoteVerificationOptions.ExpiryHours (72).",
            "format": "int32"
          }
        },
        "description": "How a case's subject is invited to verify themselves."
      },
      "CreateWebhookRequest": {
        "required": [
          "url",
          "events",
          "description"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ],
            "description": "https URL (public internet address)."
          },
          "events": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            },
            "description": "Event types: case.created, case.completed, case.awaiting_provider, check.completed, invitation.completed, decision.recorded, case.due_for_review, billing.low_balance."
          },
          "description": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional label."
          }
        },
        "description": "Create an endpoint."
      },
      "DecisionDto": {
        "required": [
          "id",
          "sequence",
          "supersedesId",
          "outcome",
          "stage",
          "riskRating",
          "suggestedRiskRating",
          "riskReason",
          "reason",
          "notes",
          "systemStatus",
          "isOverride",
          "decidedBy",
          "decidedByRole",
          "decidedAt",
          "nextReviewAt",
          "decidedByUserId",
          "channel",
          "apiKeyPrefix"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Record id.",
            "format": "uuid"
          },
          "sequence": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Position in the case's history (1 = first).",
            "format": "int32"
          },
          "supersedesId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The record this one replaces, if any.",
            "format": "uuid"
          },
          "outcome": {
            "description": "Approved, Declined or MoreInformation.",
            "$ref": "#/components/schemas/DecisionOutcome"
          },
          "stage": {
            "description": "Final, AwaitingSecondApproval (four-eyes, not yet in force) or SecondApproval.",
            "$ref": "#/components/schemas/DecisionStage"
          },
          "riskRating": {
            "description": "Low, Standard or High (enhanced due diligence).",
            "$ref": "#/components/schemas/RiskRating"
          },
          "suggestedRiskRating": {
            "description": "What FIClynx suggested from the findings.",
            "$ref": "#/components/schemas/RiskRating"
          },
          "riskReason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Why this rating."
          },
          "reason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Why this decision."
          },
          "notes": {
            "type": [
              "null",
              "string"
            ],
            "description": "Internal notes."
          },
          "systemStatus": {
            "description": "The system verdict when decided.",
            "$ref": "#/components/schemas/CaseStatus"
          },
          "isOverride": {
            "type": "boolean",
            "description": "Approved despite a Review, Failed or Incomplete verdict."
          },
          "decidedBy": {
            "type": "string",
            "description": "Who decided: \"Thandi Mokoena\", or \"Thandi Mokoena via API key flx_ab12cd34…\" when an API key acting as her recorded it (\"API key: …\" for records made before keys belonged to users)."
          },
          "decidedByRole": {
            "description": "Their role (for an API key, its effective role at the time).",
            "$ref": "#/components/schemas/OrganisationRole"
          },
          "decidedAt": {
            "type": "string",
            "description": "When (UTC).",
            "format": "date-time"
          },
          "nextReviewAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Next review date set by an approval in force (UTC).",
            "format": "date-time"
          },
          "decidedByUserId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The person who decided, also when an API key acting as them recorded it.",
            "format": "uuid"
          },
          "channel": {
            "description": "`Dashboard` or `ApiKey`.",
            "$ref": "#/components/schemas/ActionChannel"
          },
          "apiKeyPrefix": {
            "type": [
              "null",
              "string"
            ],
            "description": "The API key's public prefix when Channel is `ApiKey`."
          }
        },
        "description": "One immutable sign-off record."
      },
      "DecisionOutcome": {
        "type": "integer",
        "description": "What a compliance officer decided about a case (the FICA sign-off)."
      },
      "DecisionRequest": {
        "type": "object",
        "properties": {
          "outcome": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Approve, decline or request more information.",
                "$ref": "#/components/schemas/DecisionOutcome"
              }
            ]
          },
          "riskRating": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Low, Standard or High (High means enhanced due diligence).",
                "$ref": "#/components/schemas/RiskRating"
              }
            ]
          },
          "reason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Why: required to decline, to request more information, or to approve against a Review, Failed or Incomplete verdict."
          },
          "riskReason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Why this risk rating: required when it differs from the suggested rating."
          },
          "notes": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional internal notes kept with the decision."
          }
        },
        "description": "A sign-off as submitted by the dashboard form or `POST /api/v1/cases/{id}/decision`."
      },
      "DecisionStage": {
        "type": "integer",
        "description": "Where a decision record sits in the (optional) four-eyes approval."
      },
      "EnrolmentDto": {
        "required": [
          "status",
          "modalities",
          "sourceCaseReference",
          "consentReference",
          "consentVersion",
          "createdAt",
          "enrolledAt",
          "expiresAt",
          "revokedAt",
          "revokedReason",
          "lastMatchedAt",
          "matchCount"
        ],
        "type": "object",
        "properties": {
          "status": {
            "description": "Pending (templates held for confirmation), Active, Revoked or Expired.",
            "$ref": "#/components/schemas/BiometricEnrolmentStatus"
          },
          "modalities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BiometricModality"
            },
            "description": "Face and/or Fingerprint templates held (empty once deleted)."
          },
          "sourceCaseReference": {
            "type": "string",
            "description": "The DHA-verified case it was enrolled from."
          },
          "consentReference": {
            "type": "string",
            "description": "The biometric consent it is held under."
          },
          "consentVersion": {
            "type": "string",
            "description": "Consent text version."
          },
          "createdAt": {
            "type": "string",
            "description": "When the templates were extracted.",
            "format": "date-time"
          },
          "enrolledAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When a member or API key confirmed it.",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "description": "Pending: end of the hold. Active: end of retention.",
            "format": "date-time"
          },
          "revokedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When revoked.",
            "format": "date-time"
          },
          "revokedReason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Why revoked."
          },
          "lastMatchedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Last local match.",
            "format": "date-time"
          },
          "matchCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Local matches so far.",
            "format": "int32"
          }
        },
        "description": "A subject's biometric enrolment (no templates, no images, no full ID number)."
      },
      "EntityTagHeaderValue": {
        "type": "object",
        "properties": {
          "tag": {
            "$ref": "#/components/schemas/StringSegment"
          },
          "isWeak": {
            "type": "boolean"
          }
        }
      },
      "FileContentResult": {
        "type": "object",
        "properties": {
          "fileContents": {
            "type": "string",
            "format": "byte"
          },
          "contentType": {
            "type": [
              "null",
              "string"
            ]
          },
          "fileDownloadName": {
            "type": [
              "null",
              "string"
            ]
          },
          "lastModified": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "entityTag": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/EntityTagHeaderValue"
              }
            ]
          },
          "enableRangeProcessing": {
            "type": "boolean"
          }
        }
      },
      "FindingStatus": {
        "type": "integer",
        "description": "Status of a single finding shown to the user."
      },
      "FingerprintCaptureMetadata": {
        "type": "object",
        "properties": {
          "source": {
            "type": [
              "null",
              "string"
            ],
            "description": "The capture software: string FingerprintCaptureSources.Bridge,\r\nstring FingerprintCaptureSources.LiteClient or string FingerprintCaptureSources.Simulated."
          },
          "bridgeVersion": {
            "type": [
              "null",
              "string"
            ],
            "description": "FIClynx Bridge version, e.g. `1.0.0`, when string? FingerprintCaptureMetadata.Source is the Bridge."
          },
          "readerVendor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Reader manufacturer, e.g. `SecuGen`."
          },
          "readerModel": {
            "type": [
              "null",
              "string"
            ],
            "description": "Reader model, e.g. `Hamster Pro 20`."
          },
          "thumbs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FingerprintThumbMetadata"
            },
            "description": "One entry per captured thumb (at most two)."
          }
        },
        "description": "How the thumbprints of a fingerprint check were captured: the capture software, the reader and,\r\nper thumb, the reader's quality score and presentation attack detection (PAD, fake-finger\r\ndetection) result. Sent by the browser capture module next to the captures (JSON\r\n`fingerprintCapture`) and recorded on the check's findings. It never holds biometric data:\r\nonly short labels and numbers, checked by FingerprintCaptureMetadataRules.\r\nOptional: API callers that capture by other means may omit it."
      },
      "FingerprintThumbMetadata": {
        "type": "object",
        "properties": {
          "fingerIndex": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "ISO/IEC 19794 finger position: 1 (right thumb) or 6 (left thumb).",
            "format": "int32"
          },
          "quality": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Quality score 0-100 (higher is better), or null when the reader did not report one.",
            "format": "int32"
          },
          "qualityAlgorithm": {
            "type": [
              "null",
              "string"
            ],
            "description": "Which scale int? FingerprintThumbMetadata.Quality uses, e.g. `nfiq2`, `secugen`, `biomini`, `dpfpdd`."
          },
          "pad": {
            "type": [
              "null",
              "string"
            ],
            "description": "The reader's fake-finger check: string FingerprintPadResults.Pass,\r\nstring FingerprintPadResults.Fail, string FingerprintPadResults.Unavailable or string FingerprintPadResults.Unverified\r\n(the reader has no PAD, or the capture path does not report it). Null means unavailable."
          }
        },
        "description": "Capture facts for one thumb. No image data."
      },
      "HealthDto": {
        "required": [
          "status",
          "database",
          "providerMode",
          "providers",
          "version",
          "time"
        ],
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "\"ok\" or \"degraded\"."
          },
          "database": {
            "type": "string",
            "description": "\"ok\" or \"unreachable\"."
          },
          "providerMode": {
            "type": "string",
            "description": "Simulated or Live."
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The source chain in order, by neutral name (e.g. \"Primary source\", \"Backup source\")."
          },
          "version": {
            "type": "string",
            "description": "App version."
          },
          "time": {
            "type": "string",
            "description": "Server time (UTC).",
            "format": "date-time"
          }
        },
        "description": "`GET /api/v1/health`."
      },
      "InvitationChannel": {
        "type": "integer",
        "description": "How the verification link reaches the client."
      },
      "InvitationDto": {
        "required": [
          "id",
          "caseId",
          "status",
          "channel",
          "destinationMasked",
          "createdAt",
          "expiresAt",
          "sentAt",
          "openedAt",
          "completedAt",
          "revokedAt",
          "lockedAt",
          "lockReason",
          "sendCount",
          "lastSendError",
          "steps",
          "livenessPassed",
          "checksStartedAt",
          "checksCompletedAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Invitation id.",
            "format": "uuid"
          },
          "caseId": {
            "type": "string",
            "description": "Case id.",
            "format": "uuid"
          },
          "status": {
            "description": "Sent, Opened, InProgress, Completed, Expired, Revoked or Locked (expiry applied).",
            "$ref": "#/components/schemas/InvitationStatus"
          },
          "channel": {
            "description": "Sms, WhatsApp or Email.",
            "$ref": "#/components/schemas/InvitationChannel"
          },
          "destinationMasked": {
            "type": "string",
            "description": "Masked mobile number or email."
          },
          "createdAt": {
            "type": "string",
            "description": "Created (UTC).",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "description": "Link expiry (UTC).",
            "format": "date-time"
          },
          "sentAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Last sent (UTC).",
            "format": "date-time"
          },
          "openedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "First opened by the client (UTC).",
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Finished by the client (UTC).",
            "format": "date-time"
          },
          "revokedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Revoked (UTC).",
            "format": "date-time"
          },
          "lockedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Locked after abuse (UTC).",
            "format": "date-time"
          },
          "lockReason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Why it locked."
          },
          "sendCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Times sent.",
            "format": "int32"
          },
          "lastSendError": {
            "type": [
              "null",
              "string"
            ],
            "description": "Last sender error, if the last send failed."
          },
          "steps": {
            "description": "Which steps the client has completed.",
            "$ref": "#/components/schemas/InvitationStepsDto"
          },
          "livenessPassed": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Liveness evidence passed (null before the selfie). A basic motion challenge, not certified liveness."
          },
          "checksStartedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the checks started (UTC).",
            "format": "date-time"
          },
          "checksCompletedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the checks finished (UTC).",
            "format": "date-time"
          },
          "simulatedLink": {
            "type": [
              "null",
              "string"
            ],
            "description": "Simulated mode only: the link, so sandbox integrations and demos can open it. Never present\r\nin Live mode (the link exists only in the message sent to the client)."
          }
        },
        "description": "A client verification link as returned by the API. The token itself is never returned."
      },
      "InvitationStatus": {
        "type": "integer",
        "description": "Lifecycle of a client invitation. InvitationStatus.Completed, InvitationStatus.Expired,\r\nInvitationStatus.Revoked and InvitationStatus.Locked stop the link from working; see\r\nInvitationStateMachine for the allowed transitions."
      },
      "InvitationStepsDto": {
        "required": [
          "consent",
          "detailsConfirmed",
          "idFront",
          "idBack",
          "selfie",
          "proofOfAddressAnswered",
          "proofOfAddressUploaded"
        ],
        "type": "object",
        "properties": {
          "consent": {
            "type": "boolean",
            "description": "POPIA consent given."
          },
          "detailsConfirmed": {
            "type": "boolean",
            "description": "ID number proved and details confirmed."
          },
          "idFront": {
            "type": "boolean",
            "description": "ID front captured."
          },
          "idBack": {
            "type": "boolean",
            "description": "ID back captured (smart card only)."
          },
          "selfie": {
            "type": "boolean",
            "description": "Selfie captured."
          },
          "proofOfAddressAnswered": {
            "type": "boolean",
            "description": "Proof-of-address step answered (uploaded or skipped)."
          },
          "proofOfAddressUploaded": {
            "type": "boolean",
            "description": "Proof of address uploaded."
          }
        },
        "description": "Client progress through the steps."
      },
      "LedgerEntryDto": {
        "required": [
          "id",
          "at",
          "kind",
          "amount",
          "heldDelta",
          "balanceAfter",
          "description",
          "reason",
          "caseId",
          "caseReference",
          "checkId",
          "checkType",
          "topUpId"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Entry id (increasing).",
            "format": "int64"
          },
          "at": {
            "type": "string",
            "description": "When.",
            "format": "date-time"
          },
          "kind": {
            "description": "TopUp, Promotional, Hold, Capture, Release, Refund or Adjustment.",
            "$ref": "#/components/schemas/LedgerEntryKind"
          },
          "amount": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Signed effect on the balance.",
            "format": "double"
          },
          "heldDelta": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Signed effect on the held amount.",
            "format": "double"
          },
          "balanceAfter": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Balance after this entry.",
            "format": "double"
          },
          "description": {
            "type": "string",
            "description": "What."
          },
          "reason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Why (releases, refunds, adjustments, promotional credit)."
          },
          "caseId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The case, for check entries.",
            "format": "uuid"
          },
          "caseReference": {
            "type": [
              "null",
              "string"
            ],
            "description": "The case reference."
          },
          "checkId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The check.",
            "format": "uuid"
          },
          "checkType": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The check type.",
                "$ref": "#/components/schemas/CheckType"
              }
            ]
          },
          "topUpId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The top-up, for top-up entries.",
            "format": "uuid"
          }
        },
        "description": "A ledger entry."
      },
      "LedgerEntryKind": {
        "type": "integer",
        "description": "What a ledger entry records. The balance and the held amount are sums over the entries."
      },
      "LocalMatchDto": {
        "required": [
          "checkId",
          "modality",
          "matched",
          "result",
          "score",
          "threshold",
          "occurredAt"
        ],
        "type": "object",
        "properties": {
          "checkId": {
            "type": "string",
            "description": "The check.",
            "format": "uuid"
          },
          "modality": {
            "description": "Face or Fingerprint.",
            "$ref": "#/components/schemas/BiometricModality"
          },
          "matched": {
            "type": "boolean",
            "description": "True when it answered the check without a billed call."
          },
          "result": {
            "type": "string",
            "description": "Matched, BelowThreshold, NoLiveness, Unusable..."
          },
          "score": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Similarity score.",
            "format": "double"
          },
          "threshold": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Threshold applied.",
            "format": "double"
          },
          "occurredAt": {
            "type": "string",
            "description": "When.",
            "format": "date-time"
          }
        },
        "description": "One local match attempt."
      },
      "MeApiKeyDto": {
        "required": [
          "id",
          "name",
          "prefix",
          "role"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Key id.",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Label."
          },
          "prefix": {
            "type": "string",
            "description": "Public prefix, e.g. flx_ab12cd34."
          },
          "role": {
            "description": "The role the key was given (Operator or ComplianceOfficer), before the user's role limits it.",
            "$ref": "#/components/schemas/OrganisationRole"
          }
        },
        "description": "The calling key (never its secret)."
      },
      "MeDto": {
        "required": [
          "organisation",
          "user",
          "apiKey",
          "effectiveRole",
          "limitedByUser",
          "permissions",
          "attributedAs"
        ],
        "type": "object",
        "properties": {
          "organisation": {
            "description": "The key's organisation.",
            "$ref": "#/components/schemas/MeOrganisationDto"
          },
          "user": {
            "description": "The member the key belongs to and acts as.",
            "$ref": "#/components/schemas/MeUserDto"
          },
          "apiKey": {
            "description": "The calling key.",
            "$ref": "#/components/schemas/MeApiKeyDto"
          },
          "effectiveRole": {
            "description": "What the key acts with now: the lower of its role and the user's current role (Operator, ComplianceOfficer or Viewer).",
            "$ref": "#/components/schemas/OrganisationRole"
          },
          "limitedByUser": {
            "type": "boolean",
            "description": "True when the user's role is lower than the key's role, so the key is limited to the user's role."
          },
          "permissions": {
            "description": "What the key may do now.",
            "$ref": "#/components/schemas/ApiKeyPermissions"
          },
          "attributedAs": {
            "type": "string",
            "description": "How its actions are recorded, e.g. \"Thandi Mokoena via API key flx_ab12cd34…\"."
          }
        },
        "description": "`GET /api/v1/me`: the key, the user it acts as and its effective permissions."
      },
      "MeOrganisationDto": {
        "required": [
          "id",
          "name"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Organisation id.",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Name."
          }
        },
        "description": "The key's organisation."
      },
      "MeUserDto": {
        "required": [
          "id",
          "name",
          "role"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "User id (the same id appears as `decidedByUserId` and `authorUserId` on records the key makes).",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Their name."
          },
          "role": {
            "description": "Their current role in the organisation.",
            "$ref": "#/components/schemas/OrganisationRole"
          }
        },
        "description": "The member a key belongs to."
      },
      "NewCaseRequest": {
        "type": "object",
        "properties": {
          "subjectKind": {
            "description": "Person or Entity.",
            "$ref": "#/components/schemas/SubjectKind"
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckType"
            },
            "description": "The checks to run."
          },
          "externalReference": {
            "type": [
              "null",
              "string"
            ],
            "description": "Caller's own reference (matter or deal number)."
          },
          "countryCode": {
            "type": "string",
            "description": "ISO country code of the subject. Only ZA is validated structurally today."
          },
          "firstNames": {
            "type": [
              "null",
              "string"
            ],
            "description": "Person: first names."
          },
          "surname": {
            "type": [
              "null",
              "string"
            ],
            "description": "Person: surname."
          },
          "idNumber": {
            "type": [
              "null",
              "string"
            ],
            "description": "Person: SA ID number."
          },
          "email": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional contact email."
          },
          "phone": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional contact phone."
          },
          "entityName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Entity: registered name."
          },
          "registrationNumber": {
            "type": [
              "null",
              "string"
            ],
            "description": "Entity: CIPC registration number, e.g. 2015/123456/07."
          },
          "bankName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bank: bank name, e.g. \"FNB\". Derived from a universal branch code when omitted."
          },
          "branchCode": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bank: six-digit branch code."
          },
          "accountNumber": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bank: account number."
          },
          "accountType": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bank: Current, Savings or Transmission."
          },
          "addressLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Address: street address line."
          },
          "postalCode": {
            "type": [
              "null",
              "string"
            ],
            "description": "Address: postal code."
          },
          "bbbeeCertificateNumber": {
            "type": [
              "null",
              "string"
            ],
            "description": "B-BBEE: certificate number, optional."
          },
          "includePhoto": {
            "type": "boolean",
            "description": "Identity: ask for the DHA photo as well."
          },
          "selfie": {
            "type": [
              "null",
              "string"
            ],
            "description": "Face match: selfie image bytes (base64 in JSON).",
            "format": "byte"
          },
          "selfieContentType": {
            "type": [
              "null",
              "string"
            ],
            "description": "Face match: selfie MIME type, e.g. image/jpeg."
          },
          "livenessPassed": {
            "type": "boolean",
            "description": "Face match: whether the capture passed a liveness check, as reported by the caller. Recorded as\r\n\"Reported by caller (not verified)\"; it never unlocks the local face match or a face enrolment,\r\nwhich need FIClynx's own (phone-link) liveness. See docs/biometrics.md, liveness provenance."
          },
          "fingerprint": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fingerprint: the thumb named by int NewCaseRequest.FingerIndex (base64 in JSON), as a PNG from the\r\nreader or a 512x512 WSQ. Never stored: it lives only for the request (see docs/fingerprint.md).",
            "format": "byte"
          },
          "secondFingerprint": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fingerprint: the other thumb (base64 in JSON), same format; OmniCheck needs both thumbs.",
            "format": "byte"
          },
          "fingerprintFormat": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fingerprint: `PNG` or `WSQ`; detected from the bytes when omitted."
          },
          "fingerIndex": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Fingerprint: position of byte[]? NewCaseRequest.Fingerprint, 1 (right thumb, default) or 6 (left thumb).",
            "format": "int32"
          },
          "fingerprintCapture": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Fingerprint: optional capture metadata (capture software, reader, quality, PAD result), recorded\r\non the check's findings. A reported PAD failure refuses the request. No biometric data.",
                "$ref": "#/components/schemas/FingerprintCaptureMetadata"
              }
            ]
          },
          "storeBiometricTemplates": {
            "type": "boolean",
            "description": "Optional, separate biometric consent captured by the operator (dashboard) or the integrator\r\n(API): true only when the client explicitly agreed to BiometricConsentText\r\nso that encrypted face and fingerprint templates may be kept for future re-verification in\r\nthis organisation. Requires string? NewCaseRequest.BiometricConsentVersion. Ignored when the\r\norganisation has re-verification off. Remote (phone-link) cases ask the client directly."
          },
          "biometricConsentVersion": {
            "type": [
              "null",
              "string"
            ],
            "description": "The string BiometricConsentText.Version the client agreed to; must be the current one."
          },
          "invitation": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Send the client a verification link instead of running the checks now. The client then\r\nsupplies the ID photos and the selfie, and the checks run when they finish; identity and face\r\nmatch are added automatically. See RemoteCaseRequestValidator.",
                "$ref": "#/components/schemas/ClientInvitationRequest"
              }
            ]
          }
        },
        "description": "Everything needed to open a case and build each requested check's input. Shared by the REST\r\nAPI (JSON, camelCase) and the dashboard form. Which fields are required depends on the subject\r\nkind and the checks; see CaseRequestValidation CaseRequestBuilder.Validate(NewCaseRequest request, DateOnly today) and CheckCatalog."
      },
      "NoteDto": {
        "required": [
          "id",
          "text",
          "author",
          "createdAt",
          "authorUserId",
          "channel",
          "apiKeyPrefix"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Note id.",
            "format": "uuid"
          },
          "text": {
            "type": "string",
            "description": "The note."
          },
          "author": {
            "type": "string",
            "description": "Who wrote it: a name, or \"Thandi Mokoena via API key flx_ab12cd34…\" (\"API key: …\" for notes made before keys belonged to users)."
          },
          "createdAt": {
            "type": "string",
            "description": "When (UTC).",
            "format": "date-time"
          },
          "authorUserId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The person who wrote it, also through an API key acting as them.",
            "format": "uuid"
          },
          "channel": {
            "description": "`Dashboard` or `ApiKey`.",
            "$ref": "#/components/schemas/ActionChannel"
          },
          "apiKeyPrefix": {
            "type": [
              "null",
              "string"
            ],
            "description": "The API key's public prefix when Channel is `ApiKey`."
          }
        },
        "description": "An internal case note."
      },
      "NoteRequest": {
        "type": "object",
        "properties": {
          "text": {
            "type": [
              "null",
              "string"
            ],
            "description": "The note (plain text, up to 4 000 characters). Internal only: never shown to the client."
          }
        },
        "description": "Body of `POST /api/v1/cases/{id}/notes`."
      },
      "OrganisationRole": {
        "type": "integer",
        "description": "What a member may do in an organisation."
      },
      "PagedResultOfCaseSummaryDto": {
        "required": [
          "items",
          "page",
          "pageSize",
          "total"
        ],
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseSummaryDto"
            },
            "description": "Items on this page."
          },
          "page": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "1-based page.",
            "format": "int32"
          },
          "pageSize": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Page size.",
            "format": "int32"
          },
          "total": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Total matching items.",
            "format": "int32"
          }
        },
        "description": "A page of results."
      },
      "PagedResultOfLedgerEntryDto": {
        "required": [
          "items",
          "page",
          "pageSize",
          "total"
        ],
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LedgerEntryDto"
            },
            "description": "Items on this page."
          },
          "page": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "1-based page.",
            "format": "int32"
          },
          "pageSize": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Page size.",
            "format": "int32"
          },
          "total": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Total matching items.",
            "format": "int32"
          }
        },
        "description": "A page of results."
      },
      "PendingCheckDto": {
        "required": [
          "source",
          "sourceName",
          "submittedAt",
          "lastCheckedAt",
          "nextCheckAt",
          "fallbackAfter",
          "statusChecks",
          "etaHint"
        ],
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "The source holding the job: `primary` or `backup`."
          },
          "sourceName": {
            "type": "string",
            "description": "Its neutral name, e.g. \"Primary source\"."
          },
          "submittedAt": {
            "type": "string",
            "description": "When the source accepted the job (UTC).",
            "format": "date-time"
          },
          "lastCheckedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "The last status check (UTC), if any.",
            "format": "date-time"
          },
          "nextCheckAt": {
            "type": "string",
            "description": "The next status check (UTC).",
            "format": "date-time"
          },
          "fallbackAfter": {
            "type": "string",
            "description": "If there is still no answer by then (UTC), the check falls back once to the next provider.",
            "format": "date-time"
          },
          "statusChecks": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Status checks made so far.",
            "format": "int32"
          },
          "etaHint": {
            "type": "string",
            "description": "Human-readable expectation, e.g. \"Banks usually answer within 30 minutes…\"."
          }
        },
        "description": "A check waiting in the background for an asynchronous provider answer."
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "ProviderErrorKind": {
        "type": "integer",
        "description": "Why a provider attempt did not produce a business answer."
      },
      "RiskRating": {
        "type": "integer"
      },
      "StringSegment": {
        "type": "object",
        "properties": {
          "buffer": {
            "type": [
              "null",
              "string"
            ]
          },
          "offset": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "length": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "value": {
            "type": [
              "null",
              "string"
            ]
          },
          "hasValue": {
            "type": "boolean"
          }
        }
      },
      "SubjectDto": {
        "required": [
          "kind",
          "displayName",
          "idNumberMasked",
          "dateOfBirth",
          "registrationNumber",
          "countryCode"
        ],
        "type": "object",
        "properties": {
          "kind": {
            "description": "Person or Entity.",
            "$ref": "#/components/schemas/SubjectKind"
          },
          "displayName": {
            "type": "string",
            "description": "Name."
          },
          "idNumberMasked": {
            "type": [
              "null",
              "string"
            ],
            "description": "Person: masked SA ID number."
          },
          "dateOfBirth": {
            "type": [
              "null",
              "string"
            ],
            "description": "Person: date of birth.",
            "format": "date"
          },
          "registrationNumber": {
            "type": [
              "null",
              "string"
            ],
            "description": "Entity: CIPC number."
          },
          "countryCode": {
            "type": "string",
            "description": "ISO country."
          }
        },
        "description": "The subject of a case."
      },
      "SubjectKind": {
        "type": "integer",
        "description": "Whether a subject is a natural person or a legal entity."
      },
      "UpdateWebhookRequest": {
        "required": [
          "url",
          "events",
          "description",
          "enabled"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ],
            "description": "New URL."
          },
          "events": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            },
            "description": "New event list."
          },
          "description": {
            "type": [
              "null",
              "string"
            ],
            "description": "New label."
          },
          "enabled": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Turn on (resets the failure count) or off."
          }
        },
        "description": "Change an endpoint (omitted fields stay as they are)."
      },
      "UsageByCheckDto": {
        "required": [
          "check",
          "count",
          "total"
        ],
        "type": "object",
        "properties": {
          "check": {
            "description": "Type.",
            "$ref": "#/components/schemas/CheckType"
          },
          "count": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Checks charged.",
            "format": "int32"
          },
          "total": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Total charged.",
            "format": "double"
          }
        },
        "description": "Charges for one check type."
      },
      "UsageDto": {
        "required": [
          "month",
          "openingBalance",
          "charges",
          "credits",
          "closingBalance",
          "byCheck",
          "lines"
        ],
        "type": "object",
        "properties": {
          "month": {
            "type": "string",
            "description": "yyyy-MM."
          },
          "openingBalance": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Balance at the start of the month.",
            "format": "double"
          },
          "charges": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Checks charged.",
            "format": "double"
          },
          "credits": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Credits added (top-ups, promotional, refunds, adjustments).",
            "format": "double"
          },
          "closingBalance": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Balance at the end (or now).",
            "format": "double"
          },
          "byCheck": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageByCheckDto"
            },
            "description": "Charges per check type."
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageLineDto"
            },
            "description": "Every charge and credit, oldest first."
          }
        },
        "description": "`GET /api/v1/billing/usage`."
      },
      "UsageLineDto": {
        "required": [
          "at",
          "kind",
          "description",
          "caseReference",
          "checkType",
          "amount"
        ],
        "type": "object",
        "properties": {
          "at": {
            "type": "string",
            "description": "When.",
            "format": "date-time"
          },
          "kind": {
            "description": "Entry kind.",
            "$ref": "#/components/schemas/LedgerEntryKind"
          },
          "description": {
            "type": "string",
            "description": "What."
          },
          "caseReference": {
            "type": [
              "null",
              "string"
            ],
            "description": "The case (the only case detail)."
          },
          "checkType": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Check type.",
                "$ref": "#/components/schemas/CheckType"
              }
            ]
          },
          "amount": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Signed effect on the balance.",
            "format": "double"
          }
        },
        "description": "A usage line."
      },
      "ValidationProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      },
      "WebhookAttemptDto": {
        "required": [
          "number",
          "at",
          "statusCode",
          "durationMs",
          "error"
        ],
        "type": "object",
        "properties": {
          "number": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Attempt number.",
            "format": "int32"
          },
          "at": {
            "type": "string",
            "description": "When.",
            "format": "date-time"
          },
          "statusCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "HTTP status, or null when no response arrived.",
            "format": "int32"
          },
          "durationMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Duration.",
            "format": "int32"
          },
          "error": {
            "type": [
              "null",
              "string"
            ],
            "description": "Error, if any."
          }
        },
        "description": "One HTTP attempt."
      },
      "WebhookDeliveryDto": {
        "required": [
          "id",
          "eventId",
          "eventType",
          "status",
          "attemptCount",
          "lastStatusCode",
          "lastError",
          "nextAttemptAt",
          "createdAt",
          "deliveredAt",
          "redeliveryOf",
          "attempts"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Delivery id (the FIClynx-Delivery header).",
            "format": "uuid"
          },
          "eventId": {
            "type": "string",
            "description": "Event id (`evt_…`, the payload's id)."
          },
          "eventType": {
            "type": "string",
            "description": "Event type."
          },
          "status": {
            "type": "string",
            "description": "Pending, Delivering, Succeeded or Failed."
          },
          "attemptCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Attempts made.",
            "format": "int32"
          },
          "lastStatusCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Last HTTP status.",
            "format": "int32"
          },
          "lastError": {
            "type": [
              "null",
              "string"
            ],
            "description": "Last error."
          },
          "nextAttemptAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Next retry, while pending.",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "description": "Queued.",
            "format": "date-time"
          },
          "deliveredAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Accepted by the receiver.",
            "format": "date-time"
          },
          "redeliveryOf": {
            "type": [
              "null",
              "string"
            ],
            "description": "The delivery this one re-sends.",
            "format": "uuid"
          },
          "attempts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookAttemptDto"
            },
            "description": "Every attempt: number, time, status code, duration, error."
          }
        },
        "description": "One delivery and its attempts."
      },
      "WebhookEndpointDto": {
        "required": [
          "id",
          "url",
          "description",
          "events",
          "enabled",
          "disabledReason",
          "secretHint",
          "consecutiveFailures",
          "lastSuccessAt",
          "lastFailureAt",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Endpoint id.",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "description": "The https URL events are POSTed to."
          },
          "description": {
            "type": [
              "null",
              "string"
            ],
            "description": "Label."
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Subscribed event types."
          },
          "enabled": {
            "type": "boolean",
            "description": "False when turned off or disabled after repeated failures."
          },
          "disabledReason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Why it is disabled."
          },
          "secretHint": {
            "type": "string",
            "description": "The secret's last four characters."
          },
          "consecutiveFailures": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Failed attempts since the last success.",
            "format": "int32"
          },
          "lastSuccessAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Last successful delivery.",
            "format": "date-time"
          },
          "lastFailureAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Last failed attempt.",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "description": "Created.",
            "format": "date-time"
          },
          "secret": {
            "type": [
              "null",
              "string"
            ],
            "description": "The signing secret: only in the response to create and rotate, never again."
          }
        },
        "description": "A webhook endpoint."
      },
      "WebhookEventTypeDto": {
        "required": [
          "type",
          "description"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "The type."
          },
          "description": {
            "type": "string",
            "description": "What it means."
          }
        },
        "description": "An event type you can subscribe to."
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "description": "Organisation API key (Settings, API keys). It acts as the member who owns it, limited to their current role.",
        "name": "X-Api-Key",
        "in": "header"
      }
    }
  },
  "security": [
    {
      "ApiKey": [ ]
    }
  ],
  "tags": [
    {
      "name": "BillingApi"
    },
    {
      "name": "BiometricsApi"
    },
    {
      "name": "CasesApi"
    },
    {
      "name": "CaseWorkflowApi"
    },
    {
      "name": "ChecksApi"
    },
    {
      "name": "HealthApi"
    },
    {
      "name": "InvitationsApi"
    },
    {
      "name": "MeApi"
    },
    {
      "name": "Webhooks"
    }
  ]
}