{
  "openapi": "3.0.3",
  "info": {
    "title": "ZeroDrift Public API",
    "version": "1.0.0",
    "description": "Complete reference for the ZeroDrift public API. This document aggregates every endpoint (Validate, Custom Policies, Activities, and Rule Packs) into a single OpenAPI specification."
  },
  "servers": [
    {
      "url": "https://api.zerodrift.ai"
    }
  ],
  "tags": [
    {
      "name": "Validate",
      "description": "Content validation and result polling"
    },
    {
      "name": "Custom Policies",
      "description": "Import policy documents, extract and manage custom rules"
    },
    {
      "name": "Activities",
      "description": "Eventually-consistent Activity Center feed"
    },
    {
      "name": "Rule Packs",
      "description": "Managed and custom rule pack catalog"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    }
  ],
  "paths": {
    "/api/v3/content/validate": {
      "post": {
        "summary": "Validate Content",
        "operationId": "validateContent",
        "tags": [
          "Validate"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ItemValidateV3Email"
              },
              "example": {
                "content": "Guaranteed 15% returns, no risk. Act now — this opportunity will not last!",
                "model_engine": "anchor_3_0",
                "mode": "sync"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted (async) — poll the returned job URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateAsyncAccepted"
                },
                "example": {
                  "api_version": "v3",
                  "job_id": "a1b2c3",
                  "status": "queued",
                  "mode": "async",
                  "model_engine": "anchor_3_0",
                  "poll": {
                    "method": "GET",
                    "url": "/api/v3/jobs/a1b2c3"
                  }
                }
              }
            }
          },
          "200": {
            "description": "Completed (sync) — full v3 result envelope inline",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationResultResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid model_engine or unsupported parameters"
          },
          "403": {
            "description": "Forbidden — missing, invalid, inactive, or unresolved API key"
          },
          "422": {
            "description": "Unprocessable Entity"
          }
        }
      }
    },
    "/api/v3/jobs/{job_id}": {
      "get": {
        "summary": "Get Validation Results",
        "operationId": "getValidationResult",
        "tags": [
          "Validate"
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Job identifier returned by POST /api/v3/content/validate",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Validation result (status: started | in_progress | done | failed)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationResultResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden — missing, invalid, inactive, or unresolved API key"
          },
          "404": {
            "description": "Job Not Found"
          }
        }
      }
    },
    "/api/policies/import": {
      "post": {
        "summary": "Import Policy",
        "operationId": "importPolicy",
        "tags": [
          "Custom Policies"
        ],
        "description": "Import a policy document (inline base64 or plain text) and extract candidate rules asynchronously. Status transitions: processing → pending_review (rules extracted) | no_rules_found (nothing extractable) | failed (extraction error). Base64 payload size is limited by API Gateway/Lambda constraints — use the presigned-URL upload flow (Get Import Presigned URL → Start Import) for larger files.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PolicyImportRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Import Accepted — processing asynchronously",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyImportAccepted"
                },
                "example": {
                  "import_id": "550e8400-e29b-41d4-a716-446655440000",
                  "status": "processing",
                  "message": "Import accepted. Poll GET /api/policies/import/{import_id} for results."
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — missing or invalid fields"
          },
          "403": {
            "description": "Forbidden — invalid API key or inactive customer"
          },
          "422": {
            "description": "Unprocessable Entity — cannot extract text from document"
          }
        }
      },
      "get": {
        "summary": "List Policy Imports",
        "operationId": "listPolicyImports",
        "tags": [
          "Custom Policies"
        ],
        "responses": {
          "200": {
            "description": "List of imports for the authenticated customer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyImportListResponse"
                },
                "example": {
                  "imports": [
                    {
                      "import_id": "550e8400-e29b-41d4-a716-446655440000",
                      "status": "pending_review",
                      "rule_count": 5,
                      "created_at": "2025-12-23T10:30:00Z"
                    }
                  ],
                  "count": 1
                }
              }
            }
          },
          "403": {
            "description": "Forbidden — invalid API key or inactive customer"
          }
        }
      }
    },
    "/api/policies/import/presigned_url": {
      "post": {
        "summary": "Get Import Presigned URL",
        "operationId": "getPolicyImportPresignedUrl",
        "tags": [
          "Custom Policies"
        ],
        "description": "Step 1 of the large-file import flow. Returns an import_id and a presigned S3 PUT URL. Upload the raw policy file directly to S3 with the exact required_headers, then call Start Import with the import_id.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PolicyImportPresignedUrlRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Presigned URL generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyImportPresignedUrlResponse"
                },
                "example": {
                  "import_id": "550e8400-e29b-41d4-a716-446655440000",
                  "upload_url": "https://example-bucket.s3.amazonaws.com/policy-imports/raw/550e8400-e29b-41d4-a716-446655440000.bin?X-Amz-Algorithm=...",
                  "upload_method": "PUT",
                  "s3_bucket": "example-bucket",
                  "s3_key": "policy-imports/raw/550e8400-e29b-41d4-a716-446655440000.bin",
                  "required_headers": {
                    "Content-Type": "application/pdf"
                  },
                  "expires_in_seconds": 900,
                  "expires_at": "2026-06-15T10:45:00Z",
                  "max_upload_bytes": 1073741824,
                  "next_steps": {
                    "step_1": "PUT the raw file bytes to upload_url with the exact required_headers",
                    "step_2": "POST /api/policies/import/start with { \"import_id\": \"550e8400-...\" }"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid JSON body"
          },
          "403": {
            "description": "Forbidden — invalid API key, inactive customer, or read_only API key (requires full_access)"
          },
          "500": {
            "description": "Internal Server Error — document storage misconfigured or presigned URL generation failed"
          }
        }
      }
    },
    "/api/policies/import/start": {
      "post": {
        "summary": "Start Import",
        "operationId": "startPolicyImport",
        "tags": [
          "Custom Policies"
        ],
        "description": "Step 3 of the large-file import flow. Verifies the uploaded S3 object exists and passed malware scanning, then triggers asynchronous rule extraction. Returns status: processing (extraction kicked off) or scan_pending (malware scan still running — no import record created yet; retry shortly).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PolicyImportStartRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Import accepted or scan still pending",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyImportStartAccepted"
                },
                "examples": {
                  "processing": {
                    "summary": "Upload scanned clean, import kicked off",
                    "value": {
                      "import_id": "550e8400-e29b-41d4-a716-446655440000",
                      "status": "processing",
                      "message": "Import accepted. Poll GET /api/policies/import/{import_id} for results."
                    }
                  },
                  "scan_pending": {
                    "summary": "Malware scan still running — retry shortly",
                    "value": {
                      "import_id": "550e8400-e29b-41d4-a716-446655440000",
                      "status": "scan_pending",
                      "message": "File is still being scanned. Retry POST /api/policies/import/start shortly."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — missing import_id"
          },
          "403": {
            "description": "Forbidden — invalid API key, inactive customer, read_only key, or import belongs to another customer"
          },
          "404": {
            "description": "Not Found — no uploaded object for this import_id"
          },
          "409": {
            "description": "Conflict — import already started or completed"
          },
          "413": {
            "description": "Payload Too Large — uploaded file exceeds the maximum allowed size"
          },
          "422": {
            "description": "Unprocessable Entity — malware detected or file type not scannable"
          },
          "500": {
            "description": "Internal Server Error — do not retry on the same import_id"
          }
        }
      }
    },
    "/api/policies/import/{import_id}": {
      "get": {
        "summary": "Get Import Details",
        "operationId": "getPolicyImportDetails",
        "tags": [
          "Custom Policies"
        ],
        "parameters": [
          {
            "name": "import_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Import details including extracted rules",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyImportDetails"
                },
                "example": {
                  "import_id": "550e8400-e29b-41d4-a716-446655440000",
                  "status": "pending_review",
                  "rule_count": 3,
                  "created_at": "2026-01-15T10:30:00Z",
                  "rules": [
                    {
                      "id": "no_misleading_claims",
                      "type": "AI_SIGNAL",
                      "name": "No Misleading Claims",
                      "action": "flag",
                      "severity": "high",
                      "confidence": 0.95
                    },
                    {
                      "id": "benchmark_comparison_required",
                      "type": "AI_SIGNAL",
                      "name": "Benchmark Comparison Required",
                      "action": "fix",
                      "severity": "medium",
                      "confidence": 0.88,
                      "suggested_text": "Performance results should be compared to an appropriate benchmark index."
                    },
                    {
                      "id": "risk_disclosure_present",
                      "type": "REQUIRE_NEAR",
                      "name": "Risk Disclosure Near Performance Data",
                      "action": "flag",
                      "severity": "high",
                      "confidence": 0.92
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Import Not Found"
          }
        }
      }
    },
    "/api/policies/import/{import_id}/rules/{rule_id}": {
      "patch": {
        "summary": "Edit Imported Rule",
        "operationId": "editImportedRule",
        "tags": [
          "Custom Policies"
        ],
        "description": "Partially edit prompt, remediation guidance, or extraction confidence for one rule while its import is pending review. Explicit null clears prompt or fix_note. Requires a full_access API key.",
        "parameters": [
          {
            "name": "import_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "description": "Extracted (unprefixed) rule ID within the import",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportedRuleUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated imported rule",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractedPolicyRule"
                }
              }
            }
          },
          "400": {
            "description": "Invalid imported rule update"
          },
          "403": {
            "description": "Forbidden — full_access API key required"
          },
          "404": {
            "description": "Import or imported rule not found"
          },
          "409": {
            "description": "Import is not pending review, or changed concurrently"
          }
        }
      }
    },
    "/api/policies/import/{import_id}/activate": {
      "post": {
        "summary": "Activate Rules",
        "operationId": "activateImportedRules",
        "tags": [
          "Custom Policies"
        ],
        "description": "Activate rules extracted from a pending policy import. If rule_ids is omitted, all extracted rules are activated.",
        "parameters": [
          {
            "name": "import_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PolicyActivateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rules activated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyActivateResponse"
                },
                "example": {
                  "import_id": "550e8400-e29b-41d4-a716-446655440000",
                  "status": "activated",
                  "activated_count": 5,
                  "activated_rule_ids": [
                    "cust_abc123_no_misleading_claims"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — no matching rule_ids"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Import Not Found"
          },
          "409": {
            "description": "Conflict — import already activated or rejected, or a conflicting rule_id (see conflicting_rule_id on the error body)"
          }
        }
      }
    },
    "/api/policies/rules": {
      "get": {
        "summary": "List Rules",
        "operationId": "listActiveRules",
        "tags": [
          "Custom Policies"
        ],
        "description": "List all rules for the authenticated customer with active/deactivated status: default rules (tagged with rule_pack_id and scenario IDs) and custom rules (tagged with import_id).",
        "responses": {
          "200": {
            "description": "Active rules list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveRulesListResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden — missing, invalid, or inactive API key"
          }
        }
      },
      "post": {
        "summary": "Create Custom Rule",
        "operationId": "createCustomRule",
        "tags": [
          "Custom Policies"
        ],
        "description": "Create a customer-owned AI_SIGNAL, REGEX, or REQUIRE_NEAR rule with a server-generated rule ID.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomRuleCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Custom rule created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomRuleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid custom rule definition"
          },
          "403": {
            "description": "Forbidden — full_access API key required"
          },
          "409": {
            "description": "Generated rule ID conflict"
          }
        }
      }
    },
    "/api/policies/rules/{rule_id}": {
      "get": {
        "summary": "Get Custom Rule",
        "operationId": "getCustomRule",
        "tags": [
          "Custom Policies"
        ],
        "description": "Return the full editable definition for a customer-owned custom rule.",
        "parameters": [
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Custom rule definition",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomRuleResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Custom rule not found"
          }
        }
      },
      "patch": {
        "summary": "Edit Custom Rule",
        "operationId": "updateCustomRule",
        "tags": [
          "Custom Policies"
        ],
        "description": "Partially update an existing customer-owned rule. Rule type and metadata are immutable; supply only fields applicable to the stored rule type.",
        "parameters": [
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomRuleUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated custom rule",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomRuleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid custom rule update"
          },
          "403": {
            "description": "Forbidden — full_access API key required"
          },
          "404": {
            "description": "Custom rule not found"
          },
          "409": {
            "description": "Concurrent custom rule update"
          }
        }
      }
    },
    "/api/policies/rules/deactivate": {
      "post": {
        "summary": "Deactivate Rules",
        "operationId": "deactivateRules",
        "tags": [
          "Custom Policies"
        ],
        "description": "Deactivate rules by rule_pack_id, import_id, rule_pack_scenario_id, or rule_ids. Custom rules are soft-deactivated (preserved for audit); default rules are recorded as deactivated on the customer record. At least one selector field is required.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RuleSelectorRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rules deactivated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RuleDeactivateResponse"
                },
                "example": {
                  "deactivated_custom_count": 2,
                  "deactivated_custom_rule_ids": [
                    "cust_abc123_require_risk_disclosure",
                    "cust_abc123_past_performance_disclaimer"
                  ],
                  "deactivated_default_count": 47,
                  "deactivated_default_rule_ids": [
                    "signal_mnpi_leak",
                    "signal_promissory_tone"
                  ],
                  "errors": []
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — at least one of rule_pack_id, import_id, rule_pack_scenario_id, or rule_ids is required"
          },
          "403": {
            "description": "Forbidden — import does not belong to customer"
          },
          "404": {
            "description": "Import not found"
          }
        }
      }
    },
    "/api/policies/rules/activate": {
      "post": {
        "summary": "Reactivate Rules",
        "operationId": "reactivateRules",
        "tags": [
          "Custom Policies"
        ],
        "description": "Re-activate previously deactivated rules by rule_pack_id, import_id, rule_pack_scenario_id, or rule_ids. For default rules, removes the rule from the customer's deactivated list; for custom rules, sets status back to active. At least one selector field is required. (Not to be confused with \"Activate Rules\", which activates rules freshly extracted from a policy import.)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RuleSelectorRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rules reactivated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RuleActivateResponse"
                },
                "example": {
                  "activated_custom_count": 3,
                  "activated_custom_rule_ids": [
                    "cust_abc123_require_risk_disclosure",
                    "cust_abc123_past_performance_disclaimer",
                    "cust_abc123_no_specific_client_returns"
                  ],
                  "activated_default_count": 0,
                  "activated_default_rule_ids": [],
                  "errors": []
                }
              }
            }
          },
          "400": {
            "description": "Bad request — invalid JSON body, malformed rule_ids, or no selectors supplied"
          },
          "403": {
            "description": "Forbidden — the supplied import_id belongs to a different customer"
          },
          "404": {
            "description": "Not Found — the supplied import_id does not exist (rule_pack_id / rule_pack_scenario_id failures are instead accumulated into the response's errors array with a 200)"
          }
        }
      }
    },
    "/api/activities": {
      "get": {
        "summary": "List Activities",
        "operationId": "listActivities",
        "tags": [
          "Activities"
        ],
        "description": "Newest-first, eventually-consistent Activity Center feed. Date ranges are capped at 30 days.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "status",
            "in": "query",
            "style": "form",
            "explode": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "auto_fixed",
                  "blocked",
                  "warned",
                  "passed"
                ]
              }
            }
          },
          {
            "name": "agent_id",
            "in": "query",
            "style": "form",
            "explode": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "source",
            "in": "query",
            "style": "form",
            "explode": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "rule_id",
            "in": "query",
            "style": "form",
            "explode": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Activity feed page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivityListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date range (maximum 30 days)"
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      }
    },
    "/api/activities/{activity_id}": {
      "get": {
        "summary": "Get Activity",
        "operationId": "getActivity",
        "tags": [
          "Activities"
        ],
        "parameters": [
          {
            "name": "activity_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full activity timeline and rule detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Activity"
                }
              }
            }
          },
          "404": {
            "description": "Not found, including cross-customer access"
          }
        }
      }
    },
    "/api/rulepacks/": {
      "get": {
        "summary": "Rule Packs",
        "operationId": "listRulePacks",
        "tags": [
          "Rule Packs"
        ],
        "description": "Returns the normalized policy catalog for the active authenticated customer. Managed entries reflect the Anchor 3.0 runtime vocabulary; custom entries are activated policy imports. Supplying id selects detail and requires type.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Rulepack ID for detail lookup; requires type",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter list results or disambiguate a detail ID",
            "schema": {
              "type": "string",
              "enum": [
                "managed",
                "custom"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 15
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Case-insensitive match against ID, name, or description",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "active",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated summaries for list requests, or one detailed rulepack",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RulepackCatalogResponse"
                },
                "examples": {
                  "list": {
                    "value": {
                      "data": [
                        {
                          "id": "zd-us-securities",
                          "name": "US Securities and Investment Communications",
                          "description": "SEC and FINRA communication compliance",
                          "type": "managed",
                          "engine": "anchor_3_0",
                          "active": true,
                          "total_rules": 72,
                          "active_rules": 72,
                          "inactive_rules": 0,
                          "publisher": "ZeroDrift",
                          "version": "3.0.0",
                          "domain": "securities",
                          "jurisdictions": [
                            "US"
                          ],
                          "last_updated": "2026-07-28"
                        }
                      ],
                      "meta": {
                        "current_page": 1,
                        "per_page": 15,
                        "total": 13,
                        "last_page": 1
                      }
                    }
                  },
                  "detail": {
                    "value": {
                      "data": {
                        "id": "zd-us-securities",
                        "name": "US Securities and Investment Communications",
                        "type": "managed",
                        "engine": "anchor_3_0",
                        "active": true,
                        "total_rules": 72,
                        "active_rules": 72,
                        "inactive_rules": 0,
                        "rules": [
                          {
                            "id": "guarantee_of_returns",
                            "name": "Promissory Tone",
                            "description": "Promissory words are risky",
                            "type": "AI_SIGNAL",
                            "severity": "major",
                            "verdict": "do_not_send",
                            "active": true,
                            "lifecycle": {
                              "status": "in_force",
                              "last_reviewed": "2026-07-28"
                            },
                            "citations": [
                              {
                                "framework": "FINRA Rule 2210",
                                "jurisdictions": [
                                  "US"
                                ]
                              }
                            ],
                            "remediation": {
                              "kind": "rewrite",
                              "note": "Review with compliance"
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid pagination, filter, or detail selector"
          },
          "403": {
            "description": "Forbidden — missing, invalid, inactive, or unresolved API key"
          },
          "404": {
            "description": "Rulepack not found or not accessible to this customer"
          },
          "500": {
            "description": "Catalog backend read failed or stored catalog data is inconsistent"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "name": "x-api-key",
        "in": "header",
        "description": "API key issued to your ZeroDrift customer account. Keys are either read_only or full_access; write/mutating endpoints require full_access."
      }
    },
    "schemas": {
      "ItemValidateV3Email": {
        "type": "object",
        "title": "ItemValidateV3Email",
        "description": "V3 content validation request with Anchor 3.0 SLM model engine support. The text to validate is supplied as content; email_text is the deprecated alias of the same field and is still accepted. Exactly one of content or email_text must be present, and content wins if both are sent.",
        "required": [
          "model_engine",
          "mode"
        ],
        "anyOf": [
          {
            "required": [
              "content"
            ]
          },
          {
            "required": [
              "email_text"
            ]
          }
        ],
        "properties": {
          "content": {
            "type": "string",
            "description": "Plain text content to validate"
          },
          "email_text": {
            "type": "string",
            "deprecated": true,
            "description": "Deprecated alias for content, kept for older callers. Use content instead."
          },
          "model_engine": {
            "type": "string",
            "enum": [
              "anchor_3_0"
            ],
            "default": "anchor_3_0",
            "description": "Validation engine. Use anchor_3_0 to run the Anchor 3.0 compliance SLM. Results include relevant_rule_ids and input/output token counts."
          },
          "mode": {
            "type": "string",
            "enum": [
              "async",
              "sync"
            ],
            "default": "async",
            "description": "async returns 202 + job_id to poll; sync runs inline for short content and returns 200, falling back to async if it would exceed the inline budget."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional metadata merged into the job (document_type is forced to \"email\")"
          },
          "document_category": {
            "type": "string",
            "description": "Optional explicit scenario id (defaults to scenario_email_general)"
          },
          "validation_scope": {
            "type": "object",
            "additionalProperties": false,
            "description": "Optional nested form for narrowing validation to a subset of already-active rules/rulepacks/imports",
            "properties": {
              "rules": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "rulepacks": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "imports": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ValidateAsyncAccepted": {
        "type": "object",
        "title": "ValidateAsyncAccepted",
        "properties": {
          "api_version": {
            "type": "string"
          },
          "job_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "async"
            ]
          },
          "model_engine": {
            "type": "string",
            "enum": [
              "anchor_3_0"
            ]
          },
          "poll": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "enum": [
                  "GET"
                ]
              },
              "url": {
                "type": "string"
              }
            }
          }
        }
      },
      "ValidationResultResponse": {
        "type": "object",
        "title": "ValidationResultResponse",
        "properties": {
          "api_version": {
            "type": "string"
          },
          "job_id": {
            "type": "string",
            "description": "Async validation job identifier"
          },
          "status": {
            "type": "string",
            "enum": [
              "started",
              "in_progress",
              "done",
              "failed"
            ]
          },
          "model_engine": {
            "type": "string",
            "enum": [
              "anchor_3_0"
            ]
          },
          "started": {
            "type": "string",
            "description": "Time when the validation job started"
          },
          "timestamp": {
            "type": "string",
            "description": "Time when this result snapshot was generated"
          },
          "error": {
            "type": "string",
            "description": "Error details (present only when status is failed)"
          },
          "overall_status": {
            "type": "string",
            "enum": [
              "approved",
              "needs_changes",
              "do not send"
            ]
          },
          "summary": {
            "type": "object",
            "properties": {
              "do_not_send": {
                "type": "integer"
              },
              "send_with_caution": {
                "type": "integer"
              },
              "document_pages": {
                "type": "integer"
              }
            }
          },
          "violating_line_count": {
            "type": "integer"
          },
          "compliant_line_count": {
            "type": "integer"
          },
          "total_line_count": {
            "type": "integer"
          },
          "revalidation_recommended": {
            "type": "boolean",
            "description": "True when >1 fix found, suggesting re-scan after Fix All"
          },
          "relevant_rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Rule IDs the Anchor 3.0 SLM identified as relevant to the content."
          },
          "input_tokens": {
            "type": "integer",
            "description": "Input (prompt) tokens the Anchor 3.0 SLM consumed for this validation."
          },
          "output_tokens": {
            "type": "integer",
            "description": "Output (generated) tokens the Anchor 3.0 SLM produced for this validation."
          },
          "violations_by_line": {
            "type": "array",
            "description": "One entry per violating line. Present but empty for fully compliant documents.",
            "items": {
              "$ref": "#/components/schemas/LineViolation"
            }
          },
          "fixes": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "fixes_group": {
            "type": "object"
          },
          "all_violations": {
            "type": "array",
            "description": "Present on email-style validation — merged signal + regex violations",
            "items": {
              "$ref": "#/components/schemas/EmailViolation"
            }
          },
          "violations": {
            "type": "array",
            "description": "Present on email-style validation — the AI-signal subset of all_violations",
            "items": {
              "$ref": "#/components/schemas/EmailViolation"
            }
          },
          "metadata": {
            "type": "object",
            "description": "Document metadata used for scenario matching"
          }
        }
      },
      "LineViolation": {
        "type": "object",
        "title": "LineViolation",
        "properties": {
          "line_number": {
            "type": "integer"
          },
          "line_text": {
            "type": "string"
          },
          "char_from": {
            "type": "integer"
          },
          "char_to": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "rule_count": {
            "type": "integer"
          },
          "rules_violated": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "rule_id": {
                  "type": "string"
                },
                "rule_name": {
                  "type": "string"
                },
                "rule_ref": {
                  "type": "string",
                  "description": "Regulatory citation, e.g. FINRA 2210(d)(1)(B)"
                },
                "severity": {
                  "type": "string",
                  "enum": [
                    "do_not_send",
                    "send_with_caution"
                  ]
                },
                "confidence": {
                  "type": "number",
                  "format": "float"
                },
                "action": {
                  "type": "string",
                  "enum": [
                    "replace",
                    "insert_after",
                    "remove",
                    "warning"
                  ]
                }
              }
            }
          },
          "best_fix": {
            "type": "object",
            "properties": {
              "severity": {
                "type": "string",
                "enum": [
                  "do_not_send",
                  "send_with_caution"
                ]
              },
              "rule_id": {
                "type": "string"
              },
              "rule_name": {
                "type": "string"
              },
              "rule_ref": {
                "type": "string"
              },
              "action": {
                "type": "string"
              },
              "suggested_text": {
                "type": "string",
                "nullable": true
              },
              "human_action": {
                "type": "string"
              },
              "confidence": {
                "type": "number",
                "format": "float"
              }
            }
          }
        }
      },
      "EmailViolation": {
        "type": "object",
        "title": "EmailViolation",
        "properties": {
          "rule_id": {
            "type": "string"
          },
          "signal_name": {
            "type": "string"
          },
          "rule_name": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "do_not_send",
              "send_with_caution"
            ]
          },
          "confidence": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ]
          },
          "quote": {
            "type": "string"
          },
          "char_from": {
            "type": "integer"
          },
          "char_to": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "fix": {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "replace",
                  "insert_after",
                  "remove",
                  "warning",
                  "remove_or_escalate"
                ],
                "description": "remove_or_escalate (anchor_3_0 only): the line can't be rewritten compliantly while preserving its meaning. suggested_text is empty; remove the line or escalate for human review."
              },
              "suggested_text": {
                "type": "string"
              },
              "fix_note": {
                "type": "string"
              }
            }
          }
        }
      },
      "PolicyImportRequest": {
        "type": "object",
        "title": "PolicyImportRequest",
        "required": [
          "source",
          "content"
        ],
        "properties": {
          "source": {
            "type": "string",
            "enum": [
              "file",
              "text"
            ],
            "description": "Whether content is a base64-encoded file or plain text"
          },
          "content": {
            "type": "string",
            "description": "Base64-encoded document bytes (for file) or plain text (for text)"
          },
          "filename": {
            "type": "string",
            "description": "Original filename (optional, for file uploads)"
          }
        }
      },
      "PolicyImportAccepted": {
        "type": "object",
        "title": "PolicyImportAccepted",
        "properties": {
          "import_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "PolicyImportSummary": {
        "type": "object",
        "title": "PolicyImportSummary",
        "properties": {
          "import_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "pending_review",
              "no_rules_found",
              "failed",
              "activated",
              "partially_activated"
            ]
          },
          "rule_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PolicyImportListResponse": {
        "type": "object",
        "title": "PolicyImportListResponse",
        "properties": {
          "imports": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PolicyImportSummary"
            }
          },
          "count": {
            "type": "integer"
          }
        }
      },
      "PolicyImportPresignedUrlRequest": {
        "type": "object",
        "title": "PolicyImportPresignedUrlRequest",
        "description": "Request a presigned S3 PUT URL for uploading a large policy file. The returned upload_url and required_headers must be used verbatim, or S3 rejects the upload with SignatureDoesNotMatch.",
        "properties": {
          "filename": {
            "type": "string",
            "description": "Original filename, for reference/audit",
            "example": "my-compliance-policy.pdf"
          },
          "content_type": {
            "type": "string",
            "description": "MIME type of the file to be uploaded",
            "default": "application/pdf",
            "example": "application/pdf"
          }
        }
      },
      "PolicyImportPresignedUrlResponse": {
        "type": "object",
        "title": "PolicyImportPresignedUrlResponse",
        "properties": {
          "import_id": {
            "type": "string"
          },
          "upload_url": {
            "type": "string"
          },
          "upload_method": {
            "type": "string",
            "enum": [
              "PUT"
            ]
          },
          "s3_bucket": {
            "type": "string"
          },
          "s3_key": {
            "type": "string"
          },
          "required_headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "expires_in_seconds": {
            "type": "integer",
            "default": 900
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "max_upload_bytes": {
            "type": "integer",
            "description": "Maximum file size (1 GB = 1073741824 bytes)"
          },
          "next_steps": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "PolicyImportStartRequest": {
        "type": "object",
        "title": "PolicyImportStartRequest",
        "required": [
          "import_id"
        ],
        "properties": {
          "import_id": {
            "type": "string",
            "description": "Import identifier returned from the presigned_url endpoint"
          },
          "filename": {
            "type": "string",
            "description": "Optional filename to record on the import (overrides the presigned-step value)"
          }
        }
      },
      "PolicyImportStartAccepted": {
        "type": "object",
        "title": "PolicyImportStartAccepted",
        "properties": {
          "import_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "scan_pending"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "PolicyImportDetails": {
        "type": "object",
        "title": "PolicyImportDetails",
        "properties": {
          "import_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "pending_review",
              "no_rules_found",
              "failed",
              "activated",
              "partially_activated"
            ]
          },
          "rule_count": {
            "type": "integer"
          },
          "error_message": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExtractedPolicyRule"
            }
          }
        }
      },
      "ImportedRuleUpdateRequest": {
        "type": "object",
        "title": "ImportedRuleUpdateRequest",
        "description": "Partial edit for one pending imported rule. prompt is accepted only for AI_SIGNAL rules. Explicit null clears prompt or fix_note.",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "prompt": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "fix_note": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          }
        }
      },
      "ExtractedPolicyRule": {
        "type": "object",
        "title": "ExtractedPolicyRule",
        "required": [
          "id",
          "type",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "AI_SIGNAL",
              "REGEX",
              "REQUIRE_NEAR"
            ]
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "description": "Rule severity: low, medium, or high"
          },
          "action": {
            "type": "string",
            "enum": [
              "flag",
              "fix"
            ],
            "description": "Suggested action: flag (warn only) or fix (suggest replacement text)"
          },
          "source_text": {
            "type": "string",
            "description": "Source policy text retained as provenance"
          },
          "prompt": {
            "type": "string",
            "nullable": true,
            "minLength": 1,
            "description": "AI instruction, used only by AI_SIGNAL rules"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "window": {
            "type": "string",
            "enum": [
              "sentence",
              "paragraph",
              "document"
            ]
          },
          "regex_pattern": {
            "type": "string",
            "maxLength": 512
          },
          "fix_note": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "suggested_text": {
            "type": "string",
            "description": "Suggested replacement or guidance text (if applicable)"
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "AI confidence score (0-1)"
          },
          "simulatable": {
            "type": "boolean"
          },
          "activated_rule_id": {
            "type": "string",
            "nullable": true
          },
          "anchor": {
            "type": "string",
            "maxLength": 512
          },
          "near": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "maxLength": 512
            }
          },
          "distance_chars": {
            "type": "integer",
            "minimum": 0,
            "default": 100
          },
          "direction": {
            "type": "string",
            "enum": [
              "before",
              "after",
              "either"
            ],
            "default": "either"
          },
          "case_insensitive": {
            "type": "boolean",
            "default": false
          },
          "mode": {
            "type": "string",
            "enum": [
              "document",
              "page"
            ],
            "default": "document"
          },
          "min_hits": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          }
        }
      },
      "PolicyActivateRequest": {
        "type": "object",
        "title": "PolicyActivateRequest",
        "properties": {
          "rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional subset of extracted rule IDs to activate. If omitted, all rules are activated."
          },
          "overwrite": {
            "type": "boolean",
            "description": "Set true to overwrite rules already activated from a previous import. Defaults to false."
          }
        }
      },
      "PolicyActivateResponse": {
        "type": "object",
        "title": "PolicyActivateResponse",
        "properties": {
          "import_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "activated"
            ]
          },
          "activated_count": {
            "type": "integer"
          },
          "activated_rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "conflicting_rule_id": {
            "type": "string",
            "description": "Present on 409 responses: the rule ID that caused the conflict"
          }
        }
      },
      "RuleSelectorRequest": {
        "type": "object",
        "title": "RuleSelectorRequest",
        "minProperties": 1,
        "properties": {
          "rule_pack_id": {
            "type": "string",
            "description": "e.g. sec_finra_comms_v2"
          },
          "import_id": {
            "type": "string"
          },
          "rule_pack_scenario_id": {
            "type": "string",
            "description": "e.g. scenario_email_general"
          },
          "rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "RuleDeactivateResponse": {
        "type": "object",
        "title": "RuleDeactivateResponse",
        "properties": {
          "deactivated_custom_count": {
            "type": "integer"
          },
          "deactivated_custom_rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "deactivated_default_count": {
            "type": "integer"
          },
          "deactivated_default_rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        }
      },
      "RuleActivateResponse": {
        "type": "object",
        "title": "RuleActivateResponse",
        "properties": {
          "activated_custom_count": {
            "type": "integer"
          },
          "activated_custom_rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "activated_default_count": {
            "type": "integer"
          },
          "activated_default_rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        }
      },
      "CustomRuleCreateRequest": {
        "title": "CustomRuleCreateRequest",
        "oneOf": [
          {
            "$ref": "#/components/schemas/CustomRuleCreateAiSignalRequest"
          },
          {
            "$ref": "#/components/schemas/CustomRuleCreateRegexRequest"
          },
          {
            "$ref": "#/components/schemas/CustomRuleCreateRequireNearRequest"
          }
        ]
      },
      "CustomRuleCreateAiSignalRequest": {
        "type": "object",
        "title": "CustomRuleCreateAiSignalRequest",
        "additionalProperties": false,
        "required": [
          "name",
          "type",
          "action",
          "severity",
          "prompt",
          "keywords"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "type": {
            "type": "string",
            "enum": [
              "AI_SIGNAL"
            ]
          },
          "action": {
            "type": "string",
            "enum": [
              "fix",
              "flag"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "do_not_send",
              "send_with_caution"
            ]
          },
          "suggested_text": {
            "type": "string",
            "nullable": true,
            "minLength": 1,
            "description": "Editable suggested replacement or warning guidance. Omit to allow warning fallback on create; null explicitly clears/suppresses it."
          },
          "fix_note": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "prompt": {
            "type": "string",
            "minLength": 1,
            "description": "Allowed only for AI_SIGNAL rules"
          },
          "keywords": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "minLength": 1
            },
            "description": "Allowed only for AI_SIGNAL rules"
          },
          "window": {
            "type": "string",
            "enum": [
              "sentence",
              "paragraph",
              "document"
            ],
            "default": "document"
          }
        }
      },
      "CustomRuleCreateRegexRequest": {
        "type": "object",
        "title": "CustomRuleCreateRegexRequest",
        "additionalProperties": false,
        "required": [
          "name",
          "type",
          "action",
          "severity",
          "regex_pattern"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "type": {
            "type": "string",
            "enum": [
              "REGEX"
            ]
          },
          "action": {
            "type": "string",
            "enum": [
              "fix",
              "flag"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "do_not_send",
              "send_with_caution"
            ]
          },
          "suggested_text": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "fix_note": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "regex_pattern": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Python regex, allowed only for REGEX rules"
          }
        }
      },
      "CustomRuleCreateRequireNearRequest": {
        "type": "object",
        "title": "CustomRuleCreateRequireNearRequest",
        "additionalProperties": false,
        "required": [
          "name",
          "type",
          "action",
          "severity",
          "anchor",
          "near"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "type": {
            "type": "string",
            "enum": [
              "REQUIRE_NEAR"
            ]
          },
          "action": {
            "type": "string",
            "enum": [
              "fix",
              "flag"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "do_not_send",
              "send_with_caution"
            ]
          },
          "suggested_text": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "fix_note": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "anchor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Python regex anchor pattern"
          },
          "near": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            }
          },
          "distance_chars": {
            "type": "integer",
            "minimum": 0,
            "default": 100
          },
          "direction": {
            "type": "string",
            "enum": [
              "before",
              "after",
              "either"
            ],
            "default": "either"
          },
          "case_insensitive": {
            "type": "boolean",
            "default": false
          },
          "mode": {
            "type": "string",
            "enum": [
              "document",
              "page"
            ],
            "default": "document"
          },
          "min_hits": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          }
        }
      },
      "CustomRuleUpdateRequest": {
        "title": "CustomRuleUpdateRequest",
        "description": "Partial update. Rule ID, type, ownership, provenance, timestamps, and active status are immutable. Supply only fields applicable to the stored rule type.",
        "anyOf": [
          {
            "$ref": "#/components/schemas/CustomRuleUpdateAiSignalRequest"
          },
          {
            "$ref": "#/components/schemas/CustomRuleUpdateRegexRequest"
          },
          {
            "$ref": "#/components/schemas/CustomRuleUpdateRequireNearRequest"
          }
        ]
      },
      "CustomRuleUpdateAiSignalRequest": {
        "type": "object",
        "title": "CustomRuleUpdateAiSignalRequest",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "action": {
            "type": "string",
            "enum": [
              "fix",
              "flag"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "do_not_send",
              "send_with_caution"
            ]
          },
          "suggested_text": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "fix_note": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "prompt": {
            "type": "string",
            "minLength": 1,
            "description": "Allowed only when the stored rule type is AI_SIGNAL"
          },
          "keywords": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "window": {
            "type": "string",
            "enum": [
              "sentence",
              "paragraph",
              "document"
            ]
          }
        }
      },
      "CustomRuleUpdateRegexRequest": {
        "type": "object",
        "title": "CustomRuleUpdateRegexRequest",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "action": {
            "type": "string",
            "enum": [
              "fix",
              "flag"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "do_not_send",
              "send_with_caution"
            ]
          },
          "suggested_text": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "fix_note": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "regex_pattern": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Allowed only when the stored rule type is REGEX"
          }
        }
      },
      "CustomRuleUpdateRequireNearRequest": {
        "type": "object",
        "title": "CustomRuleUpdateRequireNearRequest",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "action": {
            "type": "string",
            "enum": [
              "fix",
              "flag"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "do_not_send",
              "send_with_caution"
            ]
          },
          "suggested_text": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "fix_note": {
            "type": "string",
            "nullable": true,
            "minLength": 1
          },
          "anchor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512
          },
          "near": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            }
          },
          "distance_chars": {
            "type": "integer",
            "minimum": 0,
            "default": 100
          },
          "direction": {
            "type": "string",
            "enum": [
              "before",
              "after",
              "either"
            ],
            "default": "either"
          },
          "case_insensitive": {
            "type": "boolean",
            "default": false
          },
          "mode": {
            "type": "string",
            "enum": [
              "document",
              "page"
            ],
            "default": "document"
          },
          "min_hits": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          }
        }
      },
      "CustomRuleResponse": {
        "type": "object",
        "title": "CustomRuleResponse",
        "required": [
          "rule_id",
          "name",
          "type",
          "action",
          "severity",
          "source",
          "active",
          "created_at"
        ],
        "properties": {
          "rule_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "AI_SIGNAL",
              "REGEX",
              "REQUIRE_NEAR"
            ]
          },
          "action": {
            "type": "string",
            "enum": [
              "fix",
              "flag"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "do_not_send",
              "send_with_caution"
            ]
          },
          "suggested_text": {
            "type": "string",
            "minLength": 1
          },
          "source": {
            "type": "string",
            "enum": [
              "custom"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "fix_note": {
            "type": "string"
          },
          "prompt": {
            "type": "string"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "window": {
            "type": "string",
            "enum": [
              "sentence",
              "paragraph",
              "document"
            ]
          },
          "regex_pattern": {
            "type": "string"
          },
          "anchor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512
          },
          "near": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            }
          },
          "distance_chars": {
            "type": "integer",
            "minimum": 0,
            "default": 100
          },
          "direction": {
            "type": "string",
            "enum": [
              "before",
              "after",
              "either"
            ],
            "default": "either"
          },
          "case_insensitive": {
            "type": "boolean",
            "default": false
          },
          "mode": {
            "type": "string",
            "enum": [
              "document",
              "page"
            ],
            "default": "document"
          },
          "min_hits": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          },
          "import_id": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ActiveRulesListResponse": {
        "type": "object",
        "title": "ActiveRulesListResponse",
        "properties": {
          "customer_id": {
            "type": "string"
          },
          "default_rules": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "rule_id": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "AI_SIGNAL",
                    "REGEX"
                  ]
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "default"
                  ]
                },
                "active": {
                  "type": "boolean"
                },
                "simulatable": {
                  "type": "boolean",
                  "description": "Whether this rule can be run via the simulate endpoint (internal-only, not part of this public spec). Non-simulatable rules are still listed so the UI can render them disabled."
                },
                "rule_pack_id": {
                  "type": "string"
                },
                "rule_pack_scenario_ids": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "threshold": {
                  "type": "number",
                  "nullable": true
                },
                "operator": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          },
          "custom_rules": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "rule_id": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "AI_SIGNAL",
                    "REGEX",
                    "REQUIRE_NEAR"
                  ]
                },
                "name": {
                  "type": "string"
                },
                "severity": {
                  "type": "string",
                  "enum": [
                    "low",
                    "medium",
                    "high"
                  ],
                  "description": "Rule severity: low, medium, or high"
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "custom"
                  ]
                },
                "active": {
                  "type": "boolean"
                },
                "simulatable": {
                  "type": "boolean"
                },
                "import_id": {
                  "type": "string"
                },
                "action": {
                  "type": "string",
                  "enum": [
                    "fix",
                    "flag"
                  ]
                },
                "window": {
                  "type": "string"
                },
                "created_at": {
                  "type": "string"
                },
                "anchor": {
                  "type": "string",
                  "maxLength": 512
                },
                "near": {
                  "type": "array",
                  "minItems": 1,
                  "items": {
                    "type": "string",
                    "maxLength": 512
                  }
                },
                "distance_chars": {
                  "type": "integer",
                  "minimum": 0,
                  "default": 100
                },
                "direction": {
                  "type": "string",
                  "enum": [
                    "before",
                    "after",
                    "either"
                  ],
                  "default": "either"
                },
                "case_insensitive": {
                  "type": "boolean",
                  "default": false
                },
                "mode": {
                  "type": "string",
                  "enum": [
                    "document",
                    "page"
                  ],
                  "default": "document"
                },
                "min_hits": {
                  "type": "integer",
                  "minimum": 1,
                  "default": 1
                }
              }
            }
          },
          "default_rules_count": {
            "type": "integer"
          },
          "default_rules_active_count": {
            "type": "integer"
          },
          "custom_rules_count": {
            "type": "integer"
          },
          "custom_rules_active_count": {
            "type": "integer"
          },
          "total_rules_count": {
            "type": "integer"
          },
          "total_active_count": {
            "type": "integer"
          }
        }
      },
      "ActivityRuleSummary": {
        "type": "object",
        "title": "ActivityRuleSummary",
        "required": [
          "id",
          "name",
          "severity",
          "type",
          "policy"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "severity": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "AI_SIGNAL",
              "REGEX",
              "REQUIRE_NEAR"
            ]
          },
          "policy": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          }
        }
      },
      "ActivityRule": {
        "type": "object",
        "title": "ActivityRule",
        "required": [
          "id",
          "name",
          "severity",
          "type",
          "policy"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "severity": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "AI_SIGNAL",
              "REGEX",
              "REQUIRE_NEAR"
            ]
          },
          "policy": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "snippet": {
            "type": "string"
          },
          "suggested_text": {
            "type": "string"
          },
          "fix_note": {
            "type": "string"
          }
        }
      },
      "ActivitySummary": {
        "type": "object",
        "title": "ActivitySummary",
        "required": [
          "activity_id",
          "occurred_at",
          "event_name",
          "status",
          "source",
          "agent",
          "rules"
        ],
        "properties": {
          "activity_id": {
            "type": "string"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "event_name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "auto_fixed",
              "blocked",
              "warned",
              "passed"
            ]
          },
          "source": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "nullable": true
          },
          "model": {
            "type": "string",
            "nullable": true
          },
          "agent": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityRuleSummary"
            }
          },
          "rule_count": {
            "type": "integer"
          },
          "truncated_rule_count": {
            "type": "integer"
          }
        }
      },
      "Activity": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ActivitySummary"
          },
          {
            "type": "object",
            "properties": {
              "endpoint": {
                "type": "string"
              },
              "request_id": {
                "type": "string"
              },
              "rules": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ActivityRule"
                }
              },
              "timeline": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "step": {
                      "type": "string"
                    },
                    "at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "ActivityListResponse": {
        "type": "object",
        "title": "ActivityListResponse",
        "required": [
          "items",
          "meta"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivitySummary"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true
          },
          "meta": {
            "type": "object",
            "required": [
              "total_pages",
              "current_page"
            ],
            "properties": {
              "total_pages": {
                "type": "integer",
                "minimum": 0
              },
              "current_page": {
                "type": "integer",
                "minimum": 1
              }
            }
          }
        }
      },
      "RulepackCatalogResponse": {
        "type": "object",
        "title": "RulepackCatalogResponse",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/RulepackSummary"
                }
              },
              {
                "$ref": "#/components/schemas/RulepackDetail"
              }
            ]
          },
          "meta": {
            "type": "object",
            "nullable": true,
            "properties": {
              "current_page": {
                "type": "integer"
              },
              "per_page": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              },
              "last_page": {
                "type": "integer"
              }
            }
          }
        }
      },
      "RulepackSummary": {
        "type": "object",
        "title": "RulepackSummary",
        "required": [
          "id",
          "name",
          "type",
          "engine",
          "active",
          "total_rules",
          "active_rules",
          "inactive_rules"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "enum": [
              "managed",
              "custom"
            ]
          },
          "engine": {
            "type": "string",
            "enum": [
              "anchor_3_0"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "total_rules": {
            "type": "integer"
          },
          "active_rules": {
            "type": "integer"
          },
          "inactive_rules": {
            "type": "integer"
          },
          "publisher": {
            "type": "string",
            "nullable": true
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "domain": {
            "type": "string",
            "nullable": true
          },
          "jurisdictions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "last_updated": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RulepackDetail": {
        "type": "object",
        "title": "RulepackDetail",
        "required": [
          "id",
          "name",
          "type",
          "engine",
          "active",
          "total_rules",
          "active_rules",
          "inactive_rules",
          "rules"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "enum": [
              "managed",
              "custom"
            ]
          },
          "engine": {
            "type": "string",
            "enum": [
              "anchor_3_0"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "total_rules": {
            "type": "integer"
          },
          "active_rules": {
            "type": "integer"
          },
          "inactive_rules": {
            "type": "integer"
          },
          "publisher": {
            "type": "string",
            "nullable": true
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "domain": {
            "type": "string",
            "nullable": true
          },
          "jurisdictions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "last_updated": {
            "type": "string",
            "nullable": true
          },
          "rules": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "type",
                "severity",
                "verdict",
                "active",
                "citations",
                "remediation"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string",
                  "nullable": true
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "AI_SIGNAL",
                    "REGEX",
                    "COMPOSITE",
                    "LEXICON",
                    "REQUIRE_NEAR",
                    "CUSTOM"
                  ]
                },
                "severity": {
                  "type": "string",
                  "nullable": true
                },
                "verdict": {
                  "type": "string",
                  "enum": [
                    "do_not_send",
                    "send_with_caution"
                  ]
                },
                "active": {
                  "type": "boolean"
                },
                "lifecycle": {
                  "type": "object",
                  "nullable": true,
                  "properties": {
                    "status": {
                      "type": "string",
                      "nullable": true
                    },
                    "effective_from": {
                      "type": "string",
                      "nullable": true
                    },
                    "last_reviewed": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                },
                "citations": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "framework": {
                        "type": "string",
                        "nullable": true
                      },
                      "cite": {
                        "type": "string",
                        "nullable": true
                      },
                      "jurisdictions": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "remediation": {
                  "type": "object",
                  "properties": {
                    "kind": {
                      "type": "string",
                      "nullable": true
                    },
                    "note": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
