{
  "openapi": "3.1.0",
  "info": {
    "title": "Verdict API",
    "version": "2026-11-01",
    "description": "Verdict answers the questions an AI agent asks in the middle of its work, as a calibrated probability it can act on, with the lookups included.\n\nAuthenticate with `Authorization: Bearer vd_live_...` (or `vd_test_...`). Send `Idempotency-Key` (a UUID) on every POST; a repeat within 24 hours returns the stored response and bills nothing. Pin the version with `X-Verdict-Version` (dates; the current one is `2026-11-01`). Cap spend per call with `X-Max-Cost-USD`. List endpoints use `cursor` and `limit` (up to 200). Errors are RFC 9457 problem details with a stable `type` and a `request_id`. Every response carries `X-Request-Id` and `X-RateLimit-*` headers; 429 adds `Retry-After`.\n\nOnly decisions are priced (`x-verdict-price-usd` on each). Misses, errors and refused calls are never billed. Index reads, outcomes and account calls are free.",
    "contact": { "name": "Verdict", "url": "https://docs.verdict.invalid" },
    "license": { "name": "Proprietary", "url": "https://verdict.invalid/terms" }
  },
  "servers": [{ "url": "https://api.askverdict.io", "description": "Production (spec 3.7)." }],
  "security": [{ "bearerAuth": [] }],
  "tags": [
    { "name": "Decisions", "description": "The six priced decisions and decision lookup." },
    {
      "name": "Index",
      "description": "Firms, events and sources from Verdict's open-licensed index."
    },
    {
      "name": "Watches",
      "description": "Standing scored-event subscriptions delivered by webhook."
    },
    { "name": "Outcomes", "description": "What happened after a decision; feeds calibration." },
    {
      "name": "Inbound webhooks",
      "description": "Receivers that turn vendor webhooks into outcomes."
    },
    {
      "name": "ICP profiles",
      "description": "Who you sell to and the thresholds decisions apply."
    },
    { "name": "Account", "description": "Sign-up, identity, keys, limits and the audit log." },
    { "name": "Billing", "description": "Balance, top-ups, usage and the ledger." },
    {
      "name": "Console",
      "description": "Console sign-in, sessions, TOTP and members (cookie auth)."
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key: `vd_live_` or `vd_test_` followed by its base62 body."
      },
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "verdict_session",
        "description": "Console session cookie set by the sign-in endpoints (httpOnly, Secure, SameSite=Lax, 7-day idle expiry). Console endpoints only; agents use API keys."
      }
    },
    "headers": {
      "XRequestId": {
        "description": "The request id (`req_...`), also `request_id` in every error. Quote it to support.",
        "required": true,
        "schema": { "type": "string", "pattern": "^req_[0-7][0-9A-HJKMNP-TV-Z]{25}$" }
      },
      "XRateLimitLimit": {
        "description": "Requests allowed per minute for this key.",
        "required": true,
        "schema": { "type": "integer", "minimum": 0 }
      },
      "XRateLimitRemaining": {
        "description": "Requests left in the current one-minute window.",
        "required": true,
        "schema": { "type": "integer", "minimum": 0 }
      },
      "XRateLimitReset": {
        "description": "Unix time, in seconds, when the current window resets.",
        "required": true,
        "schema": { "type": "integer", "minimum": 0 }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "required": true,
        "schema": { "type": "integer", "minimum": 0 }
      }
    },
    "responses": {
      "Error400": {
        "description": "Invalid request: malformed JSON, an unknown field, a failed constraint or a size limit (`invalid_request`).",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "invalid_request": {
                "summary": "Invalid request",
                "value": {
                  "type": "invalid_request",
                  "title": "Invalid request",
                  "status": 400,
                  "detail": "roster: at most 50 entries are allowed.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "errors": [{ "path": "/roster", "message": "at most 50 entries are allowed" }]
                }
              }
            }
          }
        }
      },
      "Error401": {
        "description": "Missing, malformed, revoked or expired API key, or a bad webhook signature (`unauthorized`).",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "unauthorized": {
                "summary": "Unauthorized",
                "value": {
                  "type": "unauthorized",
                  "title": "Unauthorized",
                  "status": 401,
                  "detail": "The API key is missing, revoked or expired.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
                }
              }
            }
          }
        }
      },
      "Error402": {
        "description": "Payment required: the balance cannot cover the call (`insufficient_balance`), or the call would exceed `X-Max-Cost-USD` (`max_cost_exceeded`). Nothing was spent.",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "insufficient_balance": {
                "summary": "Insufficient balance",
                "value": {
                  "type": "insufficient_balance",
                  "title": "Insufficient balance",
                  "status": 402,
                  "detail": "The balance cannot cover this call. Top up with POST /v1/topup.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "required_usd": 0.005,
                  "balance_usd": 0.002
                }
              },
              "max_cost_exceeded": {
                "summary": "Maximum cost exceeded",
                "value": {
                  "type": "max_cost_exceeded",
                  "title": "Maximum cost exceeded",
                  "status": 402,
                  "detail": "This call costs $0.005, above X-Max-Cost-USD 0.001. Nothing was spent.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "required_usd": 0.005
                }
              }
            }
          }
        }
      },
      "Error403": {
        "description": "The key lacks the scope this operation needs (`forbidden_scope`).",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "forbidden_scope": {
                "summary": "Forbidden",
                "value": {
                  "type": "forbidden_scope",
                  "title": "Forbidden",
                  "status": 403,
                  "detail": "This key lacks the decisions:write scope.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
                }
              }
            }
          }
        }
      },
      "Error404": {
        "description": "The resource does not exist in this organization (`not_found`).",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "not_found": {
                "summary": "Not found",
                "value": {
                  "type": "not_found",
                  "title": "Not found",
                  "status": 404,
                  "detail": "No ICP profile icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V in this organization.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
                }
              }
            }
          }
        }
      },
      "Error409": {
        "description": "The `Idempotency-Key` was reused with a different request, or the first request is still running (`idempotency_conflict`).",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "idempotency_conflict": {
                "summary": "Idempotency conflict",
                "value": {
                  "type": "idempotency_conflict",
                  "title": "Idempotency conflict",
                  "status": 409,
                  "detail": "This Idempotency-Key was used with a different request body.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
                }
              }
            }
          }
        }
      },
      "Error429": {
        "description": "Rate limited (`rate_limited`). Wait `Retry-After` seconds.",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" },
          "retry-after": { "$ref": "#/components/headers/RetryAfter" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "rate_limited": {
                "summary": "Rate limited",
                "value": {
                  "type": "rate_limited",
                  "title": "Rate limited",
                  "status": 429,
                  "detail": "600 requests per minute exceeded for this key.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "retry_after_seconds": 12
                }
              }
            }
          }
        }
      },
      "Error500": {
        "description": "Unexpected server error (`internal`). Not billed; retry with the same `Idempotency-Key`.",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "internal": {
                "summary": "Internal error",
                "value": {
                  "type": "internal",
                  "title": "Internal error",
                  "status": 500,
                  "detail": "Unexpected error. Nothing was billed; retry with the same Idempotency-Key.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
                }
              }
            }
          }
        }
      },
      "Error503": {
        "description": "Temporarily unavailable: the decision model failed, timed out or is rate limited, or decisions are switched off (`decision_unavailable`), or a vendor the call depends on is unavailable (`vendor_unavailable`, phase 2). Not billed. Wait `Retry-After` seconds and retry with the same `Idempotency-Key`.",
        "headers": {
          "x-request-id": { "$ref": "#/components/headers/XRequestId" },
          "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
          "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
          "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" },
          "retry-after": { "$ref": "#/components/headers/RetryAfter" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/Problem" },
            "examples": {
              "vendor_unavailable": {
                "summary": "Vendor unavailable",
                "value": {
                  "type": "vendor_unavailable",
                  "title": "Vendor unavailable",
                  "status": 503,
                  "detail": "The vendor did not answer. Nothing was billed.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "retry_after_seconds": 30
                }
              },
              "decision_unavailable": {
                "summary": "Decision unavailable",
                "value": {
                  "type": "decision_unavailable",
                  "title": "Decision unavailable",
                  "status": 503,
                  "detail": "The decision model did not answer in time. Nothing was billed; retry after Retry-After seconds with the same Idempotency-Key.",
                  "request_id": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "retry_after_seconds": 2
                }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "ScoredEventDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^dlv_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Delivery id; dedupe on it, retries reuse it.",
            "example": "dlv_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "type": { "type": "string", "enum": ["event.scored"], "description": "Payload type." },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the delivery was created."
          },
          "watch_id": {
            "type": "string",
            "pattern": "^wch_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The watch.",
            "example": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "event": { "$ref": "#/components/schemas/Event" },
          "score": {
            "allOf": [
              { "$ref": "#/components/schemas/EventScore" },
              { "description": "A `score_signal` result for one event and one ICP." }
            ]
          }
        },
        "required": ["id", "type", "created_at", "watch_id", "event", "score"],
        "description": "A scored event delivered to a watch."
      },
      "Event": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["filing"],
                "description": "Event type `filing`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "filing_type": {
                    "type": "string",
                    "enum": ["sec_8k", "sec_form_d", "sec_form_4", "sec_s1", "sec_13f", "sec_adv"],
                    "description": "The filing sub-type."
                  },
                  "accession_number": { "type": "string", "description": "SEC accession number." },
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "description": "An 8-K item number, for example `5.02`."
                    },
                    "description": "8-K item numbers reported, for `sec_8k`."
                  },
                  "title": { "type": "string", "description": "Filing title or form description." },
                  "form": {
                    "type": "string",
                    "description": "The form type exactly as the source lists it, for example `8-K/A` or `13F-HR`."
                  },
                  "file_number": {
                    "type": "string",
                    "description": "SEC file number, for example `333-299845`."
                  }
                },
                "required": ["filing_type"],
                "description": "Attributes of a `filing` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["registration"],
                "description": "Event type `registration`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "registry": {
                    "type": "string",
                    "description": "The registry or regulator, for example `SEC IARD` or `Companies House`."
                  },
                  "registration_number": { "type": "string", "description": "Registration number." }
                },
                "required": ["registry"],
                "description": "Attributes of a `registration` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["officer_change"],
                "description": "Event type `officer_change`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "change": {
                    "type": "string",
                    "enum": ["appointed", "departed", "unspecified"],
                    "description": "Appointment or departure."
                  },
                  "role": {
                    "type": "string",
                    "description": "The officer role, for example `Chief Compliance Officer` or `Director`."
                  }
                },
                "required": ["change", "role"],
                "description": "Attributes of a `officer_change` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["ownership_change"],
                "description": "Event type `ownership_change`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "change": {
                    "type": "string",
                    "enum": ["acquired", "disposed", "control_changed"],
                    "description": "What changed."
                  },
                  "owner_kind": {
                    "type": "string",
                    "enum": ["person", "entity", "unknown"],
                    "description": "Kind of holder."
                  },
                  "ownership_band": {
                    "type": "string",
                    "description": "Ownership band as the source reports it, for example `25-50%`."
                  },
                  "parent_lei": {
                    "type": "string",
                    "pattern": "^[A-Z0-9]{18}[0-9]{2}$",
                    "description": "LEI of the parent, for GLEIF relationship records.",
                    "example": "549300ABCDEF12345678"
                  },
                  "relationship": {
                    "type": "string",
                    "enum": ["direct_parent", "ultimate_parent"],
                    "description": "Which parent relationship changed, for GLEIF relationship records."
                  }
                },
                "required": ["change", "owner_kind"],
                "description": "Attributes of a `ownership_change` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["lei_change"],
                "description": "Event type `lei_change`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "change": {
                    "type": "string",
                    "enum": ["issued", "renewed", "lapsed", "retired", "parent_changed"],
                    "description": "What changed in the LEI record."
                  },
                  "lei": {
                    "type": "string",
                    "pattern": "^[A-Z0-9]{18}[0-9]{2}$",
                    "description": "The LEI concerned.",
                    "example": "549300ABCDEF12345678"
                  },
                  "parent_lei": {
                    "type": "string",
                    "pattern": "^[A-Z0-9]{18}[0-9]{2}$",
                    "description": "LEI of the new parent, for `parent_changed`.",
                    "example": "549300ABCDEF12345678"
                  }
                },
                "required": ["change", "lei"],
                "description": "Attributes of a `lei_change` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["address_change"],
                "description": "Event type `address_change`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "country": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$",
                    "description": "New country.",
                    "example": "US"
                  },
                  "region": { "type": "string", "description": "New region or state." },
                  "city": { "type": "string", "description": "New city." }
                },
                "required": ["country"],
                "description": "Attributes of a `address_change` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["fund_raise"],
                "description": "Event type `fund_raise`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "amount_usd": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Amount raised or offered. US dollars, up to 6 decimals."
                  },
                  "exemption": {
                    "type": "string",
                    "description": "Securities exemption claimed, for example `506(b)`."
                  },
                  "offering_type": {
                    "type": "string",
                    "description": "Type of securities offered, for example `equity`."
                  }
                },
                "description": "Attributes of a `fund_raise` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["insider_trade"],
                "description": "Event type `insider_trade`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "transaction_code": {
                    "type": "string",
                    "description": "SEC Form 4 transaction code, for example `P` (purchase) or `S` (sale)."
                  },
                  "shares": { "type": "number", "description": "Number of shares." },
                  "value_usd": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Transaction value. US dollars, up to 6 decimals."
                  },
                  "insider_role": {
                    "type": "string",
                    "description": "The insider's relationship to the issuer, for example `Director`."
                  }
                },
                "required": ["transaction_code"],
                "description": "Attributes of a `insider_trade` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["patent_filing"],
                "description": "Event type `patent_filing`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "office": {
                    "type": "string",
                    "description": "Patent or trademark office, for example `USPTO`."
                  },
                  "application_number": { "type": "string", "description": "Application number." },
                  "title": { "type": "string", "description": "Title of the application." }
                },
                "required": ["office"],
                "description": "Attributes of a `patent_filing` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["litigation"],
                "description": "Event type `litigation`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "court": { "type": "string", "description": "Court." },
                  "case_number": { "type": "string", "description": "Case number." },
                  "nature": { "type": "string", "description": "Nature of suit." }
                },
                "description": "Attributes of a `litigation` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["news_mention"],
                "description": "Event type `news_mention`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "headline": { "type": "string", "description": "Headline of the cited article." },
                  "publisher": { "type": "string", "description": "Publisher." }
                },
                "required": ["headline"],
                "description": "Attributes of a `news_mention` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["repo_activity"],
                "description": "Event type `repo_activity`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "metric": {
                    "type": "string",
                    "description": "Organization-level metric, for example `public_repos_created`."
                  },
                  "value": { "type": "number", "description": "Metric value." },
                  "period_days": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Window the metric covers, in days."
                  }
                },
                "required": ["metric", "value", "period_days"],
                "description": "Attributes of a `repo_activity` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The event id.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The firm the event happened to.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the event happened, per the source."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "When Verdict ingested the event."
              },
              "source": {
                "type": "string",
                "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
                "description": "The index source."
              },
              "source_url": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri",
                "description": "Link to the event at the source."
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Confidence in the event's normalization and firm keying."
              },
              "score": { "$ref": "#/components/schemas/EventScore" },
              "type": {
                "type": "string",
                "enum": ["hiring_aggregate"],
                "description": "Event type `hiring_aggregate`."
              },
              "attributes": {
                "type": "object",
                "properties": {
                  "metric": {
                    "type": "string",
                    "description": "Aggregate hiring metric, for example `postings_index`."
                  },
                  "value": { "type": "number", "description": "Metric value." },
                  "period": {
                    "type": "string",
                    "description": "Period the metric covers, for example `2026-10`."
                  }
                },
                "required": ["metric", "value", "period"],
                "description": "Attributes of a `hiring_aggregate` event."
              }
            },
            "required": [
              "id",
              "firm_id",
              "occurred_at",
              "observed_at",
              "source",
              "source_url",
              "confidence",
              "score",
              "type",
              "attributes"
            ]
          }
        ],
        "description": "Something that happened to a firm, normalized to one schema; `attributes` are typed per `type` (one of `filing`, `registration`, `officer_change`, `ownership_change`, `lei_change`, `address_change`, `fund_raise`, `insider_trade`, `patent_filing`, `litigation`, `news_mention`, `repo_activity`, `hiring_aggregate`)."
      },
      "EventScore": {
        "type": ["object", "null"],
        "properties": {
          "decision_id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The `score_signal` decision that produced this score (billed once).",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "icp_id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The ICP profile the event was scored against.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "relevant": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Calibrated probability that the event matters for the ICP's offer."
          },
          "act_now": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Calibrated probability that now is the time to act."
          },
          "window_days": {
            "type": ["integer", "null"],
            "minimum": 0,
            "description": "Days left to act on the event, or `null` when there is no clear window."
          },
          "answer": {
            "type": "string",
            "enum": ["relevant", "not_relevant"],
            "description": "`relevant` applied to the threshold."
          },
          "reason_code": {
            "type": "string",
            "enum": [
              "event_relevant_and_timely",
              "event_relevant_but_stale",
              "event_type_not_relevant",
              "event_routine",
              "firm_not_in_icp",
              "event_low_confidence",
              "event_superseded",
              "insufficient_event_data"
            ],
            "description": "Why, as a `score_signal` reason code."
          }
        },
        "required": [
          "decision_id",
          "icp_id",
          "relevant",
          "act_now",
          "window_days",
          "answer",
          "reason_code"
        ],
        "description": "The event's score for the requested ICP, or `null` when read without `icp_id`."
      },
      "WebhookChallenge": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["webhook.challenge"],
            "description": "Payload type."
          },
          "watch_id": {
            "type": "string",
            "pattern": "^wch_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The watch being registered.",
            "example": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "challenge": {
            "type": "string",
            "minLength": 32,
            "maxLength": 128,
            "description": "Random string; respond 200 with `{\"challenge\": <this value>}` within 10 seconds."
          }
        },
        "required": ["type", "watch_id", "challenge"],
        "description": "The registration challenge sent to a new webhook URL."
      },
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "invalid_request",
              "unauthorized",
              "forbidden_scope",
              "not_found",
              "insufficient_balance",
              "max_cost_exceeded",
              "rate_limited",
              "idempotency_conflict",
              "vendor_unavailable",
              "decision_unavailable",
              "internal"
            ],
            "description": "Stable error slug (a relative URI reference, RFC 9457). Branch on this, not on `title` or `detail`. `invalid_request` (400): The request is malformed, has unknown fields or breaks a size limit. `unauthorized` (401): The API key is missing, malformed, revoked or expired. `forbidden_scope` (403): The key lacks the scope this endpoint needs, or the resource belongs to another org. `not_found` (404): The resource does not exist in this organization. `insufficient_balance` (402): The balance cannot cover the call; top up. `max_cost_exceeded` (402): The call would cost more than `X-Max-Cost-USD`; nothing was spent. `rate_limited` (429): Too many requests; wait `Retry-After` seconds. `idempotency_conflict` (409): The `Idempotency-Key` was reused with a different request, or the first request is still running. `vendor_unavailable` (503): A vendor the call depends on is unavailable; nothing was billed. `decision_unavailable` (503): The decision model is temporarily unavailable or decisions are switched off; retry after `Retry-After`. Nothing was billed. `internal` (500): An unexpected server error; nothing was billed. Retry with the same `Idempotency-Key`."
          },
          "title": { "type": "string", "description": "Short human summary of the error type." },
          "status": { "type": "integer", "description": "The HTTP status code, repeated." },
          "detail": { "type": "string", "description": "Human explanation of this occurrence." },
          "instance": { "type": "string", "description": "The request path that failed." },
          "request_id": {
            "type": "string",
            "pattern": "^req_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The request id; also sent as `X-Request-Id`.",
            "example": "req_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string",
                  "description": "JSON Pointer (RFC 6901) to the offending field, or the header or query parameter name.",
                  "example": "/roster/50"
                },
                "message": {
                  "type": "string",
                  "description": "What is wrong with the field.",
                  "example": "too many entries"
                }
              },
              "required": ["path", "message"]
            },
            "description": "Field-level issues, present on `invalid_request`."
          },
          "required_usd": {
            "type": "number",
            "description": "What the call would cost, in US dollars; present on 402 errors."
          },
          "balance_usd": {
            "type": "number",
            "description": "The current balance, in US dollars; present on `insufficient_balance`."
          },
          "retry_after_seconds": {
            "type": "integer",
            "description": "Seconds to wait before retrying; present on `rate_limited` (429) and on 503s (`decision_unavailable`, `vendor_unavailable`), equal to the `Retry-After` header."
          }
        },
        "required": ["type", "title", "status", "detail", "request_id"],
        "description": "An RFC 9457 problem-details error. Every error carries `type` and `request_id`. Errors are never billed."
      },
      "QualifyFirmResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The decision id. Report outcomes against it.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "decision": {
            "type": "string",
            "enum": ["qualify_firm"],
            "description": "The decision name."
          },
          "version": {
            "type": "string",
            "enum": ["2026-11-01"],
            "description": "API version that served the decision."
          },
          "question_set_version": {
            "type": "string",
            "format": "date",
            "description": "Version (a date) of the question set that answered (spec 6.1)."
          },
          "model": {
            "type": "string",
            "enum": ["jev"],
            "description": "Decision model that answered: always `jev` (ADR-0008)."
          },
          "p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Calibrated probability (spec 6.4). Always present."
          },
          "answer": {
            "type": "string",
            "enum": ["fit", "not_fit"],
            "description": "`fit` or `not_fit`: `p` applied to your threshold."
          },
          "reason_code": {
            "type": "string",
            "enum": [
              "icp_type_and_size_match",
              "icp_type_match_size_mismatch",
              "icp_size_match_type_mismatch",
              "icp_type_and_size_mismatch",
              "icp_geography_mismatch",
              "icp_exclusion_filter_match",
              "firm_inactive",
              "insufficient_firm_data"
            ],
            "description": "Why, from the fixed `qualify_firm` reason-code enum."
          },
          "reason": {
            "type": "string",
            "description": "Short templated explanation of `reason_code`; never free text from a frontier model."
          },
          "evidence": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Evidence" },
            "description": "Cited sources, with URLs and dates."
          },
          "calibration": { "$ref": "#/components/schemas/Calibration" },
          "cost": { "$ref": "#/components/schemas/Cost" },
          "balance_usd": {
            "type": "number",
            "description": "Balance after this call. US dollars, up to 6 decimals."
          },
          "latency_ms": {
            "type": "integer",
            "minimum": 0,
            "description": "Server-side latency of the call, in milliseconds."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the decision was made. Decisions are immutable."
          },
          "fit": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Probability the firm fits the ICP; equal to `p`."
          },
          "firm": { "$ref": "#/components/schemas/FirmSummary" }
        },
        "required": [
          "id",
          "decision",
          "version",
          "question_set_version",
          "model",
          "p",
          "answer",
          "reason_code",
          "reason",
          "evidence",
          "calibration",
          "cost",
          "balance_usd",
          "latency_ms",
          "created_at",
          "fit",
          "firm"
        ],
        "description": "The `qualify_firm` decision envelope."
      },
      "Evidence": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "enum": ["sec_edgar", "gleif", "companies_house", "wikidata", "request"],
            "description": "The index source cited, or `request` when the evidence is part of your own input."
          },
          "url": {
            "type": ["string", "null"],
            "format": "uri",
            "description": "Link to the cited record at the source; `null` when `source` is `request`."
          },
          "observed_at": {
            "type": "string",
            "format": "date",
            "description": "Date the source reported the fact."
          },
          "label": {
            "type": "string",
            "description": "Short description of what the evidence shows."
          },
          "pointer": {
            "type": "string",
            "description": "JSON Pointer into your request body when `source` is `request`, for example `/thread/2`."
          }
        },
        "required": ["source", "url", "observed_at"],
        "description": "A cited source behind a decision."
      },
      "Calibration": {
        "type": "object",
        "properties": {
          "basis": {
            "type": "string",
            "enum": ["org", "segment", "global"],
            "description": "`org` (your own outcomes), `segment` (your ICP's segment) or `global`: how much to trust `p`."
          },
          "n_outcomes": {
            "type": "integer",
            "minimum": 0,
            "description": "Outcomes behind the calibration map used."
          },
          "threshold": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "The threshold `answer` applied to `p`."
          }
        },
        "required": ["basis", "n_outcomes", "threshold"],
        "description": "How `p` was calibrated (spec 6.4)."
      },
      "Cost": {
        "type": "object",
        "properties": {
          "decision_usd": {
            "type": "number",
            "minimum": 0,
            "description": "Price of the decision. US dollars, up to 6 decimals."
          },
          "vendor_usd": {
            "type": "number",
            "minimum": 0,
            "description": "Vendor pass-through charges (always 0 in v1). US dollars, up to 6 decimals."
          },
          "total_usd": {
            "type": "number",
            "minimum": 0,
            "description": "Total billed for this call. US dollars, up to 6 decimals."
          }
        },
        "required": ["decision_usd", "vendor_usd", "total_usd"],
        "description": "What this call was billed, itemized. Misses and errors bill nothing."
      },
      "FirmSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The firm id.",
            "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "name": { "type": "string", "description": "Canonical firm name." },
          "domain": { "type": ["string", "null"], "description": "Primary web domain, if known." },
          "identifiers": {
            "type": "object",
            "properties": {
              "lei": {
                "type": "string",
                "pattern": "^[A-Z0-9]{18}[0-9]{2}$",
                "description": "Legal Entity Identifier.",
                "example": "549300ABCDEF12345678"
              },
              "cik": {
                "type": "string",
                "pattern": "^[0-9]{1,10}$",
                "description": "SEC Central Index Key.",
                "example": "1601234"
              },
              "crd": {
                "type": "string",
                "pattern": "^[0-9]{1,8}$",
                "description": "CRD number.",
                "example": "298765"
              },
              "companies_house": {
                "type": "string",
                "pattern": "^[A-Z0-9]{8}$",
                "description": "UK Companies House number.",
                "example": "09876543"
              },
              "wikidata": {
                "type": "string",
                "pattern": "^Q[1-9][0-9]*$",
                "description": "Wikidata item id.",
                "example": "Q95"
              }
            },
            "description": "Registry identifiers, by kind."
          },
          "type": {
            "type": "string",
            "enum": [
              "operating_company",
              "investment_adviser",
              "broker_dealer",
              "investment_fund",
              "nonprofit",
              "public_body",
              "other",
              "unknown"
            ],
            "description": "Coarse firm type."
          },
          "size_band": {
            "type": "string",
            "enum": ["micro", "small", "medium", "large", "enterprise", "unknown"],
            "description": "Employee-count size band."
          },
          "hq": {
            "type": "object",
            "properties": {
              "country": {
                "type": ["string", "null"],
                "pattern": "^[A-Z]{2}$",
                "description": "ISO 3166-1 alpha-2 country.",
                "example": "US"
              },
              "region": {
                "type": ["string", "null"],
                "description": "State, county or region, as the registry gives it."
              },
              "city": { "type": ["string", "null"], "description": "City." }
            },
            "required": ["country", "region", "city"],
            "description": "Headquarters location."
          },
          "status": {
            "type": "string",
            "enum": ["active", "inactive", "dissolved", "unknown", "merged"],
            "description": "Registry status."
          }
        },
        "required": ["id", "name", "domain", "identifiers", "type", "size_band", "hq", "status"],
        "description": "A firm's id, names, identifiers and public facts."
      },
      "QualifyFirmRequest": {
        "type": "object",
        "properties": {
          "firm": { "$ref": "#/components/schemas/FirmReference" },
          "icp_id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The ICP profile to decide against.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          }
        },
        "required": ["firm", "icp_id"],
        "additionalProperties": false,
        "description": "A firm reference and the ICP to qualify it against."
      },
      "FirmReference": {
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "firm_id": {
                "type": "string",
                "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "A firm id from Verdict's index.",
                "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              }
            },
            "required": ["firm_id"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "domain": {
                "type": "string",
                "pattern": "^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+[A-Za-z]{2,63}$",
                "description": "The firm's web domain.",
                "example": "northfieldcapital.com"
              }
            },
            "required": ["domain"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "The firm's legal or trading name."
              },
              "hint": {
                "type": "object",
                "properties": {
                  "country": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$",
                    "description": "ISO 3166-1 alpha-2 country of the firm's headquarters.",
                    "example": "US"
                  },
                  "city": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "City of the firm's headquarters."
                  },
                  "domain": {
                    "type": "string",
                    "pattern": "^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+[A-Za-z]{2,63}$",
                    "description": "A domain the firm is known to use.",
                    "example": "northfieldcapital.com"
                  }
                },
                "additionalProperties": false,
                "description": "Optional country, city or domain to disambiguate the name."
              }
            },
            "required": ["name"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "lei": {
                "type": "string",
                "pattern": "^[A-Z0-9]{18}[0-9]{2}$",
                "description": "The firm's Legal Entity Identifier.",
                "example": "549300ABCDEF12345678"
              }
            },
            "required": ["lei"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "cik": {
                "type": "string",
                "pattern": "^[0-9]{1,10}$",
                "description": "The firm's SEC Central Index Key.",
                "example": "1601234"
              }
            },
            "required": ["cik"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "crd": {
                "type": "string",
                "pattern": "^[0-9]{1,8}$",
                "description": "The firm's CRD number.",
                "example": "298765"
              }
            },
            "required": ["crd"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "companies_house": {
                "type": "string",
                "pattern": "^[A-Z0-9]{8}$",
                "description": "The firm's UK Companies House number.",
                "example": "09876543"
              }
            },
            "required": ["companies_house"],
            "additionalProperties": false
          }
        ],
        "description": "A firm reference: exactly one of `firm_id`, `domain`, `name` (with an optional `hint`), `lei`, `cik`, `crd` or `companies_house`."
      },
      "ScoreSignalResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The decision id. Report outcomes against it.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "decision": {
            "type": "string",
            "enum": ["score_signal"],
            "description": "The decision name."
          },
          "version": {
            "type": "string",
            "enum": ["2026-11-01"],
            "description": "API version that served the decision."
          },
          "question_set_version": {
            "type": "string",
            "format": "date",
            "description": "Version (a date) of the question set that answered (spec 6.1)."
          },
          "model": {
            "type": "string",
            "enum": ["jev"],
            "description": "Decision model that answered: always `jev` (ADR-0008)."
          },
          "p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Calibrated probability (spec 6.4). Always present."
          },
          "answer": {
            "type": "string",
            "enum": ["relevant", "not_relevant"],
            "description": "`relevant` or `not_relevant`: `p` applied to your threshold."
          },
          "reason_code": {
            "type": "string",
            "enum": [
              "event_relevant_and_timely",
              "event_relevant_but_stale",
              "event_type_not_relevant",
              "event_routine",
              "firm_not_in_icp",
              "event_low_confidence",
              "event_superseded",
              "insufficient_event_data"
            ],
            "description": "Why, from the fixed `score_signal` reason-code enum."
          },
          "reason": {
            "type": "string",
            "description": "Short templated explanation of `reason_code`; never free text from a frontier model."
          },
          "evidence": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Evidence" },
            "description": "Cited sources, with URLs and dates."
          },
          "calibration": { "$ref": "#/components/schemas/Calibration" },
          "cost": { "$ref": "#/components/schemas/Cost" },
          "balance_usd": {
            "type": "number",
            "description": "Balance after this call. US dollars, up to 6 decimals."
          },
          "latency_ms": {
            "type": "integer",
            "minimum": 0,
            "description": "Server-side latency of the call, in milliseconds."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the decision was made. Decisions are immutable."
          },
          "relevant": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Probability the event matters for the ICP's offer; equal to `p`."
          },
          "act_now": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Probability that now is the time to act on it."
          },
          "window_days": {
            "type": ["integer", "null"],
            "minimum": 0,
            "description": "Days left to act, or `null` when there is no clear window."
          },
          "event_id": {
            "type": "string",
            "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The scored event (an inline event is stored and given an id).",
            "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "firm": { "$ref": "#/components/schemas/FirmSummary" }
        },
        "required": [
          "id",
          "decision",
          "version",
          "question_set_version",
          "model",
          "p",
          "answer",
          "reason_code",
          "reason",
          "evidence",
          "calibration",
          "cost",
          "balance_usd",
          "latency_ms",
          "created_at",
          "relevant",
          "act_now",
          "window_days",
          "event_id",
          "firm"
        ],
        "description": "The `score_signal` decision envelope."
      },
      "ScoreSignalRequest": {
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "event_id": {
                "type": "string",
                "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "An event from the index.",
                "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "icp_id": {
                "type": "string",
                "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The ICP profile to decide against.",
                "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              }
            },
            "required": ["event_id", "icp_id"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "event": { "$ref": "#/components/schemas/InlineEvent" },
              "icp_id": {
                "type": "string",
                "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The ICP profile to decide against.",
                "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              }
            },
            "required": ["event", "icp_id"],
            "additionalProperties": false
          }
        ],
        "description": "An `event_id` from the index, or an inline `event`, and the ICP to score it for."
      },
      "InlineEvent": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "filing",
              "registration",
              "officer_change",
              "ownership_change",
              "lei_change",
              "address_change",
              "fund_raise",
              "insider_trade",
              "patent_filing",
              "litigation",
              "news_mention",
              "repo_activity",
              "hiring_aggregate"
            ],
            "description": "Event type."
          },
          "firm": { "$ref": "#/components/schemas/FirmReference" },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the event happened."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500,
            "description": "One-line summary of the event."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8192,
            "description": "What happened, in plain text. At most 8192 bytes of UTF-8."
          },
          "source_url": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri",
            "description": "Where the event was reported."
          }
        },
        "required": ["type", "firm", "occurred_at"],
        "additionalProperties": false,
        "description": "An event the caller supplies, for events Verdict's index does not hold."
      },
      "PickPersonResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The decision id. Report outcomes against it.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "decision": {
            "type": "string",
            "enum": ["pick_person"],
            "description": "The decision name."
          },
          "version": {
            "type": "string",
            "enum": ["2026-11-01"],
            "description": "API version that served the decision."
          },
          "question_set_version": {
            "type": "string",
            "format": "date",
            "description": "Version (a date) of the question set that answered (spec 6.1)."
          },
          "model": {
            "type": "string",
            "enum": ["jev"],
            "description": "Decision model that answered: always `jev` (ADR-0008)."
          },
          "p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Calibrated probability (spec 6.4). Always present."
          },
          "answer": {
            "type": "string",
            "enum": ["pick", "no_pick"],
            "description": "`pick` or `no_pick`: the top person's `p` applied to your threshold."
          },
          "reason_code": {
            "type": "string",
            "enum": [
              "buyer_role_match",
              "seniority_match",
              "influencer_role_match",
              "question_match",
              "too_senior_for_offer",
              "too_junior_for_offer",
              "titles_ambiguous",
              "no_strong_match"
            ],
            "description": "Why, from the fixed `pick_person` reason-code enum."
          },
          "reason": {
            "type": "string",
            "description": "Short templated explanation of `reason_code`; never free text from a frontier model."
          },
          "evidence": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Evidence" },
            "description": "Cited sources, with URLs and dates."
          },
          "calibration": { "$ref": "#/components/schemas/Calibration" },
          "cost": { "$ref": "#/components/schemas/Cost" },
          "balance_usd": {
            "type": "number",
            "description": "Balance after this call. US dollars, up to 6 decimals."
          },
          "latency_ms": {
            "type": "integer",
            "minimum": 0,
            "description": "Server-side latency of the call, in milliseconds."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the decision was made. Decisions are immutable."
          },
          "people": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Zero-based position of the person in your `roster`."
                },
                "ref": {
                  "type": ["string", "null"],
                  "description": "Your `ref` for the person, or `null` if you gave none."
                },
                "rank": { "type": "integer", "minimum": 1, "description": "Rank, 1 is best." },
                "p": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1,
                  "description": "Calibrated probability that this is the right person to write to."
                }
              },
              "required": ["index", "ref", "rank", "p"]
            },
            "description": "The whole roster ranked best first, each with `p`."
          }
        },
        "required": [
          "id",
          "decision",
          "version",
          "question_set_version",
          "model",
          "p",
          "answer",
          "reason_code",
          "reason",
          "evidence",
          "calibration",
          "cost",
          "balance_usd",
          "latency_ms",
          "created_at",
          "people"
        ],
        "description": "The `pick_person` decision envelope."
      },
      "PickPersonRequest": {
        "type": "object",
        "properties": {
          "roster": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/RosterEntry" },
            "minItems": 1,
            "maxItems": 50,
            "description": "The people to rank, 1 to 50."
          },
          "firm": { "$ref": "#/components/schemas/FirmReference" },
          "icp_id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The ICP profile to decide against.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "question": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500,
            "description": "Optional extra question, for example `who owns trading operations?`."
          }
        },
        "required": ["roster", "icp_id"],
        "additionalProperties": false,
        "description": "A roster of people at one firm, the ICP and an optional question."
      },
      "RosterEntry": {
        "type": "object",
        "properties": {
          "ref": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "Your own id for this person, echoed back in `people`."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Full name."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "Job title."
          },
          "seniority": {
            "type": "string",
            "enum": ["owner", "c_level", "vp", "director", "manager", "senior", "entry", "unknown"],
            "description": "Seniority, if known."
          },
          "department": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Department or function, for example `Operations`."
          },
          "location": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "City or country."
          },
          "tenure_months": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1200,
            "description": "Months in the current role."
          }
        },
        "required": ["name", "title"],
        "additionalProperties": false,
        "description": "One person at the firm. LinkedIn-sourced data is not accepted."
      },
      "TriageReplyResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The decision id. Report outcomes against it.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "decision": {
            "type": "string",
            "enum": ["triage_reply"],
            "description": "The decision name."
          },
          "version": {
            "type": "string",
            "enum": ["2026-11-01"],
            "description": "API version that served the decision."
          },
          "question_set_version": {
            "type": "string",
            "format": "date",
            "description": "Version (a date) of the question set that answered (spec 6.1)."
          },
          "model": {
            "type": "string",
            "enum": ["jev"],
            "description": "Decision model that answered: always `jev` (ADR-0008)."
          },
          "p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Calibrated probability (spec 6.4). Always present."
          },
          "answer": {
            "type": "string",
            "enum": [
              "interested",
              "meeting_requested",
              "question",
              "objection_price",
              "objection_timing",
              "objection_fit",
              "not_decision_maker",
              "referral",
              "out_of_office",
              "unsubscribe",
              "bounce",
              "wrong_person",
              "other",
              "needs_review"
            ],
            "description": "The `state` when `p` is at or above your threshold, otherwise `needs_review`."
          },
          "reason_code": {
            "type": "string",
            "enum": [
              "explicit_positive_intent",
              "explicit_meeting_request",
              "explicit_question",
              "explicit_objection",
              "explicit_opt_out",
              "redirect_to_other_person",
              "auto_reply_detected",
              "delivery_failure_detected",
              "ambiguous_reply",
              "thread_too_short"
            ],
            "description": "Why, from the fixed `triage_reply` reason-code enum."
          },
          "reason": {
            "type": "string",
            "description": "Short templated explanation of `reason_code`; never free text from a frontier model."
          },
          "evidence": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Evidence" },
            "description": "Cited sources, with URLs and dates."
          },
          "calibration": { "$ref": "#/components/schemas/Calibration" },
          "cost": { "$ref": "#/components/schemas/Cost" },
          "balance_usd": {
            "type": "number",
            "description": "Balance after this call. US dollars, up to 6 decimals."
          },
          "latency_ms": {
            "type": "integer",
            "minimum": 0,
            "description": "Server-side latency of the call, in milliseconds."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the decision was made. Decisions are immutable."
          },
          "state": {
            "type": "string",
            "enum": [
              "interested",
              "meeting_requested",
              "question",
              "objection_price",
              "objection_timing",
              "objection_fit",
              "not_decision_maker",
              "referral",
              "out_of_office",
              "unsubscribe",
              "bounce",
              "wrong_person",
              "other"
            ],
            "description": "The most likely state of the thread."
          },
          "next_action": {
            "type": "string",
            "enum": [
              "reply",
              "book_meeting",
              "answer_question",
              "handle_objection",
              "forward_to_referral",
              "find_other_contact",
              "retry_later",
              "unsubscribe",
              "stop",
              "escalate_to_human",
              "none"
            ],
            "description": "What the agent should do next."
          }
        },
        "required": [
          "id",
          "decision",
          "version",
          "question_set_version",
          "model",
          "p",
          "answer",
          "reason_code",
          "reason",
          "evidence",
          "calibration",
          "cost",
          "balance_usd",
          "latency_ms",
          "created_at",
          "state",
          "next_action"
        ],
        "description": "The `triage_reply` decision envelope."
      },
      "TriageReplyRequest": {
        "type": "object",
        "properties": {
          "thread": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ThreadMessage" },
            "minItems": 1,
            "maxItems": 40,
            "description": "The thread, oldest first, 1 to 40 messages; the last is the reply to triage."
          },
          "context": {
            "type": "object",
            "properties": {
              "decision_id": {
                "type": "string",
                "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The decision behind the original send.",
                "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "notes": {
                "type": "string",
                "minLength": 1,
                "maxLength": 2000,
                "description": "Short notes on what was offered. At most 2000 bytes of UTF-8."
              }
            },
            "additionalProperties": false,
            "description": "Optional context."
          },
          "icp_id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Optional ICP profile, for calibration by segment.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          }
        },
        "required": ["thread"],
        "additionalProperties": false,
        "description": "A reply thread and optional context."
      },
      "ThreadMessage": {
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "enum": ["sender", "prospect", "system"],
            "description": "Who wrote the message."
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8192,
            "description": "Plain-text body of the message. At most 8192 bytes of UTF-8."
          },
          "sent_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the message was sent."
          }
        },
        "required": ["role", "text", "sent_at"],
        "additionalProperties": false,
        "description": "One message of a thread, oldest first."
      },
      "RightPersonResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The decision id. Report outcomes against it.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "decision": {
            "type": "string",
            "enum": ["right_person"],
            "description": "The decision name."
          },
          "version": {
            "type": "string",
            "enum": ["2026-11-01"],
            "description": "API version that served the decision."
          },
          "question_set_version": {
            "type": "string",
            "format": "date",
            "description": "Version (a date) of the question set that answered (spec 6.1)."
          },
          "model": {
            "type": "string",
            "enum": ["jev"],
            "description": "Decision model that answered: always `jev` (ADR-0008)."
          },
          "p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Calibrated probability (spec 6.4). Always present."
          },
          "answer": {
            "type": "string",
            "enum": ["right_person", "not_right_person"],
            "description": "`right_person` or `not_right_person`: `p` applied to your threshold."
          },
          "reason_code": {
            "type": "string",
            "enum": [
              "title_and_seniority_match",
              "title_match_seniority_mismatch",
              "seniority_match_title_mismatch",
              "department_mismatch",
              "firm_not_in_icp",
              "candidate_data_stale",
              "insufficient_candidate_data"
            ],
            "description": "Why, from the fixed `right_person` reason-code enum."
          },
          "reason": {
            "type": "string",
            "description": "Short templated explanation of `reason_code`; never free text from a frontier model."
          },
          "evidence": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Evidence" },
            "description": "Cited sources, with URLs and dates."
          },
          "calibration": { "$ref": "#/components/schemas/Calibration" },
          "cost": { "$ref": "#/components/schemas/Cost" },
          "balance_usd": {
            "type": "number",
            "description": "Balance after this call. US dollars, up to 6 decimals."
          },
          "latency_ms": {
            "type": "integer",
            "minimum": 0,
            "description": "Server-side latency of the call, in milliseconds."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the decision was made. Decisions are immutable."
          }
        },
        "required": [
          "id",
          "decision",
          "version",
          "question_set_version",
          "model",
          "p",
          "answer",
          "reason_code",
          "reason",
          "evidence",
          "calibration",
          "cost",
          "balance_usd",
          "latency_ms",
          "created_at"
        ],
        "description": "The `right_person` decision envelope."
      },
      "RightPersonRequest": {
        "type": "object",
        "properties": {
          "candidate": { "$ref": "#/components/schemas/CandidateContact" },
          "icp_id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The ICP profile to decide against.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          }
        },
        "required": ["candidate", "icp_id"],
        "additionalProperties": false,
        "description": "A candidate contact and the ICP."
      },
      "CandidateContact": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Full name."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "Job title."
          },
          "seniority": {
            "type": "string",
            "enum": ["owner", "c_level", "vp", "director", "manager", "senior", "entry", "unknown"],
            "description": "Seniority, if known."
          },
          "department": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Department or function."
          },
          "email": {
            "type": "string",
            "maxLength": 254,
            "format": "email",
            "description": "Work email, if known."
          },
          "firm": { "$ref": "#/components/schemas/FirmReference" },
          "title_observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When you last saw this title, to judge staleness."
          }
        },
        "required": ["title"],
        "additionalProperties": false,
        "description": "One candidate contact. LinkedIn-sourced data is not accepted."
      },
      "ShouldSendResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The decision id. Report outcomes against it.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "decision": {
            "type": "string",
            "enum": ["should_send"],
            "description": "The decision name."
          },
          "version": {
            "type": "string",
            "enum": ["2026-11-01"],
            "description": "API version that served the decision."
          },
          "question_set_version": {
            "type": "string",
            "format": "date",
            "description": "Version (a date) of the question set that answered (spec 6.1)."
          },
          "model": {
            "type": "string",
            "enum": ["jev"],
            "description": "Decision model that answered: always `jev` (ADR-0008)."
          },
          "p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Calibrated probability (spec 6.4). Always present."
          },
          "answer": {
            "type": "string",
            "enum": ["send", "hold"],
            "description": "`send` or `hold`: `p` applied to your threshold."
          },
          "reason_code": {
            "type": "string",
            "enum": [
              "all_checks_passed",
              "upstream_decision_below_threshold",
              "upstream_decision_missing",
              "inbox_health_degraded",
              "daily_volume_limit_reached",
              "recipient_recently_contacted",
              "message_quality_issue",
              "recipient_opted_out"
            ],
            "description": "Why, from the fixed `should_send` reason-code enum."
          },
          "reason": {
            "type": "string",
            "description": "Short templated explanation of `reason_code`; never free text from a frontier model."
          },
          "evidence": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Evidence" },
            "description": "Cited sources, with URLs and dates."
          },
          "calibration": { "$ref": "#/components/schemas/Calibration" },
          "cost": { "$ref": "#/components/schemas/Cost" },
          "balance_usd": {
            "type": "number",
            "description": "Balance after this call. US dollars, up to 6 decimals."
          },
          "latency_ms": {
            "type": "integer",
            "minimum": 0,
            "description": "Server-side latency of the call, in milliseconds."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the decision was made. Decisions are immutable."
          },
          "send": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Probability that sending now is right; equal to `p`."
          },
          "hold_reason": {
            "type": ["string", "null"],
            "enum": [
              "upstream_decision_weak",
              "upstream_decision_missing",
              "inbox_health_degraded",
              "daily_volume_limit",
              "recently_contacted",
              "message_issue",
              "recipient_opted_out",
              "low_confidence",
              null
            ],
            "description": "Why to hold, when `answer` is `hold`; `null` when `answer` is `send`."
          }
        },
        "required": [
          "id",
          "decision",
          "version",
          "question_set_version",
          "model",
          "p",
          "answer",
          "reason_code",
          "reason",
          "evidence",
          "calibration",
          "cost",
          "balance_usd",
          "latency_ms",
          "created_at",
          "send",
          "hold_reason"
        ],
        "description": "The `should_send` decision envelope."
      },
      "ShouldSendRequest": {
        "type": "object",
        "properties": {
          "message": {
            "type": "object",
            "properties": {
              "channel": {
                "type": "string",
                "enum": ["email", "other"],
                "description": "Channel the message will go out on."
              },
              "subject": {
                "type": "string",
                "minLength": 1,
                "maxLength": 998,
                "description": "Subject line."
              },
              "body": {
                "type": "string",
                "minLength": 1,
                "maxLength": 8192,
                "description": "Plain-text body as it will be sent. At most 8192 bytes of UTF-8."
              }
            },
            "required": ["channel", "body"],
            "additionalProperties": false,
            "description": "The prepared message."
          },
          "decision_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "A decision behind the message.",
              "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "minItems": 1,
            "maxItems": 10,
            "description": "The decisions behind the message (for example `qualify_firm` and `pick_person`), 1 to 10."
          },
          "inbox_health": { "$ref": "#/components/schemas/InboxHealth" },
          "recipient": {
            "type": "object",
            "properties": {
              "last_contacted_at": {
                "type": "string",
                "format": "date-time",
                "description": "When you last wrote to this recipient."
              },
              "touches_30d": {
                "type": "integer",
                "minimum": 0,
                "description": "Messages sent to this recipient in 30 days."
              }
            },
            "additionalProperties": false,
            "description": "Optional contact history of the recipient."
          },
          "icp_id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The ICP profile to decide against.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          }
        },
        "required": ["message", "decision_ids", "inbox_health", "icp_id"],
        "additionalProperties": false,
        "description": "A prepared message, the decisions behind it, inbox health and the ICP."
      },
      "InboxHealth": {
        "type": "object",
        "properties": {
          "bounce_rate_7d": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Share of sends that bounced over the last 7 days."
          },
          "spam_complaint_rate_7d": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Share of sends marked as spam over the last 7 days."
          },
          "reply_rate_7d": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Share of sends replied to over the last 7 days."
          },
          "sent_today": {
            "type": "integer",
            "minimum": 0,
            "description": "Messages sent from this inbox today."
          },
          "daily_limit": {
            "type": "integer",
            "minimum": 1,
            "description": "Your daily send limit for this inbox."
          },
          "domain_age_days": {
            "type": "integer",
            "minimum": 0,
            "description": "Age of the sending domain in days."
          }
        },
        "additionalProperties": false,
        "description": "Inbox health you measure; Verdict never reads your inbox."
      },
      "Decision": {
        "oneOf": [
          { "$ref": "#/components/schemas/QualifyFirmResponse" },
          { "$ref": "#/components/schemas/ScoreSignalResponse" },
          { "$ref": "#/components/schemas/PickPersonResponse" },
          { "$ref": "#/components/schemas/TriageReplyResponse" },
          { "$ref": "#/components/schemas/RightPersonResponse" },
          { "$ref": "#/components/schemas/ShouldSendResponse" }
        ],
        "discriminator": {
          "propertyName": "decision",
          "mapping": {
            "qualify_firm": "#/components/schemas/QualifyFirmResponse",
            "score_signal": "#/components/schemas/ScoreSignalResponse",
            "pick_person": "#/components/schemas/PickPersonResponse",
            "triage_reply": "#/components/schemas/TriageReplyResponse",
            "right_person": "#/components/schemas/RightPersonResponse",
            "should_send": "#/components/schemas/ShouldSendResponse"
          }
        },
        "description": "A stored decision, exactly as it was returned; discriminated by `decision`."
      },
      "ResolveFirmResponse": {
        "type": "object",
        "properties": {
          "firm": { "$ref": "#/components/schemas/Firm" },
          "matched_on": {
            "type": "string",
            "enum": ["identifier", "domain", "name_and_country", "match_decision", "provisional"],
            "description": "How the reference was matched."
          }
        },
        "required": ["firm", "matched_on"],
        "description": "The resolved firm and how it was matched."
      },
      "Firm": {
        "allOf": [
          { "$ref": "#/components/schemas/FirmSummary" },
          {
            "type": "object",
            "properties": {
              "provisional": {
                "type": "boolean",
                "description": "True when the firm was created from an unresolved reference and awaits nightly reconciliation."
              },
              "crosswalk": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "domain",
                        "lei",
                        "cik",
                        "crd",
                        "companies_house",
                        "wikidata",
                        "name_variant"
                      ],
                      "description": "Identifier kind."
                    },
                    "value": { "type": "string", "description": "Identifier value." },
                    "source": {
                      "type": "string",
                      "enum": ["sec_edgar", "gleif", "companies_house", "wikidata", "request"],
                      "description": "Source that reported the identifier: an index source, or `request` when it came from a caller's reference (provisional firms)."
                    },
                    "observed_at": {
                      "type": "string",
                      "format": "date",
                      "description": "Date the source last reported the identifier."
                    }
                  },
                  "required": ["kind", "value", "source", "observed_at"]
                },
                "description": "Every known identifier, including name variants and secondary domains, with its source."
              },
              "created_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the firm entered the index."
              },
              "updated_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the firm's record last changed."
              }
            },
            "required": ["provisional", "crosswalk", "created_at", "updated_at"]
          }
        ],
        "description": "A canonical firm with its public facts and identifier crosswalk."
      },
      "Source": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^src_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The source id.",
            "example": "src_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "source": {
            "type": "string",
            "enum": ["sec_edgar", "gleif", "companies_house", "wikidata"],
            "description": "Stable source slug, as cited in `evidence[].source`."
          },
          "name": { "type": "string", "description": "Human name." },
          "phase": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2,
            "description": "Release phase that ships the source."
          },
          "license": {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "enum": ["public_domain", "cc0", "ogl_v3", "cc_by_4_0", "cc_by_3_0_au"],
                "description": "License kind."
              },
              "name": { "type": "string", "description": "License name." },
              "url": { "type": "string", "format": "uri", "description": "License text." },
              "attribution": {
                "type": ["string", "null"],
                "description": "Attribution text to show when you display the data, if required."
              }
            },
            "required": ["kind", "name", "url", "attribution"],
            "description": "The source's license."
          },
          "refresh_cadence": {
            "type": "string",
            "description": "How often Verdict refreshes it, for example `daily`."
          },
          "rate_limit": {
            "type": ["string", "null"],
            "description": "The source's fair-access limit Verdict observes."
          },
          "last_successful_run": {
            "type": ["object", "null"],
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^run_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The run id.",
                "example": "run_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "status": {
                "type": "string",
                "enum": ["running", "succeeded", "partial", "failed"],
                "description": "Run status."
              },
              "started_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the run started."
              },
              "finished_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the run finished."
              },
              "events_upserted": {
                "type": "integer",
                "minimum": 0,
                "description": "Events inserted or updated."
              }
            },
            "required": ["id", "status", "started_at", "finished_at", "events_upserted"],
            "description": "Latest successful ingestion, or `null` if none yet."
          },
          "last_run": {
            "type": ["object", "null"],
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^run_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The run id.",
                "example": "run_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "status": {
                "type": "string",
                "enum": ["running", "succeeded", "partial", "failed"],
                "description": "Run status."
              },
              "started_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the run started."
              },
              "finished_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the run finished."
              },
              "events_upserted": {
                "type": "integer",
                "minimum": 0,
                "description": "Events inserted or updated."
              }
            },
            "required": ["id", "status", "started_at", "finished_at", "events_upserted"],
            "description": "Latest ingestion run of any status (it may still be running or have failed), or `null` if none yet."
          },
          "freshness_seconds": {
            "type": ["integer", "null"],
            "minimum": 0,
            "description": "Seconds since the latest successful run finished: how fresh this source's data is. `null` if it has never succeeded.",
            "example": 7200
          }
        },
        "required": [
          "id",
          "source",
          "name",
          "phase",
          "license",
          "refresh_cadence",
          "rate_limit",
          "last_successful_run",
          "last_run",
          "freshness_seconds"
        ],
        "description": "An open-licensed source of Verdict's index."
      },
      "CreatedWatch": {
        "allOf": [
          { "$ref": "#/components/schemas/Watch" },
          {
            "type": "object",
            "properties": {
              "signing_secret": {
                "type": "string",
                "pattern": "^whsec_[A-Za-z0-9]{32,64}$",
                "description": "Secret for verifying `Verdict-Signature` on deliveries. Shown once; store it now."
              }
            },
            "required": ["signing_secret"]
          }
        ],
        "description": "A new watch and its signing secret (shown once)."
      },
      "Watch": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^wch_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The watch id.",
            "example": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "project_id": {
            "type": "string",
            "pattern": "^prj_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Project the watch belongs to.",
            "example": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "icp_id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "ICP profile events are scored for.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "webhook_url": { "type": "string", "format": "uri", "description": "Delivery endpoint." },
          "min_p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Minimum `relevant` delivered."
          },
          "types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "filing",
                "registration",
                "officer_change",
                "ownership_change",
                "lei_change",
                "address_change",
                "fund_raise",
                "insider_trade",
                "patent_filing",
                "litigation",
                "news_mention",
                "repo_activity",
                "hiring_aggregate"
              ],
              "description": "An event type."
            },
            "description": "Event types watched."
          },
          "status": {
            "type": "string",
            "enum": ["pending_verification", "active", "paused", "deleted"],
            "description": "Lifecycle status."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the watch was created."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the watch last changed."
          }
        },
        "required": [
          "id",
          "project_id",
          "icp_id",
          "webhook_url",
          "min_p",
          "types",
          "status",
          "created_at",
          "updated_at"
        ],
        "description": "A standing scored-event subscription."
      },
      "CreateWatchRequest": {
        "type": "object",
        "properties": {
          "icp_id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Score events for this ICP profile.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "webhook_url": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri",
            "description": "HTTPS endpoint that receives deliveries. Private and link-local addresses are refused; the URL must answer a challenge at registration."
          },
          "min_p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Deliver only events whose `relevant` is at least this."
          },
          "types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "filing",
                "registration",
                "officer_change",
                "ownership_change",
                "lei_change",
                "address_change",
                "fund_raise",
                "insider_trade",
                "patent_filing",
                "litigation",
                "news_mention",
                "repo_activity",
                "hiring_aggregate"
              ],
              "description": "An event type."
            },
            "minItems": 1,
            "maxItems": 13,
            "description": "Event types to watch."
          }
        },
        "required": ["icp_id", "webhook_url", "min_p", "types"],
        "additionalProperties": false,
        "description": "A standing request for scored events, delivered by webhook."
      },
      "Delivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^dlv_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The delivery id; also the `id` of the delivered payload.",
            "example": "dlv_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "watch_id": {
            "type": "string",
            "pattern": "^wch_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The watch.",
            "example": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "event_id": {
            "type": "string",
            "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The delivered event.",
            "example": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "decision_id": {
            "type": ["string", "null"],
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The `score_signal` decision behind it.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "status": {
            "type": "string",
            "enum": ["pending", "retrying", "delivered", "failed"],
            "description": "Delivery status."
          },
          "attempts": { "type": "integer", "minimum": 0, "description": "Attempts so far." },
          "last_attempt_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Time of the last attempt."
          },
          "last_response_status": {
            "type": ["integer", "null"],
            "description": "HTTP status of the last attempt, if a response arrived."
          },
          "next_attempt_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Time of the next retry, while `retrying`."
          },
          "delivered_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When a 2xx was received."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the delivery was queued."
          }
        },
        "required": [
          "id",
          "watch_id",
          "event_id",
          "decision_id",
          "status",
          "attempts",
          "last_attempt_at",
          "last_response_status",
          "next_attempt_at",
          "delivered_at",
          "created_at"
        ],
        "description": "One webhook delivery of one scored event. Billed once, when delivered."
      },
      "Outcome": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^out_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The outcome id.",
            "example": "out_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "decision_id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The decision it belongs to.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "outcome": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "bounced",
                  "delivered",
                  "replied",
                  "interested",
                  "not_interested",
                  "meeting_booked",
                  "meeting_held",
                  "approved",
                  "skipped",
                  "reopened",
                  "converted"
                ],
                "description": "A built-in outcome type."
              },
              {
                "type": "string",
                "pattern": "^custom:[a-z][a-z0-9_]{0,62}$",
                "description": "A custom outcome, `custom:<slug>` (lowercase letters, digits, underscores).",
                "example": "custom:demo_completed"
              }
            ],
            "description": "The outcome: a built-in type or `custom:<slug>`."
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the outcome happened."
          },
          "meta": {
            "type": ["object", "null"],
            "additionalProperties": {
              "anyOf": [
                { "type": "string", "maxLength": 500 },
                { "type": "number" },
                { "type": "boolean" }
              ],
              "description": "A scalar value."
            },
            "description": "Optional metadata: up to 20 keys of at most 64 characters, scalar values. No personal data."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When Verdict recorded it."
          }
        },
        "required": ["id", "decision_id", "outcome", "observed_at", "meta", "created_at"],
        "description": "A recorded outcome."
      },
      "CreateOutcomeRequest": {
        "type": "object",
        "properties": {
          "decision_id": {
            "type": "string",
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The decision the outcome belongs to.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "outcome": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "bounced",
                  "delivered",
                  "replied",
                  "interested",
                  "not_interested",
                  "meeting_booked",
                  "meeting_held",
                  "approved",
                  "skipped",
                  "reopened",
                  "converted"
                ],
                "description": "A built-in outcome type."
              },
              {
                "type": "string",
                "pattern": "^custom:[a-z][a-z0-9_]{0,62}$",
                "description": "A custom outcome, `custom:<slug>` (lowercase letters, digits, underscores).",
                "example": "custom:demo_completed"
              }
            ],
            "description": "The outcome: a built-in type or `custom:<slug>`."
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the outcome happened."
          },
          "meta": {
            "type": "object",
            "additionalProperties": {
              "anyOf": [
                { "type": "string", "maxLength": 500 },
                { "type": "number" },
                { "type": "boolean" }
              ],
              "description": "A scalar value."
            },
            "description": "Optional metadata: up to 20 keys of at most 64 characters, scalar values. No personal data."
          }
        },
        "required": ["decision_id", "outcome", "observed_at"],
        "additionalProperties": false,
        "description": "An outcome for one decision."
      },
      "WebhookReceipt": {
        "type": "object",
        "properties": {
          "received": {
            "type": "boolean",
            "enum": [true],
            "description": "The payload was verified and accepted."
          },
          "duplicate": {
            "type": "boolean",
            "description": "True when this vendor event id was already processed."
          },
          "outcome_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^out_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "An outcome created.",
              "example": "out_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "description": "Outcomes created from the payload; empty when it maps to none."
          }
        },
        "required": ["received", "duplicate", "outcome_ids"],
        "description": "Acknowledgement of a vendor webhook."
      },
      "VendorWebhookBody": {
        "type": "object",
        "additionalProperties": { "description": "A vendor-defined value." },
        "description": "The vendor's webhook payload, unchanged. Its shape is defined by the vendor."
      },
      "Icp": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The ICP profile id.",
            "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "project_id": {
            "type": "string",
            "pattern": "^prj_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Project the profile belongs to.",
            "example": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "name": { "type": "string", "description": "Name." },
          "description": { "type": "string", "description": "Plain-text description." },
          "filters": { "$ref": "#/components/schemas/IcpFilters" },
          "segment": {
            "type": "object",
            "properties": {
              "industry_group": {
                "type": ["string", "null"],
                "description": "Industry group assigned at summarization."
              },
              "size_band": {
                "type": ["string", "null"],
                "enum": ["micro", "small", "medium", "large", "enterprise", "unknown", null],
                "description": "Size band assigned at summarization."
              }
            },
            "required": ["industry_group", "size_band"],
            "description": "Calibration segment of the profile (spec 6.4)."
          },
          "summary_status": {
            "type": "string",
            "enum": ["pending", "ready", "failed"],
            "description": "Status of the one-time summarization."
          },
          "thresholds": { "$ref": "#/components/schemas/Thresholds" },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the profile was created."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the profile last changed."
          }
        },
        "required": [
          "id",
          "project_id",
          "name",
          "description",
          "filters",
          "segment",
          "summary_status",
          "thresholds",
          "created_at",
          "updated_at"
        ],
        "description": "An ICP profile: who you sell to and what you sell."
      },
      "IcpFilters": {
        "type": "object",
        "properties": {
          "firm_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "operating_company",
                "investment_adviser",
                "broker_dealer",
                "investment_fund",
                "nonprofit",
                "public_body",
                "other",
                "unknown"
              ],
              "description": "A firm type."
            },
            "maxItems": 8,
            "description": "Firm types to target."
          },
          "size_bands": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["micro", "small", "medium", "large", "enterprise", "unknown"],
              "description": "A size band."
            },
            "maxItems": 6,
            "description": "Size bands to target."
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[A-Z]{2}$",
              "description": "A country.",
              "example": "US"
            },
            "maxItems": 250,
            "description": "Headquarters countries to target."
          },
          "exclude_countries": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[A-Z]{2}$",
              "description": "A country.",
              "example": "US"
            },
            "maxItems": 250,
            "description": "Headquarters countries to exclude."
          },
          "exclude_domains": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+[A-Za-z]{2,63}$",
              "description": "A domain.",
              "example": "northfieldcapital.com"
            },
            "maxItems": 1000,
            "description": "Firms to exclude by domain (for example existing customers)."
          },
          "event_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "filing",
                "registration",
                "officer_change",
                "ownership_change",
                "lei_change",
                "address_change",
                "fund_raise",
                "insider_trade",
                "patent_filing",
                "litigation",
                "news_mention",
                "repo_activity",
                "hiring_aggregate"
              ],
              "description": "An event type."
            },
            "maxItems": 13,
            "description": "Event types that signal buying intent for this ICP."
          }
        },
        "additionalProperties": false,
        "description": "Optional structured filters that sharpen the plain-text profile."
      },
      "Thresholds": {
        "type": "object",
        "properties": {
          "qualify_firm": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "The threshold `answer` applies to `p`."
              },
              "source": {
                "type": "string",
                "enum": ["calibrated", "custom"],
                "description": "Calibrated default or your own value."
              }
            },
            "required": ["value", "source"],
            "description": "Threshold for `qualify_firm`."
          },
          "score_signal": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "The threshold `answer` applies to `p`."
              },
              "source": {
                "type": "string",
                "enum": ["calibrated", "custom"],
                "description": "Calibrated default or your own value."
              }
            },
            "required": ["value", "source"],
            "description": "Threshold for `score_signal`."
          },
          "pick_person": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "The threshold `answer` applies to `p`."
              },
              "source": {
                "type": "string",
                "enum": ["calibrated", "custom"],
                "description": "Calibrated default or your own value."
              }
            },
            "required": ["value", "source"],
            "description": "Threshold for `pick_person`."
          },
          "triage_reply": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "The threshold `answer` applies to `p`."
              },
              "source": {
                "type": "string",
                "enum": ["calibrated", "custom"],
                "description": "Calibrated default or your own value."
              }
            },
            "required": ["value", "source"],
            "description": "Threshold for `triage_reply`."
          },
          "right_person": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "The threshold `answer` applies to `p`."
              },
              "source": {
                "type": "string",
                "enum": ["calibrated", "custom"],
                "description": "Calibrated default or your own value."
              }
            },
            "required": ["value", "source"],
            "description": "Threshold for `right_person`."
          },
          "should_send": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "The threshold `answer` applies to `p`."
              },
              "source": {
                "type": "string",
                "enum": ["calibrated", "custom"],
                "description": "Calibrated default or your own value."
              }
            },
            "required": ["value", "source"],
            "description": "Threshold for `should_send`."
          }
        },
        "required": [
          "qualify_firm",
          "score_signal",
          "pick_person",
          "triage_reply",
          "right_person",
          "should_send"
        ],
        "description": "Decision thresholds, one per decision."
      },
      "CreateIcpRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Short name, for example `RIAs under $1B`."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8192,
            "description": "Plain-text description of who you sell to and what you sell. At most 8192 bytes of UTF-8."
          },
          "filters": { "$ref": "#/components/schemas/IcpFilters" },
          "project_id": {
            "type": "string",
            "pattern": "^prj_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Project to create the profile in; defaults to the key's project.",
            "example": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          }
        },
        "required": ["name", "description"],
        "additionalProperties": false,
        "description": "A new ICP profile."
      },
      "UpdateIcpRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "New name."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8192,
            "description": "New plain-text description; re-runs summarization. At most 8192 bytes of UTF-8."
          },
          "filters": { "$ref": "#/components/schemas/IcpFilters" }
        },
        "additionalProperties": false,
        "description": "Fields of an ICP profile to change."
      },
      "UpdateThresholdsRequest": {
        "type": "object",
        "properties": {
          "thresholds": {
            "type": "object",
            "properties": {
              "qualify_firm": {
                "type": ["number", "null"],
                "minimum": 0,
                "maximum": 1,
                "description": "New threshold for `qualify_firm`, or `null` to return to the calibrated default."
              },
              "score_signal": {
                "type": ["number", "null"],
                "minimum": 0,
                "maximum": 1,
                "description": "New threshold for `score_signal`, or `null` to return to the calibrated default."
              },
              "pick_person": {
                "type": ["number", "null"],
                "minimum": 0,
                "maximum": 1,
                "description": "New threshold for `pick_person`, or `null` to return to the calibrated default."
              },
              "triage_reply": {
                "type": ["number", "null"],
                "minimum": 0,
                "maximum": 1,
                "description": "New threshold for `triage_reply`, or `null` to return to the calibrated default."
              },
              "right_person": {
                "type": ["number", "null"],
                "minimum": 0,
                "maximum": 1,
                "description": "New threshold for `right_person`, or `null` to return to the calibrated default."
              },
              "should_send": {
                "type": ["number", "null"],
                "minimum": 0,
                "maximum": 1,
                "description": "New threshold for `should_send`, or `null` to return to the calibrated default."
              }
            },
            "additionalProperties": false,
            "description": "Thresholds to change, by decision name."
          }
        },
        "required": ["thresholds"],
        "additionalProperties": false,
        "description": "Set or reset decision thresholds on an ICP profile."
      },
      "SignupResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["verification_sent"],
            "description": "A verification email was sent."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "The address it was sent to."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the verification link expires."
          }
        },
        "required": ["status", "email", "expires_at"],
        "description": "Sign-up accepted; verify the email to get a key."
      },
      "SignupRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "maxLength": 254,
            "format": "email",
            "description": "Work email. A verification link is sent to it; disposable domains are refused."
          },
          "org_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Organization name; defaults to the email's domain."
          }
        },
        "required": ["email"],
        "additionalProperties": false,
        "description": "Start sign-up with an email address."
      },
      "VerifySignupResponse": {
        "type": "object",
        "properties": {
          "org_id": {
            "type": "string",
            "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The new organization.",
            "example": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "project_id": {
            "type": "string",
            "pattern": "^prj_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Its default project.",
            "example": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "key": { "$ref": "#/components/schemas/CreatedApiKey" },
          "starter_credit_usd": {
            "type": "number",
            "minimum": 0,
            "description": "Starter credits granted. US dollars, up to 6 decimals."
          },
          "balance_usd": {
            "type": "number",
            "description": "Balance after the grant. US dollars, up to 6 decimals."
          }
        },
        "required": ["org_id", "project_id", "key", "starter_credit_usd", "balance_usd"],
        "description": "The organization, project and first key."
      },
      "CreatedApiKey": {
        "allOf": [
          { "$ref": "#/components/schemas/ApiKey" },
          {
            "type": "object",
            "properties": {
              "secret": {
                "type": "string",
                "description": "The API key: `vd_live_` or `vd_test_` plus a base62 body. Shown once; store it now."
              }
            },
            "required": ["secret"]
          }
        ],
        "description": "A new API key with its secret (shown once)."
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The key id.",
            "example": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "project_id": {
            "type": "string",
            "pattern": "^prj_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Project the key belongs to.",
            "example": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "name": { "type": "string", "description": "Name." },
          "environment": {
            "type": "string",
            "enum": ["live", "test"],
            "description": "`live` or `test`."
          },
          "prefix": {
            "type": "string",
            "pattern": "^vd_(?:live|test)_[A-Za-z0-9]{6}$",
            "description": "The key's first characters, to recognize it."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "decisions:write",
                "index:read",
                "outcomes:write",
                "watches:manage",
                "vendors:call",
                "account:read",
                "account:manage",
                "keys:manage"
              ],
              "description": "A scope."
            },
            "description": "Scopes granted."
          },
          "status": {
            "type": "string",
            "enum": ["active", "rotating", "revoked", "expired"],
            "description": "Lifecycle status."
          },
          "rate_limit_per_minute": {
            "type": "integer",
            "minimum": 1,
            "description": "Requests per minute allowed."
          },
          "daily_spend_cap_usd": {
            "type": ["number", "null"],
            "minimum": 0,
            "description": "Daily spend cap, or `null` for none. US dollars, up to 6 decimals."
          },
          "ip_allowlist": {
            "type": "array",
            "items": { "type": "string", "description": "A CIDR block." },
            "description": "CIDR blocks the key may be used from; empty means anywhere."
          },
          "expires_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Expiry, or `null` for none."
          },
          "last_used_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Last successful use, or `null`."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the key was created."
          }
        },
        "required": [
          "id",
          "project_id",
          "name",
          "environment",
          "prefix",
          "scopes",
          "status",
          "rate_limit_per_minute",
          "daily_spend_cap_usd",
          "ip_allowlist",
          "expires_at",
          "last_used_at",
          "created_at"
        ],
        "description": "An API key's metadata."
      },
      "VerifySignupRequest": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "minLength": 32,
            "maxLength": 256,
            "description": "The token from the verification link."
          }
        },
        "required": ["token"],
        "additionalProperties": false,
        "description": "Complete sign-up with the emailed token."
      },
      "MeResponse": {
        "type": "object",
        "properties": {
          "org": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Organization id.",
                "example": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "name": { "type": "string", "description": "Organization name." },
              "created_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the organization was created."
              }
            },
            "required": ["id", "name", "created_at"],
            "description": "The calling key's organization."
          },
          "project": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^prj_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Project id.",
                "example": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "name": { "type": "string", "description": "Project name." }
            },
            "required": ["id", "name"],
            "description": "The calling key's project."
          },
          "key": { "$ref": "#/components/schemas/ApiKey" },
          "api_version": {
            "type": "string",
            "enum": ["2026-11-01"],
            "description": "API version this key uses by default."
          }
        },
        "required": ["org", "project", "key", "api_version"],
        "description": "Who the calling key is."
      },
      "CreateKeyRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Name, for example `outbound-agent prod`."
          },
          "project_id": {
            "type": "string",
            "pattern": "^prj_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Project; defaults to the calling key's project.",
            "example": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "environment": {
            "type": "string",
            "enum": ["live", "test"],
            "description": "`live` (default) or `test`."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "decisions:write",
                "index:read",
                "outcomes:write",
                "watches:manage",
                "vendors:call",
                "account:read",
                "account:manage",
                "keys:manage"
              ],
              "description": "A scope."
            },
            "minItems": 1,
            "maxItems": 8,
            "description": "Scopes; default `decisions:write`, `index:read`, `outcomes:write`."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Expiry; default none."
          },
          "rate_limit_per_minute": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000,
            "description": "Requests per minute; default 600."
          },
          "daily_spend_cap_usd": {
            "type": "number",
            "minimum": 0,
            "description": "Daily spend cap; default none. US dollars, up to 6 decimals."
          },
          "ip_allowlist": {
            "type": "array",
            "items": {
              "anyOf": [
                { "type": "string", "format": "ipv4-cidr" },
                { "type": "string", "format": "ipv6-cidr" }
              ],
              "description": "An IPv4 or IPv6 CIDR block."
            },
            "maxItems": 50,
            "description": "CIDR blocks the key may be used from; default anywhere."
          }
        },
        "required": ["name"],
        "additionalProperties": false,
        "description": "A new API key."
      },
      "RotateKeyResponse": {
        "type": "object",
        "properties": {
          "key": { "$ref": "#/components/schemas/CreatedApiKey" },
          "previous_key": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The rotated key.",
                "example": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "valid_until": {
                "type": "string",
                "format": "date-time",
                "description": "When the old key stops working."
              }
            },
            "required": ["id", "valid_until"],
            "description": "The old key and the end of its grace window."
          }
        },
        "required": ["key", "previous_key"],
        "description": "The replacement key (secret shown once) and the old key's grace window."
      },
      "RotateKeyRequest": {
        "type": "object",
        "properties": {
          "grace_period_hours": {
            "type": "integer",
            "minimum": 0,
            "maximum": 168,
            "description": "Hours the old key stays valid; default 24."
          }
        },
        "additionalProperties": false,
        "description": "Rotation options."
      },
      "LimitsResponse": {
        "type": "object",
        "properties": {
          "rate_limit": {
            "type": "object",
            "properties": {
              "requests_per_minute": {
                "type": "integer",
                "description": "Requests per minute for this key."
              },
              "burst": { "type": "integer", "description": "Burst allowance." }
            },
            "required": ["requests_per_minute", "burst"],
            "description": "Rate limit of the calling key."
          },
          "daily_spend_cap_usd": {
            "type": ["number", "null"],
            "minimum": 0,
            "description": "Daily spend cap of the key, or `null`. US dollars, up to 6 decimals."
          },
          "spent_today_usd": {
            "type": "number",
            "minimum": 0,
            "description": "Spent today (UTC) by the key. US dollars, up to 6 decimals."
          },
          "request_limits": {
            "type": "object",
            "properties": {
              "max_body_bytes": { "type": "integer", "description": "Maximum request body size." },
              "max_roster_entries": {
                "type": "integer",
                "description": "Maximum `pick_person` roster size."
              },
              "max_thread_messages": {
                "type": "integer",
                "description": "Maximum `triage_reply` thread length."
              },
              "max_message_bytes": {
                "type": "integer",
                "description": "Maximum bytes per message."
              },
              "max_page_limit": {
                "type": "integer",
                "description": "Maximum `limit` on list endpoints."
              }
            },
            "required": [
              "max_body_bytes",
              "max_roster_entries",
              "max_thread_messages",
              "max_message_bytes",
              "max_page_limit"
            ],
            "description": "Request size limits (spec 9.4)."
          },
          "starter": {
            "type": "object",
            "properties": {
              "card_required": {
                "type": "boolean",
                "description": "Whether a card is now required to keep calling."
              },
              "free_usd_remaining": {
                "type": "number",
                "minimum": 0,
                "description": "Starter credit left before a card is required. US dollars, up to 6 decimals."
              },
              "free_calls_remaining": {
                "type": "integer",
                "minimum": 0,
                "description": "Calls left before a card is required."
              }
            },
            "required": ["card_required", "free_usd_remaining", "free_calls_remaining"],
            "description": "Starter allowance (spec 9.1): a card is required past $5 or 1,000 calls."
          }
        },
        "required": [
          "rate_limit",
          "daily_spend_cap_usd",
          "spent_today_usd",
          "request_limits",
          "starter"
        ],
        "description": "Limits that apply to the calling key."
      },
      "AuditEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^aud_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The audit entry id.",
            "example": "aud_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "action": {
            "type": "string",
            "enum": [
              "key_created",
              "key_rotated",
              "key_revoked",
              "key_scopes_changed",
              "member_added",
              "member_removed",
              "member_role_changed",
              "threshold_changed",
              "vendor_key_added",
              "vendor_key_removed",
              "webhook_endpoint_created",
              "webhook_endpoint_deleted",
              "webhook_secret_rotated",
              "topup_created",
              "topup_completed",
              "export_requested",
              "deletion_requested",
              "key_updated",
              "member_invited",
              "totp_enabled",
              "totp_disabled"
            ],
            "description": "What happened."
          },
          "actor": {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "enum": ["user", "key", "system"],
                "description": "Kind of actor."
              },
              "id": {
                "anyOf": [
                  {
                    "type": "string",
                    "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                    "description": "A user id.",
                    "example": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
                  },
                  {
                    "type": "string",
                    "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                    "description": "An API key id.",
                    "example": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
                  },
                  { "type": "null" }
                ],
                "description": "The `usr_` or `key_` id, or `null` for `system`."
              },
              "role": {
                "type": ["string", "null"],
                "enum": ["owner", "admin", "developer", "billing", "read_only", null],
                "description": "The user's role at the time, for `user` actors."
              }
            },
            "required": ["kind", "id", "role"],
            "description": "Who did it."
          },
          "target": {
            "type": ["object", "null"],
            "properties": {
              "type": {
                "type": "string",
                "description": "Kind of resource, for example `key` or `icp`."
              },
              "id": { "type": "string", "description": "The resource id." }
            },
            "required": ["type", "id"],
            "description": "What it was done to, if a single resource."
          },
          "ip": {
            "type": ["string", "null"],
            "description": "Client IP address, if the action came over the network."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "anyOf": [
                { "type": "string" },
                { "type": "number" },
                { "type": "boolean" },
                { "type": "null" }
              ],
              "description": "A scalar value."
            },
            "description": "Action details (for example old and new scopes). Never secrets."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened."
          }
        },
        "required": ["id", "action", "actor", "target", "ip", "metadata", "created_at"],
        "description": "One append-only audit log entry."
      },
      "BalanceResponse": {
        "type": "object",
        "properties": {
          "balance_usd": {
            "type": "number",
            "description": "Cash balance (live keys). US dollars, up to 6 decimals."
          },
          "test_balance_usd": {
            "type": "number",
            "description": "Non-cash test balance (test keys). US dollars, up to 6 decimals."
          },
          "auto_topup": {
            "type": "object",
            "properties": {
              "enabled": { "type": "boolean", "description": "Whether auto top-up is on." },
              "threshold_usd": {
                "type": ["number", "null"],
                "minimum": 0,
                "description": "Balance that triggers a top-up. US dollars, up to 6 decimals."
              },
              "pack_usd": {
                "anyOf": [
                  { "type": "number", "enum": [20] },
                  { "type": "number", "enum": [50] },
                  { "type": "number", "enum": [200] },
                  { "type": "null" }
                ],
                "description": "Pack bought on trigger."
              }
            },
            "required": ["enabled", "threshold_usd", "pack_usd"],
            "description": "Auto top-up settings (optional, phase 2)."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "When the balance was read."
          }
        },
        "required": ["balance_usd", "test_balance_usd", "auto_topup", "as_of"],
        "description": "Current balances."
      },
      "TopupResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^pck_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The pack purchase id.",
            "example": "pck_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "pack_usd": {
            "anyOf": [
              { "type": "number", "enum": [20] },
              { "type": "number", "enum": [50] },
              { "type": "number", "enum": [200] }
            ],
            "description": "Pack size."
          },
          "status": {
            "type": "string",
            "enum": ["pending", "completed", "expired", "failed"],
            "description": "Purchase status."
          },
          "checkout_url": {
            "type": "string",
            "format": "uri",
            "description": "Stripe Checkout URL; open it to pay. The balance is credited when Stripe confirms payment."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the Checkout session expires."
          }
        },
        "required": ["id", "pack_usd", "status", "checkout_url", "expires_at"],
        "description": "A pending pack purchase with its Checkout URL."
      },
      "TopupRequest": {
        "type": "object",
        "properties": {
          "pack_usd": {
            "anyOf": [
              { "type": "number", "enum": [20] },
              { "type": "number", "enum": [50] },
              { "type": "number", "enum": [200] }
            ],
            "description": "Pack to buy: 20, 50 or 200 US dollars."
          }
        },
        "required": ["pack_usd"],
        "additionalProperties": false,
        "description": "The pack to buy."
      },
      "UsageResponse": {
        "type": "object",
        "properties": {
          "from": { "type": "string", "format": "date", "description": "First day included." },
          "to": { "type": "string", "format": "date", "description": "Last day included." },
          "group_by": {
            "type": "string",
            "enum": ["day", "project", "key", "decision"],
            "description": "Grouping used."
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "calls": { "type": "integer", "minimum": 0, "description": "Calls made." },
                "billed_calls": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Calls billed (misses and errors are free)."
                },
                "decision_usd": {
                  "type": "number",
                  "minimum": 0,
                  "description": "Decision charges. US dollars, up to 6 decimals."
                },
                "vendor_usd": {
                  "type": "number",
                  "minimum": 0,
                  "description": "Vendor pass-through charges. US dollars, up to 6 decimals."
                },
                "total_usd": {
                  "type": "number",
                  "minimum": 0,
                  "description": "Total charges. US dollars, up to 6 decimals."
                },
                "group": {
                  "type": "string",
                  "description": "Group key: a date, project id, key id or decision name."
                }
              },
              "required": [
                "calls",
                "billed_calls",
                "decision_usd",
                "vendor_usd",
                "total_usd",
                "group"
              ]
            },
            "description": "One row per group."
          },
          "totals": {
            "type": "object",
            "properties": {
              "calls": { "type": "integer", "minimum": 0, "description": "Calls made." },
              "billed_calls": {
                "type": "integer",
                "minimum": 0,
                "description": "Calls billed (misses and errors are free)."
              },
              "decision_usd": {
                "type": "number",
                "minimum": 0,
                "description": "Decision charges. US dollars, up to 6 decimals."
              },
              "vendor_usd": {
                "type": "number",
                "minimum": 0,
                "description": "Vendor pass-through charges. US dollars, up to 6 decimals."
              },
              "total_usd": {
                "type": "number",
                "minimum": 0,
                "description": "Total charges. US dollars, up to 6 decimals."
              }
            },
            "required": ["calls", "billed_calls", "decision_usd", "vendor_usd", "total_usd"],
            "description": "Totals over the window; equal to the ledger sums."
          }
        },
        "required": ["from", "to", "group_by", "rows", "totals"],
        "description": "Usage over a window."
      },
      "LedgerEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^led_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The ledger entry id.",
            "example": "led_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "kind": {
            "type": "string",
            "enum": [
              "starter_credit",
              "pack_credit",
              "auto_topup_credit",
              "promotional_credit",
              "decision_debit",
              "vendor_debit",
              "refund",
              "adjustment"
            ],
            "description": "Entry kind."
          },
          "environment": {
            "type": "string",
            "enum": ["live", "test"],
            "description": "`live` (cash) or `test` balance."
          },
          "amount_usd": {
            "type": "number",
            "description": "Signed amount: credits positive, debits negative. US dollars, up to 6 decimals."
          },
          "balance_after_usd": {
            "type": "number",
            "description": "Balance after the entry. US dollars, up to 6 decimals."
          },
          "decision_id": {
            "type": ["string", "null"],
            "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Decision billed, for debits.",
            "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "pack_id": {
            "type": ["string", "null"],
            "pattern": "^pck_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Pack credited, for pack credits.",
            "example": "pck_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "description": { "type": "string", "description": "Human description." },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the entry was written."
          }
        },
        "required": [
          "id",
          "kind",
          "environment",
          "amount_usd",
          "balance_after_usd",
          "decision_id",
          "pack_id",
          "description",
          "created_at"
        ],
        "description": "One ledger entry."
      },
      "StripeWebhookReceipt": {
        "type": "object",
        "properties": {
          "received": {
            "type": "boolean",
            "enum": [true],
            "description": "The event was verified and recorded."
          },
          "duplicate": {
            "type": "boolean",
            "description": "True when this Stripe event id was already recorded; nothing changed."
          }
        },
        "required": ["received", "duplicate"],
        "description": "Acknowledgement of a Stripe event."
      },
      "StripeWebhookBody": {
        "type": "object",
        "additionalProperties": { "description": "A Stripe-defined value." },
        "description": "A Stripe event object (`id` `evt_...`, `type`, `data.object`), exactly as Stripe sends it. Its shape is defined by Stripe."
      },
      "UpdateKeyRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "New name."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "decisions:write",
                "index:read",
                "outcomes:write",
                "watches:manage",
                "vendors:call",
                "account:read",
                "account:manage",
                "keys:manage"
              ],
              "description": "A scope."
            },
            "minItems": 1,
            "maxItems": 8,
            "description": "Replacement scopes. A key can only grant scopes the calling key holds itself. Audited as `key_scopes_changed`."
          },
          "rate_limit_per_minute": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000,
            "description": "Requests per minute."
          },
          "daily_spend_cap_usd": {
            "type": ["number", "null"],
            "minimum": 0,
            "description": "Daily spend cap; `null` removes it. US dollars, up to 6 decimals."
          },
          "ip_allowlist": {
            "type": "array",
            "items": {
              "anyOf": [
                { "type": "string", "format": "ipv4-cidr" },
                { "type": "string", "format": "ipv6-cidr" }
              ],
              "description": "An IPv4 or IPv6 CIDR block."
            },
            "maxItems": 50,
            "description": "CIDR blocks the key may be used from; empty means anywhere."
          },
          "expires_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Expiry; `null` removes it."
          }
        },
        "additionalProperties": false,
        "description": "Fields of an API key to change."
      },
      "MagicLinkResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["sent"],
            "description": "Always `sent`, whether or not the address has an account, so the endpoint does not reveal which emails are registered."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When a link sent now expires."
          }
        },
        "required": ["status", "expires_at"],
        "description": "A sign-in link was sent if the account exists."
      },
      "MagicLinkRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "maxLength": 254,
            "format": "email",
            "description": "The email of an existing Verdict user."
          }
        },
        "required": ["email"],
        "additionalProperties": false,
        "description": "Ask for a sign-in link by email."
      },
      "ConsoleSession": {
        "type": "object",
        "properties": {
          "user": { "$ref": "#/components/schemas/ConsoleUser" },
          "orgs": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ConsoleOrg" },
            "description": "Organizations the user belongs to."
          },
          "mfa_verified": {
            "type": "boolean",
            "description": "Whether this session has passed TOTP. When the user has TOTP on and this is `false`, org actions answer 401 until `POST /v1/console/totp/verify` succeeds."
          },
          "idle_expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the session expires if it is not used again (7 days after last use)."
          }
        },
        "required": ["user", "orgs", "mfa_verified", "idle_expires_at"],
        "description": "The current console session."
      },
      "ConsoleUser": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "User id.",
            "example": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "The user's verified email."
          },
          "totp_enabled": { "type": "boolean", "description": "Whether TOTP is turned on." }
        },
        "required": ["id", "email", "totp_enabled"],
        "description": "A console user."
      },
      "ConsoleOrg": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Organization id.",
            "example": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "name": { "type": "string", "description": "Organization name." },
          "slug": { "type": "string", "description": "URL-safe organization slug." },
          "role": {
            "type": "string",
            "enum": ["owner", "admin", "developer", "billing", "read_only"],
            "description": "The user's role in this organization."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the organization was created."
          }
        },
        "required": ["id", "name", "slug", "role", "created_at"],
        "description": "An organization the user is a member of."
      },
      "ConsumeMagicLinkRequest": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "minLength": 32,
            "maxLength": 256,
            "description": "The token from the sign-in or invitation link."
          }
        },
        "required": ["token"],
        "additionalProperties": false,
        "description": "Exchange a magic link token for a session."
      },
      "GithubOauthStartResponse": {
        "type": "object",
        "properties": {
          "authorize_url": {
            "type": "string",
            "format": "uri",
            "description": "GitHub's authorization page; send the browser there."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the OAuth `state` in the URL expires."
          }
        },
        "required": ["authorize_url", "expires_at"],
        "description": "Where to send the browser for GitHub."
      },
      "GithubOauthCallbackRequest": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "The `code` GitHub returned."
          },
          "state": {
            "type": "string",
            "minLength": 32,
            "maxLength": 256,
            "description": "The `state` GitHub returned."
          }
        },
        "required": ["code", "state"],
        "additionalProperties": false,
        "description": "The query parameters GitHub appended to the console callback URL."
      },
      "SignOutResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["signed_out"],
            "description": "The session was revoked."
          }
        },
        "required": ["status"],
        "description": "The session was revoked and the cookie cleared."
      },
      "TotpEnrolResponse": {
        "type": "object",
        "properties": {
          "secret": {
            "type": "string",
            "pattern": "^[A-Z2-7]{32}$",
            "description": "The base32 TOTP secret (shown once). Add it to an authenticator app, then confirm with a code."
          },
          "otpauth_uri": {
            "type": "string",
            "description": "The same secret as an `otpauth://` URI, to render as a QR code."
          }
        },
        "required": ["secret", "otpauth_uri"],
        "description": "A pending TOTP secret; it is active once a code is verified."
      },
      "TotpStatusResponse": {
        "type": "object",
        "properties": {
          "totp_enabled": {
            "type": "boolean",
            "description": "Whether TOTP is now on for the user."
          },
          "mfa_verified": {
            "type": "boolean",
            "description": "Whether this session has now passed TOTP."
          }
        },
        "required": ["totp_enabled", "mfa_verified"],
        "description": "The user's TOTP state after the call."
      },
      "TotpCodeRequest": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^[0-9]{6}$",
            "description": "The six-digit code from the authenticator app."
          }
        },
        "required": ["code"],
        "additionalProperties": false,
        "description": "A current TOTP code."
      },
      "ConsoleOrgsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ConsoleOrg" },
            "description": "Organizations, oldest membership first."
          }
        },
        "required": ["data"],
        "description": "The organizations the user belongs to."
      },
      "MembersResponse": {
        "type": "object",
        "properties": {
          "members": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Member" },
            "description": "Current members, oldest first."
          },
          "invites": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Invite" },
            "description": "Pending invitations, newest first."
          }
        },
        "required": ["members", "invites"],
        "description": "Members and pending invitations."
      },
      "Member": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The member's user id.",
            "example": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "email": { "type": "string", "format": "email", "description": "The member's email." },
          "role": {
            "type": "string",
            "enum": ["owner", "admin", "developer", "billing", "read_only"],
            "description": "The member's role."
          },
          "totp_enabled": { "type": "boolean", "description": "Whether the member has TOTP on." },
          "joined_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the member joined."
          }
        },
        "required": ["user_id", "email", "role", "totp_enabled", "joined_at"],
        "description": "A member of the organization."
      },
      "Invite": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid", "description": "The invitation id." },
          "email": { "type": "string", "format": "email", "description": "Who was invited." },
          "role": {
            "type": "string",
            "enum": ["owner", "admin", "developer", "billing", "read_only"],
            "description": "The role the invitee gets on accepting."
          },
          "invited_by": {
            "type": "string",
            "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Who sent the invitation.",
            "example": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the invitation expires."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it was sent."
          }
        },
        "required": ["id", "email", "role", "invited_by", "expires_at", "created_at"],
        "description": "A pending invitation to join the organization."
      },
      "CreateInviteRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "maxLength": 254,
            "format": "email",
            "description": "Who to invite."
          },
          "role": {
            "type": "string",
            "enum": ["owner", "admin", "developer", "billing", "read_only"],
            "description": "Role on accepting. Only an owner may invite an owner."
          }
        },
        "required": ["email", "role"],
        "additionalProperties": false,
        "description": "Invite someone by email."
      },
      "UpdateMemberRequest": {
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "enum": ["owner", "admin", "developer", "billing", "read_only"],
            "description": "The new role. Only an owner may grant or remove `owner`."
          }
        },
        "required": ["role"],
        "additionalProperties": false,
        "description": "Change a member's role."
      }
    },
    "parameters": {}
  },
  "paths": {
    "/v1/decisions/qualify_firm": {
      "post": {
        "operationId": "qualifyFirm",
        "summary": "Is this firm in my ICP?",
        "description": "Is this firm in my ICP? Returns `fit` as `p` and the resolved firm.\n\nCall it when your agent meets a company and must decide whether to spend effort on it. Give one firm reference (a domain is easiest) and an ICP profile id. Verdict resolves the firm in its index, reads its public facts (type, size band, HQ) and returns `fit` as `p`, `answer` (`fit` or `not_fit`), a `reason_code`, the resolved `firm` and cited `evidence`.\n\n**Price: $0.005 per call** (`x-verdict-price-usd`), billed only when an answer is returned: errors (including `decision_unavailable`, 503 with `Retry-After`) and refused calls are free. Send `X-Max-Cost-USD` to cap spend and `Idempotency-Key` (required) to retry safely; a repeated key within 24 hours returns the stored response and bills nothing. Every response carries the common envelope: `id`, `p` (always present, calibrated), `answer`, `reason_code`, `reason`, `evidence`, `calibration`, `cost` and `balance_usd`. Report what happened next with `POST /v1/outcomes`.\n\nScope: `decisions:write`.",
        "tags": ["Decisions"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "x-verdict-price-usd": 0.005,
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^(?:0|[1-9][0-9]{0,5})(?:\\.[0-9]{1,6})?$",
              "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
              "example": "0.01"
            },
            "required": false,
            "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
            "name": "x-max-cost-usd",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The `qualify_firm` input.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "firm": { "domain": "northfieldcapital.com" },
                "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "schema": { "$ref": "#/components/schemas/QualifyFirmRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `qualify_firm` decision, in the common envelope.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "version": "2026-11-01",
                  "question_set_version": "2026-11-01",
                  "model": "jev",
                  "calibration": { "basis": "org", "n_outcomes": 412, "threshold": 0.6 },
                  "latency_ms": 180,
                  "created_at": "2026-11-07T14:03:00Z",
                  "decision": "qualify_firm",
                  "p": 0.82,
                  "answer": "fit",
                  "reason_code": "icp_type_and_size_match",
                  "reason": "Registered investment adviser, $400M AUM band, 12 employees; matches ICP type and size.",
                  "evidence": [
                    {
                      "source": "sec_edgar",
                      "url": "https://adviserinfo.sec.gov/firm/summary/298765",
                      "observed_at": "2026-10-28",
                      "label": "Form ADV Part 1A"
                    }
                  ],
                  "fit": 0.82,
                  "firm": {
                    "id": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "name": "Northfield Capital Advisors LLC",
                    "domain": "northfieldcapital.com",
                    "identifiers": { "crd": "298765", "lei": "549300ABCDEF12345678" },
                    "type": "investment_adviser",
                    "size_band": "small",
                    "hq": { "country": "US", "region": "MA", "city": "Boston" },
                    "status": "active"
                  },
                  "cost": { "decision_usd": 0.005, "vendor_usd": 0, "total_usd": 0.005 },
                  "balance_usd": 18.32
                },
                "schema": { "$ref": "#/components/schemas/QualifyFirmResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "402": { "$ref": "#/components/responses/Error402" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        }
      }
    },
    "/v1/decisions/score_signal": {
      "post": {
        "operationId": "scoreSignal",
        "summary": "Does this event matter, and is now the time?",
        "description": "Does this event matter for my offer, and is now the time? Returns `relevant`, `act_now` and `window_days`.\n\nCall it when an event (a filing, a raise, an officer change) arrives and you must decide whether it is worth acting on now. Give an `event_id` from `GET /v1/events` or an inline `event`, and an ICP profile id. Returns `relevant` as `p`, `act_now`, `window_days`, `answer` (`relevant` or `not_relevant`) and a `reason_code`.\n\n**Price: $0.005 per call** (`x-verdict-price-usd`), billed only when an answer is returned: errors (including `decision_unavailable`, 503 with `Retry-After`) and refused calls are free. Send `X-Max-Cost-USD` to cap spend and `Idempotency-Key` (required) to retry safely; a repeated key within 24 hours returns the stored response and bills nothing. Every response carries the common envelope: `id`, `p` (always present, calibrated), `answer`, `reason_code`, `reason`, `evidence`, `calibration`, `cost` and `balance_usd`. Report what happened next with `POST /v1/outcomes`.\n\nScope: `decisions:write`.",
        "tags": ["Decisions"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "x-verdict-price-usd": 0.005,
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^(?:0|[1-9][0-9]{0,5})(?:\\.[0-9]{1,6})?$",
              "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
              "example": "0.01"
            },
            "required": false,
            "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
            "name": "x-max-cost-usd",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The `score_signal` input.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "event_id": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "schema": { "$ref": "#/components/schemas/ScoreSignalRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `score_signal` decision, in the common envelope.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "version": "2026-11-01",
                  "question_set_version": "2026-11-01",
                  "model": "jev",
                  "calibration": { "basis": "org", "n_outcomes": 412, "threshold": 0.6 },
                  "latency_ms": 180,
                  "created_at": "2026-11-07T14:03:00Z",
                  "decision": "score_signal",
                  "p": 0.78,
                  "answer": "relevant",
                  "reason_code": "event_relevant_and_timely",
                  "reason": "Form D offering filed 4 days ago; new capital is a buying trigger for this ICP.",
                  "evidence": [
                    {
                      "source": "sec_edgar",
                      "url": "https://www.sec.gov/Archives/edgar/data/1601234/000160123426000004/xslFormDX01/primary_doc.xml",
                      "observed_at": "2026-11-04",
                      "label": "Form D"
                    }
                  ],
                  "relevant": 0.78,
                  "act_now": 0.64,
                  "window_days": 21,
                  "event_id": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "firm": {
                    "id": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "name": "Northfield Capital Advisors LLC",
                    "domain": "northfieldcapital.com",
                    "identifiers": { "crd": "298765", "lei": "549300ABCDEF12345678" },
                    "type": "investment_adviser",
                    "size_band": "small",
                    "hq": { "country": "US", "region": "MA", "city": "Boston" },
                    "status": "active"
                  },
                  "cost": { "decision_usd": 0.005, "vendor_usd": 0, "total_usd": 0.005 },
                  "balance_usd": 18.315
                },
                "schema": { "$ref": "#/components/schemas/ScoreSignalResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "402": { "$ref": "#/components/responses/Error402" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        }
      }
    },
    "/v1/decisions/pick_person": {
      "post": {
        "operationId": "pickPerson",
        "summary": "Who at this firm should I write to?",
        "description": "Who in this roster should I write to? Returns the roster ranked, each person with `p`.\n\nCall it when you have several people at a firm and must choose whom to write to. Give a `roster` of up to 50 people (name, title, seniority, department; no LinkedIn data), the ICP and an optional `question`. Returns the whole roster ranked in `people`, each with `p`; `p` and `answer` (`pick` or `no_pick`) refer to the top person. One price per call for up to 50 people.\n\n**Price: $0.005 per call** (`x-verdict-price-usd`), billed only when an answer is returned: errors (including `decision_unavailable`, 503 with `Retry-After`) and refused calls are free. Send `X-Max-Cost-USD` to cap spend and `Idempotency-Key` (required) to retry safely; a repeated key within 24 hours returns the stored response and bills nothing. Every response carries the common envelope: `id`, `p` (always present, calibrated), `answer`, `reason_code`, `reason`, `evidence`, `calibration`, `cost` and `balance_usd`. Report what happened next with `POST /v1/outcomes`.\n\nScope: `decisions:write`.",
        "tags": ["Decisions"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "x-verdict-price-usd": 0.005,
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^(?:0|[1-9][0-9]{0,5})(?:\\.[0-9]{1,6})?$",
              "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
              "example": "0.01"
            },
            "required": false,
            "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
            "name": "x-max-cost-usd",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The `pick_person` input.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "roster": [
                  {
                    "ref": "c-101",
                    "name": "Dana Whitfield",
                    "title": "Chief Operating Officer",
                    "seniority": "c_level",
                    "department": "Operations"
                  },
                  {
                    "ref": "c-102",
                    "name": "Sam Ortega",
                    "title": "Operations Associate",
                    "seniority": "entry",
                    "department": "Operations"
                  },
                  {
                    "ref": "c-103",
                    "name": "Priya Raman",
                    "title": "Chief Compliance Officer",
                    "seniority": "c_level",
                    "department": "Compliance"
                  }
                ],
                "firm": { "domain": "northfieldcapital.com" },
                "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "schema": { "$ref": "#/components/schemas/PickPersonRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `pick_person` decision, in the common envelope.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "version": "2026-11-01",
                  "question_set_version": "2026-11-01",
                  "model": "jev",
                  "calibration": { "basis": "org", "n_outcomes": 412, "threshold": 0.6 },
                  "latency_ms": 180,
                  "created_at": "2026-11-07T14:03:00Z",
                  "decision": "pick_person",
                  "p": 0.74,
                  "answer": "pick",
                  "reason_code": "buyer_role_match",
                  "reason": "Chief Operating Officer owns operations tooling at a 12-person adviser.",
                  "evidence": [
                    {
                      "source": "request",
                      "url": null,
                      "observed_at": "2026-11-07",
                      "pointer": "/roster/0"
                    }
                  ],
                  "people": [
                    { "index": 0, "ref": "c-101", "rank": 1, "p": 0.74 },
                    { "index": 2, "ref": "c-103", "rank": 2, "p": 0.41 },
                    { "index": 1, "ref": "c-102", "rank": 3, "p": 0.09 }
                  ],
                  "cost": { "decision_usd": 0.005, "vendor_usd": 0, "total_usd": 0.005 },
                  "balance_usd": 18.31
                },
                "schema": { "$ref": "#/components/schemas/PickPersonResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "402": { "$ref": "#/components/responses/Error402" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        }
      }
    },
    "/v1/decisions/triage_reply": {
      "post": {
        "operationId": "triageReply",
        "summary": "What does this reply mean?",
        "description": "What does this reply mean? Returns the reply `state` and the `next_action`.\n\nCall it when a reply arrives and your agent must decide what to do. Give the `thread` (up to 40 messages, 8 KB each, oldest first). Returns the `state` (one of 13), `next_action`, `p` (probability of `state`) and `answer`: the state when `p` clears your threshold, otherwise `needs_review`.\n\n**Price: $0.003 per call** (`x-verdict-price-usd`), billed only when an answer is returned: errors (including `decision_unavailable`, 503 with `Retry-After`) and refused calls are free. Send `X-Max-Cost-USD` to cap spend and `Idempotency-Key` (required) to retry safely; a repeated key within 24 hours returns the stored response and bills nothing. Every response carries the common envelope: `id`, `p` (always present, calibrated), `answer`, `reason_code`, `reason`, `evidence`, `calibration`, `cost` and `balance_usd`. Report what happened next with `POST /v1/outcomes`.\n\nScope: `decisions:write`.",
        "tags": ["Decisions"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "x-verdict-price-usd": 0.003,
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^(?:0|[1-9][0-9]{0,5})(?:\\.[0-9]{1,6})?$",
              "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
              "example": "0.01"
            },
            "required": false,
            "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
            "name": "x-max-cost-usd",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The `triage_reply` input.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "thread": [
                  {
                    "role": "sender",
                    "text": "Hi Dana, saw your Form D last week. Worth a 15-minute call on trade ops?",
                    "sent_at": "2026-11-05T13:00:00Z"
                  },
                  {
                    "role": "prospect",
                    "text": "Possibly. Can you send pricing first? Next week is better for a call.",
                    "sent_at": "2026-11-06T09:12:00Z"
                  }
                ],
                "context": { "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V" }
              },
              "schema": { "$ref": "#/components/schemas/TriageReplyRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `triage_reply` decision, in the common envelope.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "version": "2026-11-01",
                  "question_set_version": "2026-11-01",
                  "model": "jev",
                  "calibration": { "basis": "org", "n_outcomes": 412, "threshold": 0.6 },
                  "latency_ms": 180,
                  "created_at": "2026-11-07T14:03:00Z",
                  "decision": "triage_reply",
                  "p": 0.71,
                  "answer": "question",
                  "reason_code": "explicit_question",
                  "reason": "The prospect asks for pricing before agreeing to a call.",
                  "evidence": [
                    {
                      "source": "request",
                      "url": null,
                      "observed_at": "2026-11-06",
                      "pointer": "/thread/1"
                    }
                  ],
                  "state": "question",
                  "next_action": "answer_question",
                  "cost": { "decision_usd": 0.003, "vendor_usd": 0, "total_usd": 0.003 },
                  "balance_usd": 18.307
                },
                "schema": { "$ref": "#/components/schemas/TriageReplyResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "402": { "$ref": "#/components/responses/Error402" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        }
      }
    },
    "/v1/decisions/right_person": {
      "post": {
        "operationId": "rightPerson",
        "summary": "Is this the right person to contact?",
        "description": "Is this candidate contact the right one for my ICP? Returns `p`.\n\nCall it to check one candidate contact before you write to them. Give the candidate (title, optional seniority, department, firm) and the ICP. Returns `p` and `answer` (`right_person` or `not_right_person`).\n\n**Price: $0.003 per call** (`x-verdict-price-usd`), billed only when an answer is returned: errors (including `decision_unavailable`, 503 with `Retry-After`) and refused calls are free. Send `X-Max-Cost-USD` to cap spend and `Idempotency-Key` (required) to retry safely; a repeated key within 24 hours returns the stored response and bills nothing. Every response carries the common envelope: `id`, `p` (always present, calibrated), `answer`, `reason_code`, `reason`, `evidence`, `calibration`, `cost` and `balance_usd`. Report what happened next with `POST /v1/outcomes`.\n\nScope: `decisions:write`.",
        "tags": ["Decisions"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "x-verdict-price-usd": 0.003,
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^(?:0|[1-9][0-9]{0,5})(?:\\.[0-9]{1,6})?$",
              "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
              "example": "0.01"
            },
            "required": false,
            "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
            "name": "x-max-cost-usd",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The `right_person` input.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "candidate": {
                  "name": "Dana Whitfield",
                  "title": "Chief Operating Officer",
                  "seniority": "c_level",
                  "department": "Operations",
                  "firm": { "domain": "northfieldcapital.com" }
                },
                "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "schema": { "$ref": "#/components/schemas/RightPersonRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `right_person` decision, in the common envelope.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "version": "2026-11-01",
                  "question_set_version": "2026-11-01",
                  "model": "jev",
                  "calibration": { "basis": "org", "n_outcomes": 412, "threshold": 0.6 },
                  "latency_ms": 180,
                  "created_at": "2026-11-07T14:03:00Z",
                  "decision": "right_person",
                  "p": 0.81,
                  "answer": "right_person",
                  "reason_code": "title_and_seniority_match",
                  "reason": "COO at a small adviser matches the ICP's operations buyer.",
                  "evidence": [
                    {
                      "source": "request",
                      "url": null,
                      "observed_at": "2026-11-07",
                      "pointer": "/candidate/title"
                    }
                  ],
                  "cost": { "decision_usd": 0.003, "vendor_usd": 0, "total_usd": 0.003 },
                  "balance_usd": 18.304
                },
                "schema": { "$ref": "#/components/schemas/RightPersonResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "402": { "$ref": "#/components/responses/Error402" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        }
      }
    },
    "/v1/decisions/should_send": {
      "post": {
        "operationId": "shouldSend",
        "summary": "Should this message go out now?",
        "description": "Should this prepared message go out now? Returns `send` as `p` and a `hold_reason`.\n\nCall it as the last gate before a prepared message goes out. Give the message, the decision ids behind it, the inbox health you measure and the ICP. Returns `send` as `p`, `answer` (`send` or `hold`) and a `hold_reason` when holding. Verdict never sends anything.\n\n**Price: $0.003 per call** (`x-verdict-price-usd`), billed only when an answer is returned: errors (including `decision_unavailable`, 503 with `Retry-After`) and refused calls are free. Send `X-Max-Cost-USD` to cap spend and `Idempotency-Key` (required) to retry safely; a repeated key within 24 hours returns the stored response and bills nothing. Every response carries the common envelope: `id`, `p` (always present, calibrated), `answer`, `reason_code`, `reason`, `evidence`, `calibration`, `cost` and `balance_usd`. Report what happened next with `POST /v1/outcomes`.\n\nScope: `decisions:write`.",
        "tags": ["Decisions"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "x-verdict-price-usd": 0.003,
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^(?:0|[1-9][0-9]{0,5})(?:\\.[0-9]{1,6})?$",
              "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
              "example": "0.01"
            },
            "required": false,
            "description": "Maximum you are willing to pay for this call, in US dollars (up to 6 decimals). If the call would cost more, it is refused with 402 `max_cost_exceeded` before spending.",
            "name": "x-max-cost-usd",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The `should_send` input.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "message": {
                  "channel": "email",
                  "subject": "Trade ops after your raise",
                  "body": "Hi Dana, congratulations on the new fund. We help 10-person advisers automate trade reconciliation. Open to a short call next week?"
                },
                "decision_ids": ["dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"],
                "inbox_health": {
                  "bounce_rate_7d": 0.012,
                  "spam_complaint_rate_7d": 0.0005,
                  "sent_today": 38,
                  "daily_limit": 50
                },
                "recipient": { "touches_30d": 1 },
                "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "schema": { "$ref": "#/components/schemas/ShouldSendRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `should_send` decision, in the common envelope.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "version": "2026-11-01",
                  "question_set_version": "2026-11-01",
                  "model": "jev",
                  "calibration": { "basis": "org", "n_outcomes": 412, "threshold": 0.6 },
                  "latency_ms": 180,
                  "created_at": "2026-11-07T14:03:00Z",
                  "decision": "should_send",
                  "p": 0.88,
                  "answer": "send",
                  "reason_code": "all_checks_passed",
                  "reason": "Upstream decisions clear their thresholds and inbox health is within bounds.",
                  "evidence": [
                    {
                      "source": "request",
                      "url": null,
                      "observed_at": "2026-11-07",
                      "pointer": "/inbox_health"
                    }
                  ],
                  "send": 0.88,
                  "hold_reason": null,
                  "cost": { "decision_usd": 0.003, "vendor_usd": 0, "total_usd": 0.003 },
                  "balance_usd": 18.301
                },
                "schema": { "$ref": "#/components/schemas/ShouldSendResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "402": { "$ref": "#/components/responses/Error402" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        }
      }
    },
    "/v1/decisions/{id}": {
      "get": {
        "operationId": "getDecision",
        "summary": "Get a decision",
        "description": "Fetch a decision your organization made, exactly as it was returned (decisions are immutable). Use it to audit an answer or to recover a response you lost. Free. Scope: `decisions:write`.",
        "tags": ["Decisions"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^dec_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The decision id.",
              "example": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The decision id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The stored decision.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "version": "2026-11-01",
                  "question_set_version": "2026-11-01",
                  "model": "jev",
                  "calibration": { "basis": "org", "n_outcomes": 412, "threshold": 0.6 },
                  "latency_ms": 180,
                  "created_at": "2026-11-07T14:03:00Z",
                  "decision": "qualify_firm",
                  "p": 0.82,
                  "answer": "fit",
                  "reason_code": "icp_type_and_size_match",
                  "reason": "Registered investment adviser, $400M AUM band, 12 employees; matches ICP type and size.",
                  "evidence": [
                    {
                      "source": "sec_edgar",
                      "url": "https://adviserinfo.sec.gov/firm/summary/298765",
                      "observed_at": "2026-10-28",
                      "label": "Form ADV Part 1A"
                    }
                  ],
                  "fit": 0.82,
                  "firm": {
                    "id": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "name": "Northfield Capital Advisors LLC",
                    "domain": "northfieldcapital.com",
                    "identifiers": { "crd": "298765", "lei": "549300ABCDEF12345678" },
                    "type": "investment_adviser",
                    "size_band": "small",
                    "hq": { "country": "US", "region": "MA", "city": "Boston" },
                    "status": "active"
                  },
                  "cost": { "decision_usd": 0.005, "vendor_usd": 0, "total_usd": 0.005 },
                  "balance_usd": 18.32
                },
                "schema": { "$ref": "#/components/schemas/Decision" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/firms/resolve": {
      "get": {
        "operationId": "resolveFirm",
        "summary": "Resolve a firm reference",
        "description": "Turn a domain, name (with `country`), LEI, CIK, CRD or Companies House number into Verdict's firm id and identifier crosswalk. Give exactly one reference parameter. Call it to dedupe companies or to get a `firm_id` before other calls; `qualify_firm` resolves on its own, so you do not need it first. Free. Unresolved references return a provisional firm (`matched_on: provisional`). Scope: `index:read`.",
        "tags": ["Index"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["index:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+[A-Za-z]{2,63}$",
              "description": "Resolve by web domain.",
              "example": "northfieldcapital.com"
            },
            "required": false,
            "description": "Resolve by web domain.",
            "name": "domain",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300,
              "description": "Resolve by name; add `country` to disambiguate."
            },
            "required": false,
            "description": "Resolve by name; add `country` to disambiguate.",
            "name": "name",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{2}$",
              "description": "Country hint for `name`.",
              "example": "US"
            },
            "required": false,
            "description": "Country hint for `name`.",
            "name": "country",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Z0-9]{18}[0-9]{2}$",
              "description": "Resolve by LEI.",
              "example": "549300ABCDEF12345678"
            },
            "required": false,
            "description": "Resolve by LEI.",
            "name": "lei",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{1,10}$",
              "description": "Resolve by SEC CIK.",
              "example": "1601234"
            },
            "required": false,
            "description": "Resolve by SEC CIK.",
            "name": "cik",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{1,8}$",
              "description": "Resolve by CRD number.",
              "example": "298765"
            },
            "required": false,
            "description": "Resolve by CRD number.",
            "name": "crd",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Z0-9]{8}$",
              "description": "Resolve by Companies House number.",
              "example": "09876543"
            },
            "required": false,
            "description": "Resolve by Companies House number.",
            "name": "companies_house",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The resolved firm.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "firm": {
                    "id": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "name": "Northfield Capital Advisors LLC",
                    "domain": "northfieldcapital.com",
                    "identifiers": { "crd": "298765", "lei": "549300ABCDEF12345678" },
                    "type": "investment_adviser",
                    "size_band": "small",
                    "hq": { "country": "US", "region": "MA", "city": "Boston" },
                    "status": "active",
                    "provisional": false,
                    "crosswalk": [
                      {
                        "kind": "crd",
                        "value": "298765",
                        "source": "sec_edgar",
                        "observed_at": "2026-10-28"
                      },
                      {
                        "kind": "lei",
                        "value": "549300ABCDEF12345678",
                        "source": "gleif",
                        "observed_at": "2026-11-02"
                      },
                      {
                        "kind": "domain",
                        "value": "northfieldcapital.com",
                        "source": "sec_edgar",
                        "observed_at": "2026-10-28"
                      },
                      {
                        "kind": "name_variant",
                        "value": "Northfield Capital",
                        "source": "wikidata",
                        "observed_at": "2026-10-30"
                      }
                    ],
                    "created_at": "2026-09-14T08:12:00Z",
                    "updated_at": "2026-11-02T06:40:00Z"
                  },
                  "matched_on": "domain"
                },
                "schema": { "$ref": "#/components/schemas/ResolveFirmResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/firms/{id}": {
      "get": {
        "operationId": "getFirm",
        "summary": "Get a firm",
        "description": "Public facts (type, size band, HQ, status) and every known identifier of a firm, each with its source and date. Free. Scope: `index:read`.",
        "tags": ["Index"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["index:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The firm id.",
              "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The firm id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The firm.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "name": "Northfield Capital Advisors LLC",
                  "domain": "northfieldcapital.com",
                  "identifiers": { "crd": "298765", "lei": "549300ABCDEF12345678" },
                  "type": "investment_adviser",
                  "size_band": "small",
                  "hq": { "country": "US", "region": "MA", "city": "Boston" },
                  "status": "active",
                  "provisional": false,
                  "crosswalk": [
                    {
                      "kind": "crd",
                      "value": "298765",
                      "source": "sec_edgar",
                      "observed_at": "2026-10-28"
                    },
                    {
                      "kind": "lei",
                      "value": "549300ABCDEF12345678",
                      "source": "gleif",
                      "observed_at": "2026-11-02"
                    },
                    {
                      "kind": "domain",
                      "value": "northfieldcapital.com",
                      "source": "sec_edgar",
                      "observed_at": "2026-10-28"
                    },
                    {
                      "kind": "name_variant",
                      "value": "Northfield Capital",
                      "source": "wikidata",
                      "observed_at": "2026-10-30"
                    }
                  ],
                  "created_at": "2026-09-14T08:12:00Z",
                  "updated_at": "2026-11-02T06:40:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Firm" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "List events",
        "description": "Events from the index for one firm (`firm_id`) or for an ICP (`icp_id`), newest first, optionally filtered by `since` and `types`. Without `icp_id` the call is free and `score` is `null`. With `icp_id` every returned event is scored (`score` set) and **bills one `score_signal` ($0.005) per scored event** (needs `decisions:write` too); a page with `icp_id` holds at most 50 events. A score made for the same ICP and event within the last hour is reused and not billed again. `min_p` filters the returned events on `relevant`; events below it were still scored and billed. If the balance (or the key's daily cap) runs out, or the decision model becomes unavailable, part-way through a page, the page stops there: you get the events scored and billed so far, `has_more: true` and a `next_cursor` that resumes at the first unscored event. Only when the first event cannot be scored is the error returned (402 `insufficient_balance`, or 503 `decision_unavailable` with `Retry-After`). Cursor-paginated. Scope: `index:read`.",
        "tags": ["Index"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["index:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^frm_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "Events of this firm.",
              "example": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": false,
            "description": "Events of this firm.",
            "name": "firm_id",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "Events for this ICP, each scored (one `score_signal` billed per scored event).",
              "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": false,
            "description": "Events for this ICP, each scored (one `score_signal` billed per scored event).",
            "name": "icp_id",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only events observed at or after this time."
            },
            "required": false,
            "description": "Only events observed at or after this time.",
            "name": "since",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^(?:filing|registration|officer_change|ownership_change|lei_change|address_change|fund_raise|insider_trade|patent_filing|litigation|news_mention|repo_activity|hiring_aggregate)(?:,(?:filing|registration|officer_change|ownership_change|lei_change|address_change|fund_raise|insider_trade|patent_filing|litigation|news_mention|repo_activity|hiring_aggregate))*$",
              "description": "Comma-separated event types to include, for example `filing,fund_raise`.",
              "example": "filing,fund_raise"
            },
            "required": false,
            "description": "Comma-separated event types to include, for example `filing,fund_raise`.",
            "name": "types",
            "in": "query"
          },
          {
            "schema": {
              "type": ["number", "null"],
              "minimum": 0,
              "maximum": 1,
              "description": "With `icp_id`: only events whose `relevant` is at least this.",
              "example": 0.6
            },
            "required": false,
            "description": "With `icp_id`: only events whose `relevant` is at least this.",
            "name": "min_p",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of events.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "type": "filing",
                      "firm_id": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "occurred_at": "2026-11-03T21:15:00Z",
                      "observed_at": "2026-11-04T02:05:00Z",
                      "source": "sec_edgar",
                      "source_url": "https://www.sec.gov/Archives/edgar/data/1601234/000160123426000004/xslFormDX01/primary_doc.xml",
                      "confidence": 0.97,
                      "attributes": {
                        "filing_type": "sec_form_d",
                        "accession_number": "0001601234-26-000004",
                        "title": "Notice of Exempt Offering of Securities"
                      },
                      "score": {
                        "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                        "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                        "relevant": 0.78,
                        "act_now": 0.64,
                        "window_days": 21,
                        "answer": "relevant",
                        "reason_code": "event_relevant_and_timely"
                      }
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Event" },
                      "description": "Events, newest first."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "402": { "$ref": "#/components/responses/Error402" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        }
      }
    },
    "/v1/sources": {
      "get": {
        "operationId": "listSources",
        "summary": "List index sources",
        "description": "The sources behind Verdict's index: license and attribution, refresh cadence, and the last successful run. Call it to check data freshness or the attribution to show. Free. Scope: `index:read`.",
        "tags": ["Index"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["index:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of sources.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "src_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "source": "gleif",
                      "name": "GLEIF LEI golden copy",
                      "phase": 1,
                      "license": {
                        "kind": "cc0",
                        "name": "CC0 1.0 Universal",
                        "url": "https://creativecommons.org/publicdomain/zero/1.0/",
                        "attribution": null
                      },
                      "refresh_cadence": "daily",
                      "rate_limit": null,
                      "last_successful_run": {
                        "id": "run_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                        "status": "succeeded",
                        "started_at": "2026-11-07T03:00:00Z",
                        "finished_at": "2026-11-07T03:21:40Z",
                        "events_upserted": 1874
                      },
                      "last_run": {
                        "id": "run_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                        "status": "succeeded",
                        "started_at": "2026-11-07T03:00:00Z",
                        "finished_at": "2026-11-07T03:21:40Z",
                        "events_upserted": 1874
                      },
                      "freshness_seconds": 7200
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Source" },
                      "description": "Sources."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/watches": {
      "post": {
        "operationId": "createWatch",
        "summary": "Create a watch",
        "description": "Ask Verdict to push scored events for an ICP to your HTTPS endpoint as they land: each event whose `relevant` is at least `min_p` is delivered, signed with `Verdict-Signature` (see the `scoredEvent` webhook). The URL must answer the `watchChallenge` webhook before deliveries start. Creating a watch is free; **each delivered event bills one `score_signal` ($0.005)**, never per retry. The response includes the signing secret once. Scope: `watches:manage`.",
        "tags": ["Watches"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["watches:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The watch to create.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                "webhook_url": "https://agent.northwind-ops.io/hooks/verdict",
                "min_p": 0.7,
                "types": ["filing", "fund_raise", "officer_change"]
              },
              "schema": { "$ref": "#/components/schemas/CreateWatchRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The watch, pending verification, with its signing secret.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "webhook_url": "https://agent.northwind-ops.io/hooks/verdict",
                  "min_p": 0.7,
                  "types": ["filing", "fund_raise", "officer_change"],
                  "status": "pending_verification",
                  "created_at": "2026-11-07T14:10:00Z",
                  "updated_at": "2026-11-07T14:10:00Z",
                  "signing_secret": "whsec_ExampleExampleExampleExampleExample"
                },
                "schema": { "$ref": "#/components/schemas/CreatedWatch" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      },
      "get": {
        "operationId": "listWatches",
        "summary": "List watches",
        "description": "Your project's watches with their ICP, `min_p`, event types and status, newest first. Use it to find a watch to inspect or delete. Free. Scope: `watches:manage`.",
        "tags": ["Watches"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["watches:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of watches.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "webhook_url": "https://agent.northwind-ops.io/hooks/verdict",
                      "min_p": 0.7,
                      "types": ["filing", "fund_raise", "officer_change"],
                      "status": "pending_verification",
                      "created_at": "2026-11-07T14:10:00Z",
                      "updated_at": "2026-11-07T14:10:00Z"
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Watch" },
                      "description": "Watches."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/watches/{id}": {
      "get": {
        "operationId": "getWatch",
        "summary": "Get a watch",
        "description": "One watch with its ICP, `min_p`, event types and status. Call it after creating a watch to see whether the URL passed the challenge (`active`) or is still `pending_verification`. Free. Scope: `watches:manage`.",
        "tags": ["Watches"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["watches:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^wch_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The watch id.",
              "example": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The watch id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The watch.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "webhook_url": "https://agent.northwind-ops.io/hooks/verdict",
                  "min_p": 0.7,
                  "types": ["filing", "fund_raise", "officer_change"],
                  "status": "pending_verification",
                  "created_at": "2026-11-07T14:10:00Z",
                  "updated_at": "2026-11-07T14:10:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Watch" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      },
      "delete": {
        "operationId": "deleteWatch",
        "summary": "Delete a watch",
        "description": "Stop a watch. Pending deliveries are cancelled and never billed; delivery history stays readable. Free. Scope: `watches:manage`.",
        "tags": ["Watches"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["watches:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^wch_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The watch id.",
              "example": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The watch id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The watch, now `deleted`.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "webhook_url": "https://agent.northwind-ops.io/hooks/verdict",
                  "min_p": 0.7,
                  "types": ["filing", "fund_raise", "officer_change"],
                  "status": "deleted",
                  "created_at": "2026-11-07T14:10:00Z",
                  "updated_at": "2026-11-07T14:10:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Watch" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/watches/{id}/deliveries": {
      "get": {
        "operationId": "listWatchDeliveries",
        "summary": "List a watch's deliveries",
        "description": "Delivery attempts for one watch, newest first, with status, attempts and the last response code. Use it to debug your endpoint or to replay missed events by id. Free. Scope: `watches:manage`.",
        "tags": ["Watches"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["watches:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^wch_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The watch id.",
              "example": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The watch id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": ["pending", "retrying", "delivered", "failed"],
              "description": "Only deliveries with this status."
            },
            "required": false,
            "description": "Only deliveries with this status.",
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of deliveries.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "dlv_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "watch_id": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "event_id": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "status": "delivered",
                      "attempts": 1,
                      "last_attempt_at": "2026-11-07T15:00:04Z",
                      "last_response_status": 200,
                      "next_attempt_at": null,
                      "delivered_at": "2026-11-07T15:00:04Z",
                      "created_at": "2026-11-07T15:00:03Z"
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Delivery" },
                      "description": "Deliveries, newest first."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/outcomes": {
      "post": {
        "operationId": "createOutcome",
        "summary": "Report an outcome",
        "description": "Tell Verdict what happened after a decision (bounced, replied, meeting_booked, approved, skipped, or `custom:<slug>`). Outcomes calibrate `p` and move your thresholds. Free and unlimited. Idempotent on `(decision_id, outcome, observed_at)`: a repeat returns 200 with the stored outcome. The SDK reports `approved` and `skipped` for you and tags sends with the `X-Verdict-Decision` email header (or a vendor custom field) so the vendor receivers can report the rest. Scope: `outcomes:write`.",
        "tags": ["Outcomes"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["outcomes:write"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The outcome.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                "outcome": "meeting_booked",
                "observed_at": "2026-11-09T16:30:00Z",
                "meta": { "channel": "email" }
              },
              "schema": { "$ref": "#/components/schemas/CreateOutcomeRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The same outcome was already recorded; nothing changed.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "out_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "outcome": "meeting_booked",
                  "observed_at": "2026-11-09T16:30:00Z",
                  "meta": { "channel": "email" },
                  "created_at": "2026-11-09T16:30:02Z"
                },
                "schema": { "$ref": "#/components/schemas/Outcome" }
              }
            }
          },
          "201": {
            "description": "The outcome was recorded.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "out_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "outcome": "meeting_booked",
                  "observed_at": "2026-11-09T16:30:00Z",
                  "meta": { "channel": "email" },
                  "created_at": "2026-11-09T16:30:02Z"
                },
                "schema": { "$ref": "#/components/schemas/Outcome" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/webhooks/instantly/{receiver_token}": {
      "post": {
        "operationId": "receiveInstantlyWebhook",
        "summary": "Receive Instantly webhooks",
        "description": "Point Instantly's webhook at this URL (copy it from the console) and Verdict turns its events into outcomes on the decision you tagged when sending. Not called by agents. The body is Instantly's own payload, passed through unchanged. Verification: Instantly does not sign webhooks: the per-org `receiver_token` in the path authenticates the call, plus Instantly's published source IPs where available. Mapping: `email_sent` to `delivered`, `email_bounced` to `bounced`, `reply_received` to `replied`, `lead_interested` to `interested`, `lead_not_interested` to `not_interested`, `lead_meeting_booked` to `meeting_booked`. Idempotent on the vendor's event id. Free. Verdict never holds your Instantly credentials.",
        "tags": ["Inbound webhooks"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{32,64}$",
              "description": "Per-org receiver token issued in the console; identifies your organization. Treat the full URL as a secret."
            },
            "required": true,
            "description": "Per-org receiver token issued in the console; identifies your organization. Treat the full URL as a secret.",
            "name": "receiver_token",
            "in": "path"
          }
        ],
        "requestBody": {
          "description": "Instantly's webhook payload.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "event_type": "reply_received",
                "timestamp": "2026-11-06T09:12:00Z",
                "campaign_id": "cmp_example",
                "lead_email": "dana@northfieldcapital.com",
                "verdict_decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
              },
              "schema": { "$ref": "#/components/schemas/VendorWebhookBody" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The payload was verified and processed.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "received": true,
                  "duplicate": false,
                  "outcome_ids": ["out_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"]
                },
                "schema": { "$ref": "#/components/schemas/WebhookReceipt" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/webhooks/smartlead/{receiver_token}": {
      "post": {
        "operationId": "receiveSmartleadWebhook",
        "summary": "Receive Smartlead webhooks",
        "description": "Point Smartlead's webhook at this URL (copy it from the console) and Verdict turns its events into outcomes on the decision you tagged when sending. Not called by agents. The body is Smartlead's own payload, passed through unchanged. Verification: Smartlead's webhook secret is checked when configured; otherwise the per-org `receiver_token` in the path authenticates the call. Mapping: `EMAIL_SENT` to `delivered`, `EMAIL_BOUNCE` to `bounced`, `EMAIL_REPLY` to `replied`, lead category changes to `interested` or `not_interested`. Idempotent on the vendor's event id. Free. Verdict never holds your Smartlead credentials.",
        "tags": ["Inbound webhooks"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{32,64}$",
              "description": "Per-org receiver token issued in the console; identifies your organization. Treat the full URL as a secret."
            },
            "required": true,
            "description": "Per-org receiver token issued in the console; identifies your organization. Treat the full URL as a secret.",
            "name": "receiver_token",
            "in": "path"
          }
        ],
        "requestBody": {
          "description": "Smartlead's webhook payload.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "event_type": "EMAIL_REPLY",
                "event_timestamp": "2026-11-06T09:12:00Z",
                "campaign_id": 4821,
                "custom_fields": { "verdict_decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V" }
              },
              "schema": { "$ref": "#/components/schemas/VendorWebhookBody" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The payload was verified and processed.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "received": true,
                  "duplicate": false,
                  "outcome_ids": ["out_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"]
                },
                "schema": { "$ref": "#/components/schemas/WebhookReceipt" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/webhooks/calcom/{receiver_token}": {
      "post": {
        "operationId": "receiveCalcomWebhook",
        "summary": "Receive Cal.com webhooks",
        "description": "Point Cal.com's webhook at this URL (copy it from the console) and Verdict turns its events into outcomes on the decision you tagged when sending. Not called by agents. The body is Cal.com's own payload, passed through unchanged. Verification: `X-Cal-Signature-256` (HMAC-SHA256 of the raw body with the webhook secret you set in Cal.com and in the console) is verified before parsing. Mapping: `BOOKING_CREATED` to `meeting_booked`, `MEETING_ENDED` to `meeting_held`, `BOOKING_CANCELLED` is recorded but creates no outcome. Idempotent on the vendor's event id. Free. Verdict never holds your Cal.com credentials.",
        "tags": ["Inbound webhooks"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{32,64}$",
              "description": "Per-org receiver token issued in the console; identifies your organization. Treat the full URL as a secret."
            },
            "required": true,
            "description": "Per-org receiver token issued in the console; identifies your organization. Treat the full URL as a secret.",
            "name": "receiver_token",
            "in": "path"
          }
        ],
        "requestBody": {
          "description": "Cal.com's webhook payload.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "triggerEvent": "BOOKING_CREATED",
                "createdAt": "2026-11-07T10:00:00Z",
                "payload": {
                  "metadata": { "verdict_decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V" }
                }
              },
              "schema": { "$ref": "#/components/schemas/VendorWebhookBody" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The payload was verified and processed.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "received": true,
                  "duplicate": false,
                  "outcome_ids": ["out_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"]
                },
                "schema": { "$ref": "#/components/schemas/WebhookReceipt" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/webhooks/calendly/{receiver_token}": {
      "post": {
        "operationId": "receiveCalendlyWebhook",
        "summary": "Receive Calendly webhooks",
        "description": "Point Calendly's webhook at this URL (copy it from the console) and Verdict turns its events into outcomes on the decision you tagged when sending. Not called by agents. The body is Calendly's own payload, passed through unchanged. Verification: `Calendly-Webhook-Signature` (`t=...,v1=...` with the subscription's signing key) is verified before parsing. Mapping: `invitee.created` to `meeting_booked`; `invitee.canceled` is recorded but creates no outcome. Idempotent on the vendor's event id. Free. Verdict never holds your Calendly credentials.",
        "tags": ["Inbound webhooks"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{32,64}$",
              "description": "Per-org receiver token issued in the console; identifies your organization. Treat the full URL as a secret."
            },
            "required": true,
            "description": "Per-org receiver token issued in the console; identifies your organization. Treat the full URL as a secret.",
            "name": "receiver_token",
            "in": "path"
          }
        ],
        "requestBody": {
          "description": "Calendly's webhook payload.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "event": "invitee.created",
                "created_at": "2026-11-07T10:00:00Z",
                "payload": { "tracking": { "utm_content": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V" } }
              },
              "schema": { "$ref": "#/components/schemas/VendorWebhookBody" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The payload was verified and processed.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "received": true,
                  "duplicate": false,
                  "outcome_ids": ["out_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"]
                },
                "schema": { "$ref": "#/components/schemas/WebhookReceipt" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/icps": {
      "post": {
        "operationId": "createIcp",
        "summary": "Create an ICP profile",
        "description": "Describe who you sell to and what you sell, in plain text plus optional filters. Every decision is made against an ICP profile, so create one first. Verdict summarizes it once (`summary_status`), assigns a calibration segment and sets calibrated default thresholds. Free. Scope: `decisions:write`.",
        "tags": ["ICP profiles"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The profile.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "name": "RIAs under $1B",
                "description": "US registered investment advisers with under $1B in assets and fewer than 50 staff. We sell trade reconciliation software to their operations lead.",
                "filters": {
                  "firm_types": ["investment_adviser"],
                  "size_bands": ["micro", "small"],
                  "countries": ["US"]
                }
              },
              "schema": { "$ref": "#/components/schemas/CreateIcpRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new profile.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "name": "RIAs under $1B",
                  "description": "US registered investment advisers with under $1B in assets and fewer than 50 staff. We sell trade reconciliation software to their operations lead.",
                  "filters": {
                    "firm_types": ["investment_adviser"],
                    "size_bands": ["micro", "small"],
                    "countries": ["US"]
                  },
                  "segment": { "industry_group": "asset_management", "size_band": "small" },
                  "summary_status": "pending",
                  "thresholds": {
                    "qualify_firm": { "value": 0.6, "source": "calibrated" },
                    "score_signal": { "value": 0.55, "source": "calibrated" },
                    "pick_person": { "value": 0.5, "source": "calibrated" },
                    "triage_reply": { "value": 0.65, "source": "calibrated" },
                    "right_person": { "value": 0.7, "source": "custom" },
                    "should_send": { "value": 0.6, "source": "calibrated" }
                  },
                  "created_at": "2026-11-07T14:00:00Z",
                  "updated_at": "2026-11-07T14:20:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Icp" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      },
      "get": {
        "operationId": "listIcps",
        "summary": "List ICP profiles",
        "description": "Your project's ICP profiles, newest first, each with its segment, summary status and thresholds. Call it to find the `icp_id` to pass to decisions. Free. Scope: `decisions:write`.",
        "tags": ["ICP profiles"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of profiles.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "name": "RIAs under $1B",
                      "description": "US registered investment advisers with under $1B in assets and fewer than 50 staff. We sell trade reconciliation software to their operations lead.",
                      "filters": {
                        "firm_types": ["investment_adviser"],
                        "size_bands": ["micro", "small"],
                        "countries": ["US"]
                      },
                      "segment": { "industry_group": "asset_management", "size_band": "small" },
                      "summary_status": "ready",
                      "thresholds": {
                        "qualify_firm": { "value": 0.6, "source": "calibrated" },
                        "score_signal": { "value": 0.55, "source": "calibrated" },
                        "pick_person": { "value": 0.5, "source": "calibrated" },
                        "triage_reply": { "value": 0.65, "source": "calibrated" },
                        "right_person": { "value": 0.7, "source": "custom" },
                        "should_send": { "value": 0.6, "source": "calibrated" }
                      },
                      "created_at": "2026-11-07T14:00:00Z",
                      "updated_at": "2026-11-07T14:20:00Z"
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Icp" },
                      "description": "ICP profiles."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/icps/{id}": {
      "get": {
        "operationId": "getIcp",
        "summary": "Get an ICP profile",
        "description": "One ICP profile with its segment, summary status and the current threshold of every decision. Call it to see what `answer` will apply. Free. Scope: `decisions:write`.",
        "tags": ["ICP profiles"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The ICP profile id.",
              "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The ICP profile id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The profile.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "name": "RIAs under $1B",
                  "description": "US registered investment advisers with under $1B in assets and fewer than 50 staff. We sell trade reconciliation software to their operations lead.",
                  "filters": {
                    "firm_types": ["investment_adviser"],
                    "size_bands": ["micro", "small"],
                    "countries": ["US"]
                  },
                  "segment": { "industry_group": "asset_management", "size_band": "small" },
                  "summary_status": "ready",
                  "thresholds": {
                    "qualify_firm": { "value": 0.6, "source": "calibrated" },
                    "score_signal": { "value": 0.55, "source": "calibrated" },
                    "pick_person": { "value": 0.5, "source": "calibrated" },
                    "triage_reply": { "value": 0.65, "source": "calibrated" },
                    "right_person": { "value": 0.7, "source": "custom" },
                    "should_send": { "value": 0.6, "source": "calibrated" }
                  },
                  "created_at": "2026-11-07T14:00:00Z",
                  "updated_at": "2026-11-07T14:20:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Icp" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      },
      "patch": {
        "operationId": "updateIcp",
        "summary": "Update an ICP profile",
        "description": "Change a profile's name, description or filters. Changing the description re-runs summarization. Past decisions are unchanged. Free. Scope: `decisions:write`.",
        "tags": ["ICP profiles"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["decisions:write"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The ICP profile id.",
              "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The ICP profile id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "Fields to change.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "name": "RIAs under $2B" },
              "schema": { "$ref": "#/components/schemas/UpdateIcpRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated profile.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "name": "RIAs under $2B",
                  "description": "US registered investment advisers with under $1B in assets and fewer than 50 staff. We sell trade reconciliation software to their operations lead.",
                  "filters": {
                    "firm_types": ["investment_adviser"],
                    "size_bands": ["micro", "small"],
                    "countries": ["US"]
                  },
                  "segment": { "industry_group": "asset_management", "size_band": "small" },
                  "summary_status": "ready",
                  "thresholds": {
                    "qualify_firm": { "value": 0.6, "source": "calibrated" },
                    "score_signal": { "value": 0.55, "source": "calibrated" },
                    "pick_person": { "value": 0.5, "source": "calibrated" },
                    "triage_reply": { "value": 0.65, "source": "calibrated" },
                    "right_person": { "value": 0.7, "source": "custom" },
                    "should_send": { "value": 0.6, "source": "calibrated" }
                  },
                  "created_at": "2026-11-07T14:00:00Z",
                  "updated_at": "2026-11-07T14:20:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Icp" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/icps/{id}/thresholds": {
      "patch": {
        "operationId": "updateIcpThresholds",
        "summary": "Set decision thresholds",
        "description": "Trade precision for recall: set the threshold `answer` applies to `p` for one or more decisions on this profile, or `null` to return to the calibrated default. Changes `answer` on future decisions and nothing else; `p` is unaffected. Audited. Free. Scope: `account:manage`.",
        "tags": ["ICP profiles"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["account:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^icp_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The ICP profile id.",
              "example": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The ICP profile id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "Thresholds to change.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "thresholds": { "right_person": 0.7, "qualify_firm": null } },
              "schema": { "$ref": "#/components/schemas/UpdateThresholdsRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The profile's thresholds after the change.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "qualify_firm": { "value": 0.6, "source": "calibrated" },
                  "score_signal": { "value": 0.55, "source": "calibrated" },
                  "pick_person": { "value": 0.5, "source": "calibrated" },
                  "triage_reply": { "value": 0.65, "source": "calibrated" },
                  "right_person": { "value": 0.7, "source": "custom" },
                  "should_send": { "value": 0.6, "source": "calibrated" }
                },
                "schema": { "$ref": "#/components/schemas/Thresholds" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/signup": {
      "post": {
        "operationId": "signup",
        "summary": "Sign up",
        "description": "Start sign-up with a work email; no browser and no card needed. Verdict emails a verification link; complete sign-up with `POST /v1/signup/verify` using the token from the link, which issues your first key (shown once) and $5 of starter credits. If the verification email cannot be sent, the answer is 503 `vendor_unavailable` with `Retry-After` and nothing is created: retry the same request after that many seconds. Free. No key needed.",
        "tags": ["Account"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The email to verify.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "email": "dana@northwind-ops.io", "org_name": "Northwind Ops" },
              "schema": { "$ref": "#/components/schemas/SignupRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Verification email sent.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "status": "verification_sent",
                  "email": "dana@northwind-ops.io",
                  "expires_at": "2026-11-07T14:10:00Z"
                },
                "schema": { "$ref": "#/components/schemas/SignupResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        }
      }
    },
    "/v1/signup/verify": {
      "post": {
        "operationId": "verifySignup",
        "summary": "Verify sign-up and get a key",
        "description": "Exchange the token from the verification email for your organization, default project and first API key. The key secret is returned once; store it. Starter credits ($5) are granted. The token is single use. Free. No key needed.",
        "tags": ["Account"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The verification token.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "token": "Ex4mpleVerificationTokenFromTheEmailLink0001" },
              "schema": { "$ref": "#/components/schemas/VerifySignupRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new organization and key.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "org_id": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "key": {
                    "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "name": "default",
                    "environment": "live",
                    "prefix": "vd_live_Ab12Cd",
                    "scopes": ["decisions:write", "index:read", "outcomes:write"],
                    "status": "active",
                    "rate_limit_per_minute": 600,
                    "daily_spend_cap_usd": 25,
                    "ip_allowlist": [],
                    "expires_at": null,
                    "last_used_at": null,
                    "created_at": "2026-11-07T14:00:00Z",
                    "secret": "vd_live_<shown-once>"
                  },
                  "starter_credit_usd": 5,
                  "balance_usd": 5
                },
                "schema": { "$ref": "#/components/schemas/VerifySignupResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Who am I",
        "description": "The organization, project and key behind the calling key, and its default API version. Call it to check a key works. Free. Any valid key.",
        "tags": ["Account"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The calling identity.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "org": {
                    "id": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "name": "Northwind Ops",
                    "created_at": "2026-11-01T09:00:00Z"
                  },
                  "project": { "id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V", "name": "outbound-ria" },
                  "key": {
                    "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "name": "outbound-agent prod",
                    "environment": "live",
                    "prefix": "vd_live_Ab12Cd",
                    "scopes": ["decisions:write", "index:read", "outcomes:write"],
                    "status": "active",
                    "rate_limit_per_minute": 600,
                    "daily_spend_cap_usd": 25,
                    "ip_allowlist": [],
                    "expires_at": null,
                    "last_used_at": "2026-11-07T14:03:00Z",
                    "created_at": "2026-11-01T09:00:00Z"
                  },
                  "api_version": "2026-11-01"
                },
                "schema": { "$ref": "#/components/schemas/MeResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/keys": {
      "get": {
        "operationId": "listKeys",
        "summary": "List API keys",
        "description": "Your organization's keys with scopes, limits, status and last use. Secrets are never returned. Free. Scope: `keys:manage`.",
        "tags": ["Account"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["keys:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of keys.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "name": "outbound-agent prod",
                      "environment": "live",
                      "prefix": "vd_live_Ab12Cd",
                      "scopes": ["decisions:write", "index:read", "outcomes:write"],
                      "status": "active",
                      "rate_limit_per_minute": 600,
                      "daily_spend_cap_usd": 25,
                      "ip_allowlist": [],
                      "expires_at": null,
                      "last_used_at": "2026-11-07T14:03:00Z",
                      "created_at": "2026-11-01T09:00:00Z"
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/ApiKey" },
                      "description": "Keys."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      },
      "post": {
        "operationId": "createKey",
        "summary": "Create an API key",
        "description": "Create a scoped key with optional rate limit, daily spend cap, IP allowlist and expiry. The secret is in the response once and never again. Audited. Free. Scope: `keys:manage`.",
        "tags": ["Account"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["keys:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The key to create.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "name": "outbound-agent prod",
                "scopes": ["decisions:write", "index:read", "outcomes:write"],
                "daily_spend_cap_usd": 25
              },
              "schema": { "$ref": "#/components/schemas/CreateKeyRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The key, with its secret shown once.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "name": "outbound-agent prod",
                  "environment": "live",
                  "prefix": "vd_live_Ab12Cd",
                  "scopes": ["decisions:write", "index:read", "outcomes:write"],
                  "status": "active",
                  "rate_limit_per_minute": 600,
                  "daily_spend_cap_usd": 25,
                  "ip_allowlist": [],
                  "expires_at": null,
                  "last_used_at": null,
                  "created_at": "2026-11-07T14:00:00Z",
                  "secret": "vd_live_<shown-once>"
                },
                "schema": { "$ref": "#/components/schemas/CreatedApiKey" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/keys/{id}": {
      "delete": {
        "operationId": "revokeKey",
        "summary": "Revoke an API key",
        "description": "Revoke a key immediately; calls with it fail within a second. Use it when a key may have leaked (then create or rotate a replacement). Cannot be undone. Audited. Free. Scope: `keys:manage`.",
        "tags": ["Account"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["keys:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The key id.",
              "example": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The key id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The key, now `revoked`.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "name": "outbound-agent prod",
                  "environment": "live",
                  "prefix": "vd_live_Ab12Cd",
                  "scopes": ["decisions:write", "index:read", "outcomes:write"],
                  "status": "revoked",
                  "rate_limit_per_minute": 600,
                  "daily_spend_cap_usd": 25,
                  "ip_allowlist": [],
                  "expires_at": null,
                  "last_used_at": "2026-11-07T14:03:00Z",
                  "created_at": "2026-11-01T09:00:00Z"
                },
                "schema": { "$ref": "#/components/schemas/ApiKey" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      },
      "patch": {
        "operationId": "updateKey",
        "summary": "Change an API key",
        "description": "Change a key's name, scopes or limits (rate limit, daily spend cap, IP allowlist, expiry) without rotating it; the secret is unchanged. A key can only grant scopes it holds itself. Takes effect on the next request. Audited (`key_scopes_changed` for scopes, `key_updated` for the rest). Free. Scope: `keys:manage`.",
        "tags": ["Account"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["keys:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The key id.",
              "example": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The key id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "Fields to change.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "scopes": ["decisions:write", "index:read"],
                "rate_limit_per_minute": 120
              },
              "schema": { "$ref": "#/components/schemas/UpdateKeyRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The key, updated.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "name": "outbound-agent prod",
                  "environment": "live",
                  "prefix": "vd_live_Ab12Cd",
                  "scopes": ["decisions:write", "index:read"],
                  "status": "active",
                  "rate_limit_per_minute": 120,
                  "daily_spend_cap_usd": 25,
                  "ip_allowlist": [],
                  "expires_at": null,
                  "last_used_at": "2026-11-07T14:03:00Z",
                  "created_at": "2026-11-01T09:00:00Z"
                },
                "schema": { "$ref": "#/components/schemas/ApiKey" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/keys/{id}/rotate": {
      "post": {
        "operationId": "rotateKey",
        "summary": "Rotate an API key",
        "description": "Create a replacement key with the same scopes and limits; the old key keeps working for `grace_period_hours` (default 24) and then stops. The new secret is shown once. Audited. Free. Scope: `keys:manage`.",
        "tags": ["Account"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["keys:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The key id.",
              "example": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The key id.",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "Rotation options.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "grace_period_hours": 24 },
              "schema": { "$ref": "#/components/schemas/RotateKeyRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The replacement key and the old key's grace window.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "key": {
                    "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "project_id": "prj_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "name": "outbound-agent prod",
                    "environment": "live",
                    "prefix": "vd_live_Ab12Cd",
                    "scopes": ["decisions:write", "index:read", "outcomes:write"],
                    "status": "active",
                    "rate_limit_per_minute": 600,
                    "daily_spend_cap_usd": 25,
                    "ip_allowlist": [],
                    "expires_at": null,
                    "last_used_at": null,
                    "created_at": "2026-11-07T14:00:00Z",
                    "secret": "vd_live_<shown-once>"
                  },
                  "previous_key": {
                    "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7W",
                    "valid_until": "2026-11-08T14:00:00Z"
                  }
                },
                "schema": { "$ref": "#/components/schemas/RotateKeyResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/limits": {
      "get": {
        "operationId": "getLimits",
        "summary": "Get limits",
        "description": "The rate limit, spend cap and request size limits that apply to the calling key, and the starter allowance left. Call it before batching. Free. Scope: `account:read`.",
        "tags": ["Account"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["account:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The limits.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "rate_limit": { "requests_per_minute": 600, "burst": 100 },
                  "daily_spend_cap_usd": 25,
                  "spent_today_usd": 1.42,
                  "request_limits": {
                    "max_body_bytes": 262144,
                    "max_roster_entries": 50,
                    "max_thread_messages": 40,
                    "max_message_bytes": 8192,
                    "max_page_limit": 200
                  },
                  "starter": {
                    "card_required": false,
                    "free_usd_remaining": 3.58,
                    "free_calls_remaining": 716
                  }
                },
                "schema": { "$ref": "#/components/schemas/LimitsResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/audit": {
      "get": {
        "operationId": "listAudit",
        "summary": "List audit log entries",
        "description": "The organization's append-only audit log (key changes, member changes, threshold changes, webhook endpoints, top-ups, exports, deletion requests), newest first. Free. Scope: `account:read`.",
        "tags": ["Account"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["account:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "key_created",
                "key_rotated",
                "key_revoked",
                "key_scopes_changed",
                "member_added",
                "member_removed",
                "member_role_changed",
                "threshold_changed",
                "vendor_key_added",
                "vendor_key_removed",
                "webhook_endpoint_created",
                "webhook_endpoint_deleted",
                "webhook_secret_rotated",
                "topup_created",
                "topup_completed",
                "export_requested",
                "deletion_requested",
                "key_updated",
                "member_invited",
                "totp_enabled",
                "totp_disabled"
              ],
              "description": "Only this action."
            },
            "required": false,
            "description": "Only this action.",
            "name": "action",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only entries at or after this time."
            },
            "required": false,
            "description": "Only entries at or after this time.",
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only entries before this time."
            },
            "required": false,
            "description": "Only entries before this time.",
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of audit entries.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "aud_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "action": "key_rotated",
                      "actor": {
                        "kind": "user",
                        "id": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                        "role": "owner"
                      },
                      "target": { "type": "key", "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V" },
                      "ip": "203.0.113.7",
                      "metadata": { "grace_period_hours": 24 },
                      "created_at": "2026-11-07T14:30:00Z"
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/AuditEntry" },
                      "description": "Audit entries, newest first."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Get the balance",
        "description": "Cash and test balances in US dollars. Billed calls also return `balance_usd`, so you rarely need this. Free. Scope: `account:read`.",
        "tags": ["Billing"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["account:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The balances.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "balance_usd": 18.32,
                  "test_balance_usd": 5,
                  "auto_topup": { "enabled": false, "threshold_usd": null, "pack_usd": null },
                  "as_of": "2026-11-07T14:03:01Z"
                },
                "schema": { "$ref": "#/components/schemas/BalanceResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/topup": {
      "post": {
        "operationId": "createTopup",
        "summary": "Buy a credit pack",
        "description": "Start buying a $20, $50 or $200 pack. Returns a Stripe Checkout URL for a human to pay; the balance is credited when Stripe confirms. Balance does not expire while the account is active. The call itself is free. Scope: `account:manage`.",
        "tags": ["Billing"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["account:manage"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The pack.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "pack_usd": 50 },
              "schema": { "$ref": "#/components/schemas/TopupRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The Checkout session.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "pck_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "pack_usd": 50,
                  "status": "pending",
                  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_example",
                  "expires_at": "2026-11-08T14:03:00Z"
                },
                "schema": { "$ref": "#/components/schemas/TopupResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Get usage",
        "description": "Calls, billed calls and charges between two UTC days, grouped by day, project, key or decision. Totals equal the ledger. Free. Scope: `account:read`.",
        "tags": ["Billing"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["account:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "date",
              "description": "First UTC day included."
            },
            "required": true,
            "description": "First UTC day included.",
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date",
              "description": "Last UTC day included."
            },
            "required": true,
            "description": "Last UTC day included.",
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": ["day", "project", "key", "decision"],
              "description": "Grouping; default `day`."
            },
            "required": false,
            "description": "Grouping; default `day`.",
            "name": "group_by",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "Usage over the window.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "from": "2026-11-01",
                  "to": "2026-11-07",
                  "group_by": "decision",
                  "rows": [
                    {
                      "group": "qualify_firm",
                      "calls": 1200,
                      "billed_calls": 1180,
                      "decision_usd": 5.9,
                      "vendor_usd": 0,
                      "total_usd": 5.9
                    },
                    {
                      "group": "triage_reply",
                      "calls": 310,
                      "billed_calls": 310,
                      "decision_usd": 0.93,
                      "vendor_usd": 0,
                      "total_usd": 0.93
                    }
                  ],
                  "totals": {
                    "calls": 1510,
                    "billed_calls": 1490,
                    "decision_usd": 6.83,
                    "vendor_usd": 0,
                    "total_usd": 6.83
                  }
                },
                "schema": { "$ref": "#/components/schemas/UsageResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/ledger": {
      "get": {
        "operationId": "listLedger",
        "summary": "List ledger entries",
        "description": "Every credit and debit on your balances, newest first, each linked to its decision or pack. Use it to reconcile spend; filter by `kind` or time. Free. Scope: `account:read`.",
        "tags": ["Billing"],
        "security": [{ "bearerAuth": [] }],
        "x-verdict-scopes": ["account:read"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "starter_credit",
                "pack_credit",
                "auto_topup_credit",
                "promotional_credit",
                "decision_debit",
                "vendor_debit",
                "refund",
                "adjustment"
              ],
              "description": "Only this kind."
            },
            "required": false,
            "description": "Only this kind.",
            "name": "kind",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only entries at or after this time."
            },
            "required": false,
            "description": "Only entries at or after this time.",
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only entries before this time."
            },
            "required": false,
            "description": "Only entries before this time.",
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of ledger entries.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "led_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "kind": "decision_debit",
                      "environment": "live",
                      "amount_usd": -0.005,
                      "balance_after_usd": 18.32,
                      "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "pack_id": null,
                      "description": "qualify_firm",
                      "created_at": "2026-11-07T14:03:00Z"
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/LedgerEntry" },
                      "description": "Ledger entries, newest first."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/webhooks/stripe": {
      "post": {
        "operationId": "receiveStripeWebhook",
        "summary": "Receive Stripe webhooks",
        "description": "Stripe calls this endpoint; agents never do. Operator setup: in the Stripe dashboard (test mode for staging, live mode for production) add a webhook endpoint with this URL, subscribe it to `checkout.session.completed`, `checkout.session.async_payment_succeeded`, `checkout.session.async_payment_failed` and `checkout.session.expired`, and store its signing secret (`whsec_...`) in Doppler as `STRIPE_WEBHOOK_SECRET`. Verdict verifies `Stripe-Signature` over the raw body before parsing anything (401 `unauthorized` on failure, nothing stored), reads the organization from the event's `metadata.org_id` and checks it against the pending pack named by `metadata.pack_id` (400 `invalid_request` when no organization resolves, nothing stored), records the event id, and credits the pack once when payment is confirmed. Idempotent on the Stripe event id: a replay returns 200 with `duplicate: true` and credits nothing; the same id with a different payload is refused with 400. Other event types are recorded and ignored. Free.",
        "tags": ["Inbound webhooks"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^t=[0-9]+(?:,v[01]=[0-9a-f]{64})+$",
              "description": "Stripe's signature over the raw body (`t=<unix seconds>,v1=<hex HMAC-SHA256>`), computed with the endpoint's signing secret. A missing or wrong signature, or a timestamp more than 5 minutes off, is refused with 401 `unauthorized` and nothing is stored.",
              "example": "t=1794060000,v1=5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e"
            },
            "required": true,
            "description": "Stripe's signature over the raw body (`t=<unix seconds>,v1=<hex HMAC-SHA256>`), computed with the endpoint's signing secret. A missing or wrong signature, or a timestamp more than 5 minutes off, is refused with 401 `unauthorized` and nothing is stored.",
            "name": "stripe-signature",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The Stripe event, unchanged.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "id": "evt_1QExampleCheckoutCompleted",
                "object": "event",
                "type": "checkout.session.completed",
                "livemode": false,
                "data": {
                  "object": {
                    "id": "cs_test_example",
                    "object": "checkout.session",
                    "mode": "payment",
                    "payment_status": "paid",
                    "amount_total": 5000,
                    "currency": "usd",
                    "client_reference_id": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "metadata": {
                      "org_id": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "pack_id": "pck_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "kind": "pack"
                    }
                  }
                }
              },
              "schema": { "$ref": "#/components/schemas/StripeWebhookBody" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The event was verified and recorded.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": { "received": true, "duplicate": false },
                "schema": { "$ref": "#/components/schemas/StripeWebhookReceipt" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/magic-link": {
      "post": {
        "operationId": "requestMagicLink",
        "summary": "Email a console sign-in link",
        "description": "Send a single-use sign-in link to an existing user's email. The link works for 10 minutes, once, and only in the browser (user agent) that asked for it. Always answers 202 so it does not reveal which emails have accounts. Rate limited per IP and per email. No key or session needed. Passwords are not supported.",
        "tags": ["Console"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "Who is signing in.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "email": "dana@northwind-ops.io" },
              "schema": { "$ref": "#/components/schemas/MagicLinkRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "A link was sent if the account exists.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": { "status": "sent", "expires_at": "2026-11-07T14:10:00Z" },
                "schema": { "$ref": "#/components/schemas/MagicLinkResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/magic-link/consume": {
      "post": {
        "operationId": "consumeMagicLink",
        "summary": "Sign in with a magic link",
        "description": "Exchange the token from a sign-in or invitation link for a console session, set as the httpOnly `verdict_session` cookie. The token is single use, expires 10 minutes after it was sent and must come from the same user agent that requested it; otherwise 401. An invitation link also adds the user to the inviting organization (creating the user if needed). No key or session needed.",
        "tags": ["Console"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The link token.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "token": "Ex4mpleMagicLinkTokenFromTheEmailLink00000001" },
              "schema": { "$ref": "#/components/schemas/ConsumeMagicLinkRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in; the cookie is set.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" },
              "set-cookie": {
                "description": "Sets or clears the httpOnly session cookie (`verdict_session`, Secure, SameSite=Lax).",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "user": {
                    "id": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "email": "dana@northwind-ops.io",
                    "totp_enabled": false
                  },
                  "orgs": [
                    {
                      "id": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "name": "Northwind Ops",
                      "slug": "northwind-ops",
                      "role": "owner",
                      "created_at": "2026-11-01T09:00:00Z"
                    }
                  ],
                  "mfa_verified": false,
                  "idle_expires_at": "2026-11-14T14:00:00Z"
                },
                "schema": { "$ref": "#/components/schemas/ConsoleSession" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/oauth/github/start": {
      "post": {
        "operationId": "startGithubOauth",
        "summary": "Start GitHub sign-in",
        "description": "Begin console sign-in with GitHub. Returns GitHub's authorization URL with a single-use `state` (valid 10 minutes) and sets a short-lived httpOnly cookie that binds the state to this browser. GitHub redirects back to the console, which posts `code` and `state` to `POST /v1/console/oauth/github/callback`. No key or session needed.",
        "tags": ["Console"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "Send the browser to `authorize_url`.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" },
              "set-cookie": {
                "description": "Sets or clears the httpOnly session cookie (`verdict_session`, Secure, SameSite=Lax).",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "authorize_url": "https://github.com/login/oauth/authorize?client_id=Iv1.example&state=example",
                  "expires_at": "2026-11-07T14:10:00Z"
                },
                "schema": { "$ref": "#/components/schemas/GithubOauthStartResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/oauth/github/callback": {
      "post": {
        "operationId": "githubOauthCallback",
        "summary": "Finish GitHub sign-in",
        "description": "Complete GitHub sign-in: Verdict checks `state` against the browser's state cookie, exchanges `code` with GitHub and signs in the existing user whose verified email matches the GitHub account's verified primary email (the GitHub identity is linked on first use). GitHub sign-in does not create accounts: sign up with `POST /v1/signup` first. Sets the `verdict_session` cookie. No key or session needed.",
        "tags": ["Console"],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "What GitHub returned.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "code": "gh-code-example",
                "state": "sssssssssssssssssssssssssssssssssssssssssss"
              },
              "schema": { "$ref": "#/components/schemas/GithubOauthCallbackRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in; the cookie is set.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" },
              "set-cookie": {
                "description": "Sets or clears the httpOnly session cookie (`verdict_session`, Secure, SameSite=Lax).",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "user": {
                    "id": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "email": "dana@northwind-ops.io",
                    "totp_enabled": false
                  },
                  "orgs": [
                    {
                      "id": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "name": "Northwind Ops",
                      "slug": "northwind-ops",
                      "role": "owner",
                      "created_at": "2026-11-01T09:00:00Z"
                    }
                  ],
                  "mfa_verified": false,
                  "idle_expires_at": "2026-11-14T14:00:00Z"
                },
                "schema": { "$ref": "#/components/schemas/ConsoleSession" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/session": {
      "get": {
        "operationId": "getConsoleSession",
        "summary": "Get the console session",
        "description": "Who is signed in, the organizations they belong to with their role in each, whether TOTP is still owed for this session, and when the session expires if left idle (7 days after last use). Using the session extends it. Session cookie required.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The session.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "user": {
                    "id": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "email": "dana@northwind-ops.io",
                    "totp_enabled": false
                  },
                  "orgs": [
                    {
                      "id": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "name": "Northwind Ops",
                      "slug": "northwind-ops",
                      "role": "owner",
                      "created_at": "2026-11-01T09:00:00Z"
                    }
                  ],
                  "mfa_verified": false,
                  "idle_expires_at": "2026-11-14T14:00:00Z"
                },
                "schema": { "$ref": "#/components/schemas/ConsoleSession" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      },
      "delete": {
        "operationId": "signOut",
        "summary": "Sign out",
        "description": "Revoke the current console session immediately and clear the cookie. Other sessions of the same user are unaffected. Session cookie required.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "Signed out.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" },
              "set-cookie": {
                "description": "Sets or clears the httpOnly session cookie (`verdict_session`, Secure, SameSite=Lax).",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "example": { "status": "signed_out" },
                "schema": { "$ref": "#/components/schemas/SignOutResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/totp/enrol": {
      "post": {
        "operationId": "enrolTotp",
        "summary": "Start TOTP enrolment",
        "description": "Generate a new TOTP secret for the signed-in user (RFC 6238: SHA-1, 6 digits, 30 seconds), shown once. It takes effect after `POST /v1/console/totp/verify` with a current code. Calling it again replaces a pending secret; when TOTP is already on, disable it first. Session cookie required.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "responses": {
          "201": {
            "description": "The pending secret.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "secret": "JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP",
                  "otpauth_uri": "otpauth://totp/Verdict:dana%40northwind-ops.io?secret=JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP&issuer=Verdict&algorithm=SHA1&digits=6&period=30"
                },
                "schema": { "$ref": "#/components/schemas/TotpEnrolResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/totp/verify": {
      "post": {
        "operationId": "verifyTotp",
        "summary": "Verify a TOTP code",
        "description": "Check a current TOTP code. With a pending enrolment it turns TOTP on (audited as `totp_enabled`); when TOTP is already on it completes sign-in for this session. Either way the session is marked as having passed TOTP. A wrong code answers 401; attempts are rate limited. Session cookie required.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The code.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "code": "123456" },
              "schema": { "$ref": "#/components/schemas/TotpCodeRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The code was accepted.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": { "totp_enabled": true, "mfa_verified": true },
                "schema": { "$ref": "#/components/schemas/TotpStatusResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/totp/disable": {
      "post": {
        "operationId": "disableTotp",
        "summary": "Turn TOTP off",
        "description": "Turn TOTP off for the signed-in user, given a current code. Refused with 403 while the user owns an organization with more than one member, where TOTP is required (spec 9.1). Audited as `totp_disabled` in each of the user's organizations. Session cookie required.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "A current code.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "code": "123456" },
              "schema": { "$ref": "#/components/schemas/TotpCodeRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "TOTP is off.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": { "totp_enabled": false, "mfa_verified": false },
                "schema": { "$ref": "#/components/schemas/TotpStatusResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/orgs": {
      "get": {
        "operationId": "listConsoleOrgs",
        "summary": "List my organizations",
        "description": "The organizations the signed-in user is a member of, with their role in each. Use the `id` in the org-scoped console endpoints. Session cookie required.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The organizations.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "name": "Northwind Ops",
                      "slug": "northwind-ops",
                      "role": "owner",
                      "created_at": "2026-11-01T09:00:00Z"
                    }
                  ]
                },
                "schema": { "$ref": "#/components/schemas/ConsoleOrgsResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/orgs/{org_id}/members": {
      "get": {
        "operationId": "listMembers",
        "summary": "List members",
        "description": "The organization's members with their roles and TOTP state, and the pending invitations. A user who is not a member gets 404. Roles: `owner`, `admin`, `developer`, `billing`, `read_only` (checked server-side). When the user has TOTP on, the session must have passed `POST /v1/console/totp/verify`; an owner of an organization with more than one member must have TOTP on (spec 9.1), otherwise 403.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "x-verdict-roles": ["owner", "admin", "developer", "billing", "read_only"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The organization.",
              "example": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The organization.",
            "name": "org_id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "Members and invitations.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "members": [
                    {
                      "user_id": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "email": "dana@northwind-ops.io",
                      "role": "owner",
                      "totp_enabled": true,
                      "joined_at": "2026-11-01T09:00:00Z"
                    }
                  ],
                  "invites": [
                    {
                      "id": "0b8f6c1e-3d2a-4f5b-9c7d-1e2f3a4b5c6d",
                      "email": "sam@northwind-ops.io",
                      "role": "developer",
                      "invited_by": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "expires_at": "2026-11-14T14:00:00Z",
                      "created_at": "2026-11-07T14:00:00Z"
                    }
                  ]
                },
                "schema": { "$ref": "#/components/schemas/MembersResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/orgs/{org_id}/invites": {
      "post": {
        "operationId": "createInvite",
        "summary": "Invite a member",
        "description": "Invite someone by email with a role. They get a magic link (valid 7 days, single use) that adds them to the organization when they sign in with it. Only an owner may invite an owner; inviting an existing member answers 409. Audited as `member_invited` (and `member_added` on acceptance). Roles: `owner`, `admin` (checked server-side). When the user has TOTP on, the session must have passed `POST /v1/console/totp/verify`; an owner of an organization with more than one member must have TOTP on (spec 9.1), otherwise 403.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "x-verdict-roles": ["owner", "admin"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The organization.",
              "example": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The organization.",
            "name": "org_id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
              "example": "5f0c8a52-3d7e-4b8a-9b1e-2f6d7c4a9e01"
            },
            "required": true,
            "description": "A UUID you generate per logical request. Required on every POST. Repeating it within 24 hours returns the stored response and bills nothing; reusing it with a different body returns 409 `idempotency_conflict`.",
            "name": "idempotency-key",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "Who to invite.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "email": "sam@northwind-ops.io", "role": "developer" },
              "schema": { "$ref": "#/components/schemas/CreateInviteRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The invitation was sent.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "id": "0b8f6c1e-3d2a-4f5b-9c7d-1e2f3a4b5c6d",
                  "email": "sam@northwind-ops.io",
                  "role": "developer",
                  "invited_by": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "expires_at": "2026-11-14T14:00:00Z",
                  "created_at": "2026-11-07T14:00:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Invite" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/orgs/{org_id}/members/{user_id}": {
      "patch": {
        "operationId": "updateMember",
        "summary": "Change a member's role",
        "description": "Change a member's role. Only an owner may grant `owner` or change an owner's role, and the last owner cannot be demoted (409). Audited as `member_role_changed`. Roles: `owner`, `admin` (checked server-side). When the user has TOTP on, the session must have passed `POST /v1/console/totp/verify`; an owner of an organization with more than one member must have TOTP on (spec 9.1), otherwise 403.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "x-verdict-roles": ["owner", "admin"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The organization.",
              "example": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The organization.",
            "name": "org_id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The member's user id.",
              "example": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The member's user id.",
            "name": "user_id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The new role.",
          "required": true,
          "content": {
            "application/json": {
              "example": { "role": "admin" },
              "schema": { "$ref": "#/components/schemas/UpdateMemberRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The member, updated.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "user_id": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "email": "dana@northwind-ops.io",
                  "role": "admin",
                  "totp_enabled": true,
                  "joined_at": "2026-11-01T09:00:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Member" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      },
      "delete": {
        "operationId": "removeMember",
        "summary": "Remove a member",
        "description": "Remove a member from the organization (any member may remove themselves). Only an owner may remove an owner, and the last owner cannot be removed (409). The user's sessions stay valid for their other organizations. Audited as `member_removed`. Roles: `owner`, `admin` (checked server-side). When the user has TOTP on, the session must have passed `POST /v1/console/totp/verify`; an owner of an organization with more than one member must have TOTP on (spec 9.1), otherwise 403.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "x-verdict-roles": ["owner", "admin"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The organization.",
              "example": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The organization.",
            "name": "org_id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The member's user id.",
              "example": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The member's user id.",
            "name": "user_id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "The member that was removed.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "user_id": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "email": "dana@northwind-ops.io",
                  "role": "owner",
                  "totp_enabled": true,
                  "joined_at": "2026-11-01T09:00:00Z"
                },
                "schema": { "$ref": "#/components/schemas/Member" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "409": { "$ref": "#/components/responses/Error409" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    },
    "/v1/console/orgs/{org_id}/audit": {
      "get": {
        "operationId": "listConsoleAudit",
        "summary": "List audit log entries (console)",
        "description": "The organization's append-only audit log, newest first, exactly as `GET /v1/audit` returns it to a key with `account:read`. In the console it is limited to owners and admins (ADR-0010). Roles: `owner`, `admin` (checked server-side). When the user has TOTP on, the session must have passed `POST /v1/console/totp/verify`; an owner of an organization with more than one member must have TOTP on (spec 9.1), otherwise 403.",
        "tags": ["Console"],
        "security": [{ "sessionCookie": [] }],
        "x-verdict-roles": ["owner", "admin"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "The organization.",
              "example": "org_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"
            },
            "required": true,
            "description": "The organization.",
            "name": "org_id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512,
              "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page."
            },
            "required": false,
            "description": "Opaque cursor from the `next_cursor` of the previous page. Omit it for the first page.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "description": "Page size, 1 to 200. Default 50.",
              "example": 50
            },
            "required": false,
            "description": "Page size, 1 to 200. Default 50.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "key_created",
                "key_rotated",
                "key_revoked",
                "key_scopes_changed",
                "member_added",
                "member_removed",
                "member_role_changed",
                "threshold_changed",
                "vendor_key_added",
                "vendor_key_removed",
                "webhook_endpoint_created",
                "webhook_endpoint_deleted",
                "webhook_secret_rotated",
                "topup_created",
                "topup_completed",
                "export_requested",
                "deletion_requested",
                "key_updated",
                "member_invited",
                "totp_enabled",
                "totp_disabled"
              ],
              "description": "Only this action."
            },
            "required": false,
            "description": "Only this action.",
            "name": "action",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only entries at or after this time."
            },
            "required": false,
            "description": "Only entries at or after this time.",
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only entries before this time."
            },
            "required": false,
            "description": "Only entries before this time.",
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$",
              "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
              "example": "2026-11-01"
            },
            "required": false,
            "description": "API version to use, a date. Defaults to the version current when the key was created. The current version is `2026-11-01`.",
            "name": "x-verdict-version",
            "in": "header"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of audit entries.",
            "headers": {
              "x-request-id": { "$ref": "#/components/headers/XRequestId" },
              "x-ratelimit-limit": { "$ref": "#/components/headers/XRateLimitLimit" },
              "x-ratelimit-remaining": { "$ref": "#/components/headers/XRateLimitRemaining" },
              "x-ratelimit-reset": { "$ref": "#/components/headers/XRateLimitReset" }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "aud_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                      "action": "key_rotated",
                      "actor": {
                        "kind": "user",
                        "id": "usr_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                        "role": "owner"
                      },
                      "target": { "type": "key", "id": "key_01JC3Z4Y8R9K2M5N7P1Q3S5T7V" },
                      "ip": "203.0.113.7",
                      "metadata": { "grace_period_hours": 24 },
                      "created_at": "2026-11-07T14:30:00Z"
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/AuditEntry" },
                      "description": "Audit entries, newest first."
                    },
                    "next_cursor": {
                      "type": ["string", "null"],
                      "description": "Pass as `cursor` to fetch the next page. `null` when this is the last page."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Whether another page follows."
                    }
                  },
                  "required": ["data", "next_cursor", "has_more"]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" }
        }
      }
    }
  },
  "webhooks": {
    "scoredEvent": {
      "post": {
        "operationId": "scoredEventWebhook",
        "summary": "A scored event for a watch",
        "description": "Verdict POSTs this to a watch's `webhook_url` for each event whose `relevant` is at least `min_p`. Verify `Verdict-Signature` against the raw body before parsing, dedupe on `id`, and answer 2xx within 10 seconds; anything else is retried with exponential backoff for 24 hours. Billed once (one `score_signal`) when delivered, never per attempt.",
        "tags": ["Watches"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^t=[0-9]+(?:,v1=[0-9a-f]{64})+$",
              "description": "`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with the watch's signing secret>`. Several `v1` values appear while a secret rotation overlaps. Reject the delivery if no `v1` matches or `t` is more than 5 minutes from your clock.",
              "example": "t=1794060000,v1=5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e"
            },
            "required": true,
            "description": "`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with the watch's signing secret>`. Several `v1` values appear while a secret rotation overlaps. Reject the delivery if no `v1` matches or `t` is more than 5 minutes from your clock.",
            "name": "verdict-signature",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The scored event.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "id": "dlv_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                "type": "event.scored",
                "created_at": "2026-11-07T15:00:03Z",
                "watch_id": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                "event": {
                  "id": "evt_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "type": "filing",
                  "firm_id": "frm_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "occurred_at": "2026-11-03T21:15:00Z",
                  "observed_at": "2026-11-04T02:05:00Z",
                  "source": "sec_edgar",
                  "source_url": "https://www.sec.gov/Archives/edgar/data/1601234/000160123426000004/xslFormDX01/primary_doc.xml",
                  "confidence": 0.97,
                  "attributes": {
                    "filing_type": "sec_form_d",
                    "accession_number": "0001601234-26-000004",
                    "title": "Notice of Exempt Offering of Securities"
                  },
                  "score": {
                    "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                    "relevant": 0.78,
                    "act_now": 0.64,
                    "window_days": 21,
                    "answer": "relevant",
                    "reason_code": "event_relevant_and_timely"
                  }
                },
                "score": {
                  "decision_id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                  "relevant": 0.78,
                  "act_now": 0.64,
                  "window_days": 21,
                  "answer": "relevant",
                  "reason_code": "event_relevant_and_timely"
                }
              },
              "schema": { "$ref": "#/components/schemas/ScoredEventDelivery" }
            }
          }
        },
        "responses": { "200": { "description": "Any 2xx acknowledges the delivery." } }
      }
    },
    "watchChallenge": {
      "post": {
        "operationId": "watchChallengeWebhook",
        "summary": "Verify a new webhook URL",
        "description": "Sent once when a watch is created. Respond 200 with `{\"challenge\": <challenge>}` within 10 seconds; the watch becomes `active` only then. Signed with `Verdict-Signature` like deliveries.",
        "tags": ["Watches"],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^t=[0-9]+(?:,v1=[0-9a-f]{64})+$",
              "description": "`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with the watch's signing secret>`. Several `v1` values appear while a secret rotation overlaps. Reject the delivery if no `v1` matches or `t` is more than 5 minutes from your clock.",
              "example": "t=1794060000,v1=5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e"
            },
            "required": true,
            "description": "`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with the watch's signing secret>`. Several `v1` values appear while a secret rotation overlaps. Reject the delivery if no `v1` matches or `t` is more than 5 minutes from your clock.",
            "name": "verdict-signature",
            "in": "header"
          }
        ],
        "requestBody": {
          "description": "The challenge.",
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "type": "webhook.challenge",
                "watch_id": "wch_01JC3Z4Y8R9K2M5N7P1Q3S5T7V",
                "challenge": "cccccccccccccccccccccccccccccccccccccccc"
              },
              "schema": { "$ref": "#/components/schemas/WebhookChallenge" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The challenge, echoed.",
            "content": {
              "application/json": {
                "example": { "challenge": "cccccccccccccccccccccccccccccccccccccccc" },
                "schema": {
                  "type": "object",
                  "properties": {
                    "challenge": {
                      "type": "string",
                      "description": "The `challenge` value, echoed."
                    }
                  },
                  "required": ["challenge"]
                }
              }
            }
          }
        }
      }
    }
  }
}
