{
  "openapi": "3.1.0",
  "info": {
    "title": "Data Guard API",
    "version": "1.0.0",
    "summary": "Find and redact PII, PHI and secrets in text and structured documents.",
    "description": "Data Guard finds sensitive values in a document and rewrites them\naccording to a policy, **without ever returning the raw value**. Findings\ncarry a masked preview (`***-**-6789`), never the original.\n\nDetection is deterministic — regexes, checksums and curated word lists.\nThere is no model, so the same input gives the same output on every call,\nand nothing you send is used for training or retained after the response.\n\n## Getting a key\n\nSubscribe on the AWS Marketplace listing. You will be sent to\n`cloud.llmlinq.com` to link the subscription to an LLMLinq account, and\nthe key is shown **once**, on the first load after activation. Only its\nSHA-256 is stored, so a lost key is replaced rather than recovered.\n\n## Authentication\n\nSend it as `Authorization: Bearer llq_live_…`, or as `X-Api-Key` if that\nsuits your client better. Both are read.\n\n## Choosing an endpoint\n\n| You want to | Call |\n|---|---|\n| know whether a document is safe to send somewhere | `/scan` |\n| rewrite it so it is safe | `/redact` |\n| rewrite it and be able to undo that later | `/redact` with `strategy: encrypt` and a `key` |\n| undo it | `/restore` with the same `key` |\n| prove a document meets HIPAA, GDPR or PCI | `/check` |\n| know what can be recognised at all | `/detectors` |\n\n## Sizes\n\nA request body is capped at about 6 MB, which is the AWS Lambda limit on\na synchronous invocation; a larger one is refused before it reaches the\nservice. The response is capped at 256 KiB. Redaction can *grow* a\ndocument — an encrypted placeholder is longer than the value it replaces —\nso an accepted input can still produce a `413`. Split the document and\nsend it in pieces.\n"
  },
  "servers": [
    {
      "url": "https://api.llmlinq.com/data-guard/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Detect",
      "description": "Find sensitive values without changing anything."
    },
    {
      "name": "Transform",
      "description": "Rewrite a document, and put it back."
    },
    {
      "name": "Compliance",
      "description": "Judge a document against a named regime."
    },
    {
      "name": "Reference",
      "description": "What this service can recognise."
    }
  ],
  "paths": {
    "/scan": {
      "post": {
        "tags": [
          "Detect"
        ],
        "summary": "Find sensitive values",
        "operationId": "scan",
        "description": "Reports what was found, where, and how confident the detector is —\nand never what the value was. Use this to decide whether a document\nis safe to forward, log or share, before deciding what to do about it.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScanRequest"
              },
              "examples": {
                "prose": {
                  "summary": "A line of text",
                  "value": {
                    "text": "Call Sarah on 415-555-2671 or s.chen@acme.test"
                  }
                },
                "structured": {
                  "summary": "A JSON document, base64-encoded",
                  "value": {
                    "base64_data": "eyJlbWFpbCI6ICJhQGIuY29tIn0=",
                    "kind": "json"
                  }
                },
                "tuned": {
                  "summary": "Only the entity types you care about",
                  "value": {
                    "text": "AKIAIOSFODNN7EXAMPLE in the config",
                    "policy": "secrets_only",
                    "min_confidence": 0.7
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The scan completed. `findings` may be empty.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResponse"
                },
                "example": {
                  "request_id": "635da2d18b66440eb8b21c6687aa52a1",
                  "document_kind": "text",
                  "policy": "default",
                  "min_confidence": 0.5,
                  "bytes": 37,
                  "origin": "inline_text",
                  "segments_scanned": 1,
                  "summary": {
                    "total": 2,
                    "by_entity_type": {
                      "EMAIL_ADDRESS": 1,
                      "PHONE_NUMBER": 1
                    },
                    "by_category": {
                      "pii": 2
                    },
                    "risk": "moderate"
                  },
                  "findings": [
                    {
                      "entity_type": "PHONE_NUMBER",
                      "category": "pii",
                      "path": null,
                      "start": 5,
                      "end": 17,
                      "confidence": 1.0,
                      "detector": "pattern+ctx:call",
                      "preview": "***-***-2671",
                      "length": 12
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Inactive"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/redact": {
      "post": {
        "tags": [
          "Transform"
        ],
        "summary": "Rewrite sensitive values",
        "operationId": "redact",
        "description": "Replaces each finding according to the policy, and returns the\nrewritten document plus a **receipt** — counts by entity type,\ncategory and strategy, and a SHA-256 of the input — which is what you\nkeep as evidence of what was done without keeping the data.\n\nReversibility is a choice you make here. `encrypt` with a `key` can be\nundone by `/restore`; `hash` gives stable tokens so equal values stay\nequal across documents (joinable, not reversible); `label`, `mask`,\n`partial` and `remove` are one-way.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RedactRequest"
              },
              "examples": {
                "simple": {
                  "summary": "One-way, using the default policy",
                  "value": {
                    "text": "Patient 123-45-6789 seen on Tuesday"
                  }
                },
                "reversible": {
                  "summary": "Reversible — keep the key, you need it to restore",
                  "value": {
                    "text": "Patient 123-45-6789 seen on Tuesday",
                    "strategy": "encrypt",
                    "key": "a-secret-you-store-separately"
                  }
                },
                "compliance": {
                  "summary": "A named regime rather than a strategy",
                  "value": {
                    "text": "Patient 123-45-6789, DOB 1974-03-02",
                    "policy": "hipaa_safe_harbor"
                  }
                },
                "caller_spans": {
                  "summary": "Redact something only you can recognise",
                  "value": {
                    "text": "Internal ref QX-88213 is confidential",
                    "extra_spans": [
                      {
                        "start": 13,
                        "end": 21,
                        "entity_type": "INTERNAL_REF"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The document was rewritten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RedactResponse"
                },
                "example": {
                  "request_id": "7ac1e0b2f1f04c1ab6d9e2f30a1b4c5d",
                  "document_kind": "text",
                  "policy": "default",
                  "strategy_override": "encrypt",
                  "delivery": "inline_text",
                  "bytes": 81,
                  "text": "Patient <US_SSN:enc:DpKJ1EaIksCk0pmUOyeKk3mINh3wrT3V> seen on Tuesday",
                  "path": null,
                  "reversible": true,
                  "notes": [],
                  "receipt": {
                    "policy": "default",
                    "input_sha256": "539fff6ed79eaad4ba8a5c427519f820dbb2ef7a62b7b03fc04620f62a754e94",
                    "input_bytes": 15,
                    "document_kind": "text",
                    "total_redactions": 1,
                    "by_entity_type": {
                      "US_SSN": 1
                    },
                    "by_category": {
                      "pii": 1
                    },
                    "by_strategy": {
                      "encrypt": 1
                    },
                    "by_source": {
                      "detected": 1,
                      "model": 0,
                      "caller": 0
                    },
                    "min_confidence": 0.5,
                    "truncated": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Inactive"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/restore": {
      "post": {
        "tags": [
          "Transform"
        ],
        "summary": "Put the original values back",
        "operationId": "restore",
        "description": "Reverses a redaction made with `strategy: encrypt`, using the same\n`key`. A wrong key, a modified token, or a token whose entity type has\nchanged all fail the same way — the ciphertext is authenticated, so a\ntampered placeholder cannot be decrypted into something plausible.\n\n**This response contains the original sensitive values.** It is\ntherefore the one call this service will not spill to a scratch file:\nan oversized restore is refused rather than written to disk.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RestoreRequest"
              },
              "examples": {
                "roundtrip": {
                  "summary": "The output of a reversible redact",
                  "value": {
                    "text": "Patient <US_SSN:enc:DpKJ1EaIksCk0pmUOyeKk3mINh3wrT3V> seen",
                    "key": "a-secret-you-store-separately"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Every placeholder was restored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestoreResponse"
                },
                "example": {
                  "request_id": "1f2e3d4c5b6a70819e2d3c4b5a697887",
                  "restored_count": 1,
                  "delivery": "inline_text",
                  "bytes": 33,
                  "text": "Patient 123-45-6789 seen"
                }
              }
            }
          },
          "400": {
            "description": "No placeholder could be restored — usually the wrong key. Nothing\nis partially applied: either every placeholder is restored or the\ndocument is returned unchanged.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "invalid_request",
                  "message": "Could not restore 1 placeholder(s); no changes were applied. First failure - US_SSN: Could not decrypt: the key is wrong, the entity type does not match the one used at redaction time, or the token was modified."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Inactive"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/check": {
      "post": {
        "tags": [
          "Compliance"
        ],
        "summary": "Judge a document against a policy",
        "operationId": "check",
        "description": "Answers \"would this document satisfy HIPAA Safe Harbor / GDPR / PCI as\nit stands?\" and lists what stops it. Defaults to\n`hipaa_safe_harbor` because that is the regime with an enumerated,\ncheckable list of identifiers.\n\nThe policy's own `notes` state what it cannot cover — Safe Harbor's\nbiometric and photographic identifiers are not detectable from text —\nso a pass is a statement about the text, not a legal opinion.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckRequest"
              },
              "examples": {
                "hipaa": {
                  "summary": "The default regime",
                  "value": {
                    "text": "Patient 123-45-6789 admitted 2024-01-05"
                  }
                },
                "gdpr": {
                  "summary": "A different regime",
                  "value": {
                    "text": "Contact: s.chen@acme.test",
                    "policy": "gdpr_basic"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The document was judged. Read `passed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Inactive"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/detectors": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "What this service can recognise",
        "operationId": "listDetectors",
        "description": "The full catalogue — 64 entity types, the policies, the redaction\nstrategies and the document kinds. Call it once and cache it; it\nchanges only when the service is released.\n\nUseful for building a UI, for choosing `entity_types`, and for\nchecking whether an identifier you care about is covered at all\nbefore you find out the hard way.\n",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Narrow the list to one category.",
            "schema": {
              "$ref": "#/components/schemas/Category"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DetectorsResponse"
                },
                "example": {
                  "detector_count": 64,
                  "categories": [
                    "pii",
                    "phi",
                    "financial",
                    "secret"
                  ],
                  "strategies": [
                    "label",
                    "mask",
                    "partial",
                    "hash",
                    "token",
                    "encrypt",
                    "remove"
                  ],
                  "document_kinds": [
                    "text",
                    "json",
                    "ndjson",
                    "yaml",
                    "csv"
                  ],
                  "detectors": [
                    {
                      "entity_type": "ANTHROPIC_API_KEY",
                      "category": "secret",
                      "detection": "pattern",
                      "requires_context": false,
                      "description": "Anthropic API key (sk-ant- prefix).",
                      "countries": []
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Inactive"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your API key, as issued at `cloud.llmlinq.com/aws/data-guard/configure`.\nKeys begin `llq_live_`. `X-Api-Key: llq_live_…` is accepted as an\nalternative to the `Authorization` header.\n"
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key"
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request could not be acted on. `message` says what to fix, and\nnever quotes the content that caused it — that guarantee is what\nmakes it safe to log this error verbatim.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "unsupported": {
                "summary": "A parameter this transport does not accept",
                "value": {
                  "error": "unsupported_parameters",
                  "parameters": [
                    "path"
                  ]
                }
              },
              "malformed": {
                "summary": "A parameter of the right name, wrong shape",
                "value": {
                  "error": "invalid_request",
                  "message": "extra_spans[0]: extra_spans entry [0, 99999) is outside the text (length 229)."
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "No key, or one this service did not issue.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "missing": {
                "summary": "No key, or one that is not ours",
                "value": {
                  "error": "api_key_required"
                }
              },
              "unknown": {
                "summary": "Well-formed, but not a key we issued — or since rotated",
                "value": {
                  "error": "invalid_api_key"
                }
              }
            }
          }
        }
      },
      "Inactive": {
        "description": "The key is valid but the subscription cannot serve this call. Fixed in\nthe AWS Marketplace, not by sending a different key — which is why this\nis distinguished from a `401`.\n\n`subscription_inactive`: the subscription has ended or has not finished\nactivating. `trial_limit_reached` (the four document operations only):\na free trial has used its allowance of requests or request bytes, which\n`limits` states. A trial does not refill; subscribing continues with the\nsame key.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "inactive": {
                "summary": "The subscription has ended",
                "value": {
                  "error": "subscription_inactive",
                  "state": "revoked"
                }
              },
              "trial": {
                "summary": "A free trial has used its allowance",
                "value": {
                  "error": "trial_limit_reached",
                  "message": "This free trial has used its allowance of 10,000 requests or 1 GB of request data. To continue, subscribe to Data Guard in AWS Marketplace and complete account setup; your API key stays the same.",
                  "limits": {
                    "requests": 10000,
                    "bytes_scanned": 1073741824
                  }
                }
              }
            }
          }
        }
      },
      "TooLarge": {
        "description": "The result exceeds what this API returns inline. Redaction can grow a\ndocument, so an accepted input can still land here.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "result_too_large",
              "message": "The result is 412 KiB, above the 256 KiB this API returns inline."
            }
          }
        }
      }
    },
    "schemas": {
      "Category": {
        "type": "string",
        "enum": [
          "pii",
          "phi",
          "financial",
          "secret"
        ]
      },
      "DocumentKind": {
        "type": "string",
        "default": "auto",
        "enum": [
          "auto",
          "text",
          "json",
          "ndjson",
          "yaml",
          "csv"
        ],
        "description": "`auto` sniffs the format. Name it explicitly when you know it — a\nJSON document parsed as text is scanned as one flat string, which\nfinds the same values but cannot report the field path they sit in.\n"
      },
      "Strategy": {
        "type": "string",
        "enum": [
          "label",
          "mask",
          "partial",
          "hash",
          "token",
          "encrypt",
          "remove"
        ],
        "description": "| | | reversible |\n|---|---|---|\n| `label` | `<US_SSN>` | no |\n| `mask` | `***-**-6789` | no |\n| `partial` | keeps a readable fragment | no |\n| `hash` | stable keyed token — equal values stay equal | no |\n| `token` | opaque reference | no |\n| `encrypt` | AES-GCM; undo with `/restore` | **yes** |\n| `remove` | deleted outright | no |\n"
      },
      "Policy": {
        "type": "string",
        "default": "default",
        "enum": [
          "default",
          "gdpr_basic",
          "hipaa_safe_harbor",
          "pci_dss",
          "secrets_only",
          "strict_all"
        ],
        "description": "A named bundle of entity types, a default strategy and a confidence\nthreshold. `GET /detectors` returns each one in full, including the\nnotes on what it deliberately does not cover.\n"
      },
      "Inline": {
        "type": "object",
        "description": "Exactly one of `text` or `base64_data`. Use `base64_data` for anything\nthat is not UTF-8 text, or where byte-exactness matters.\n",
        "properties": {
          "text": {
            "type": "string",
            "description": "The document, inline."
          },
          "base64_data": {
            "type": "string",
            "format": "byte",
            "description": "The document, base64-encoded."
          }
        }
      },
      "ScanRequest": {
        "type": "object",
        "description": "Exactly one of `text` or `base64_data`. Use `base64_data` for anything\nthat is not UTF-8 text, or where byte-exactness matters.\n",
        "properties": {
          "text": {
            "type": "string",
            "description": "The document, inline."
          },
          "base64_data": {
            "type": "string",
            "format": "byte",
            "description": "The document, base64-encoded."
          },
          "kind": {
            "$ref": "#/components/schemas/DocumentKind"
          },
          "policy": {
            "$ref": "#/components/schemas/Policy"
          },
          "entity_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict to these types, overriding the policy's list."
          },
          "min_confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Raise it to cut false positives, lower it to catch more. The\npolicy's own threshold is used when this is omitted.\n"
          },
          "max_findings": {
            "type": "integer",
            "default": 200,
            "description": "Cap the number returned; the summary still counts all of them."
          }
        }
      },
      "RedactRequest": {
        "type": "object",
        "description": "Exactly one of `text` or `base64_data`. Use `base64_data` for anything\nthat is not UTF-8 text, or where byte-exactness matters.\n",
        "properties": {
          "text": {
            "type": "string",
            "description": "The document, inline."
          },
          "base64_data": {
            "type": "string",
            "format": "byte",
            "description": "The document, base64-encoded."
          },
          "kind": {
            "$ref": "#/components/schemas/DocumentKind"
          },
          "policy": {
            "$ref": "#/components/schemas/Policy"
          },
          "strategy": {
            "$ref": "#/components/schemas/Strategy"
          },
          "key": {
            "type": "string",
            "description": "Required by `hash` and `encrypt`, and so by the `gdpr_basic`\npolicy, whose default strategy is `hash`. Store it separately\nfrom the output — it is what re-links the two. This service\ndoes not keep it.\n"
          },
          "entity_types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "min_confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "extra_spans": {
            "type": "array",
            "description": "Ranges you want redacted that no detector would find — your\nown identifiers, or spans a model flagged. Offsets are\ncharacter positions in the exact text you sent.\n",
            "items": {
              "type": "object",
              "required": [
                "start",
                "end",
                "entity_type"
              ],
              "properties": {
                "start": {
                  "type": "integer",
                  "minimum": 0
                },
                "end": {
                  "type": "integer",
                  "minimum": 0
                },
                "entity_type": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "RestoreRequest": {
        "type": "object",
        "description": "Exactly one of `text` or `base64_data`. Use `base64_data` for anything\nthat is not UTF-8 text, or where byte-exactness matters.\n",
        "properties": {
          "text": {
            "type": "string",
            "description": "The document, inline."
          },
          "base64_data": {
            "type": "string",
            "format": "byte",
            "description": "The document, base64-encoded."
          },
          "key": {
            "type": "string",
            "description": "The same key used at redaction time."
          }
        },
        "required": [
          "key"
        ]
      },
      "CheckRequest": {
        "type": "object",
        "description": "Exactly one of `text` or `base64_data`. Use `base64_data` for anything\nthat is not UTF-8 text, or where byte-exactness matters.\n",
        "properties": {
          "text": {
            "type": "string",
            "description": "The document, inline."
          },
          "base64_data": {
            "type": "string",
            "format": "byte",
            "description": "The document, base64-encoded."
          },
          "kind": {
            "$ref": "#/components/schemas/DocumentKind"
          },
          "policy": {
            "type": "string",
            "default": "hipaa_safe_harbor",
            "enum": [
              "default",
              "gdpr_basic",
              "hipaa_safe_harbor",
              "pci_dss",
              "secrets_only",
              "strict_all"
            ],
            "description": "A named bundle of entity types, a default strategy and a confidence\nthreshold. `GET /detectors` returns each one in full, including the\nnotes on what it deliberately does not cover.\n"
          },
          "min_confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          }
        }
      },
      "Finding": {
        "type": "object",
        "description": "One sensitive value, described without being disclosed.",
        "properties": {
          "entity_type": {
            "type": "string",
            "examples": [
              "US_SSN"
            ]
          },
          "category": {
            "$ref": "#/components/schemas/Category"
          },
          "path": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where it sits in a structured document, or null for plain text.",
            "examples": [
              "$.patient.ssn"
            ]
          },
          "start": {
            "type": "integer",
            "description": "Character offset",
            "inclusive.": null
          },
          "end": {
            "type": "integer",
            "description": "Character offset",
            "exclusive.": null
          },
          "length": {
            "type": "integer"
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "detector": {
            "type": "string",
            "description": "Which rule fired, and on what evidence.",
            "examples": [
              "pattern+ctx:call"
            ]
          },
          "preview": {
            "type": "string",
            "description": "**Masked, always.** The service never returns the raw value in a\nfinding; this is what makes a scan safe to log.\n",
            "examples": [
              "***-**-6789"
            ]
          }
        }
      },
      "Summary": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "by_entity_type": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "by_category": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "risk": {
            "type": "string",
            "enum": [
              "none",
              "moderate",
              "high",
              "critical"
            ],
            "description": "The highest category present — a secret is `critical`, PHI and\nfinancial data `high`, other PII `moderate`.\n"
          }
        }
      },
      "ScanResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "document_kind": {
            "type": "string"
          },
          "policy": {
            "type": "string"
          },
          "min_confidence": {
            "type": "number"
          },
          "bytes": {
            "type": "integer"
          },
          "origin": {
            "type": "string"
          },
          "segments_scanned": {
            "type": "integer"
          },
          "summary": {
            "$ref": "#/components/schemas/Summary"
          },
          "findings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Finding"
            }
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Receipt": {
        "type": "object",
        "description": "Evidence of what was done, holding no sensitive data itself — keep it\neven when you cannot keep the document.\n",
        "properties": {
          "policy": {
            "type": "string"
          },
          "input_sha256": {
            "type": "string",
            "description": "Identifies the exact input without storing it."
          },
          "input_bytes": {
            "type": "integer"
          },
          "document_kind": {
            "type": "string"
          },
          "total_redactions": {
            "type": "integer"
          },
          "by_entity_type": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "by_category": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "by_strategy": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "by_source": {
            "type": "object",
            "description": "Detected by a rule, supplied by a model, or named by you.",
            "properties": {
              "detected": {
                "type": "integer"
              },
              "model": {
                "type": "integer"
              },
              "caller": {
                "type": "integer"
              }
            }
          },
          "min_confidence": {
            "type": "number"
          },
          "truncated": {
            "type": "boolean"
          }
        }
      },
      "RedactResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "document_kind": {
            "type": "string"
          },
          "policy": {
            "type": "string"
          },
          "strategy_override": {
            "type": [
              "string",
              "null"
            ]
          },
          "delivery": {
            "type": "string",
            "enum": [
              "inline_text"
            ],
            "description": "Always inline here; an oversized result is a `413`."
          },
          "bytes": {
            "type": "integer"
          },
          "text": {
            "type": "string",
            "description": "The rewritten document."
          },
          "path": {
            "type": [
              "string",
              "null"
            ],
            "description": "Always null over HTTP. Present for parity with the MCP transport."
          },
          "reversible": {
            "type": "boolean",
            "description": "Whether `/restore` can undo this with the same key."
          },
          "receipt": {
            "$ref": "#/components/schemas/Receipt"
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "RestoreResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "restored_count": {
            "type": "integer"
          },
          "delivery": {
            "type": "string",
            "enum": [
              "inline_text"
            ]
          },
          "bytes": {
            "type": "integer"
          },
          "text": {
            "type": "string",
            "description": "The original document. Contains the sensitive values."
          }
        }
      },
      "Violation": {
        "type": "object",
        "description": "One entity type that stops the document passing, described without\ndisclosing any value.\n",
        "properties": {
          "entity_type": {
            "type": "string",
            "examples": [
              "MEDICAL_RECORD_NUMBER"
            ]
          },
          "category": {
            "$ref": "#/components/schemas/Category"
          },
          "count": {
            "type": "integer"
          },
          "max_confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "locations": {
            "type": "array",
            "description": "Up to 20 locations. Locations only, never values.",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Where it sits in a structured document, or null for plain text."
                },
                "start": {
                  "type": "integer",
                  "description": "Character offset",
                  "inclusive.": null
                }
              }
            }
          }
        }
      },
      "CheckResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "policy": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "default_strategy": {
                "type": "string"
              },
              "strategy_overrides": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "min_confidence": {
                "type": "number"
              },
              "entity_type_count": {
                "type": "integer"
              },
              "entity_types": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "notes": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "What this policy cannot check. Read them before relying on a pass."
              }
            }
          },
          "document_kind": {
            "type": "string"
          },
          "passed": {
            "type": "boolean",
            "description": "Whether the document satisfies the policy as it stands."
          },
          "violation_count": {
            "type": "integer",
            "description": "Every finding that counts against the policy, across all entity types."
          },
          "violations": {
            "type": "array",
            "description": "One entry per entity type, most frequent first.",
            "items": {
              "$ref": "#/components/schemas/Violation"
            }
          },
          "summary": {
            "$ref": "#/components/schemas/Summary"
          },
          "document_truncated": {
            "type": "boolean",
            "description": "True when the document was only partly examined."
          },
          "hipaa_identifiers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "identifier": {
                  "type": "string",
                  "examples": [
                    "1. Names"
                  ]
                },
                "entity_types": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "covered": {
                  "type": "boolean"
                }
              }
            },
            "description": "Present only for `hipaa_safe_harbor`: the 18 identifiers of\n45 CFR 164.514(b)(2) mapped to what this service detects,\nwith the three it does not stated explicitly.\n"
          }
        }
      },
      "DetectorsResponse": {
        "type": "object",
        "properties": {
          "detector_count": {
            "type": "integer"
          },
          "detectors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "entity_type": {
                  "type": "string"
                },
                "category": {
                  "$ref": "#/components/schemas/Category"
                },
                "detection": {
                  "type": "string",
                  "description": "pattern, checksum-validated, gazetteer, or context-dependent."
                },
                "requires_context": {
                  "type": "boolean",
                  "description": "Whether a nearby cue word is needed. These types are missed\nwhen the value appears with no surrounding text.\n"
                },
                "description": {
                  "type": "string"
                },
                "countries": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Category"
            }
          },
          "policies": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "strategies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Strategy"
            }
          },
          "document_kinds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A stable machine-readable code. Branch on this, not on `message`.",
            "enum": [
              "api_key_required",
              "invalid_api_key",
              "subscription_inactive",
              "trial_limit_reached",
              "invalid_json",
              "unsupported_parameters",
              "invalid_request",
              "result_too_large",
              "not_found",
              "internal_error"
            ]
          },
          "message": {
            "type": "string",
            "description": "Human-readable guidance on what to change. Never quotes the\ncontent that caused the error.\n"
          },
          "parameters": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Present on `unsupported_parameters` — the names rejected."
          },
          "state": {
            "type": "string",
            "description": "Present on `subscription_inactive` — the subscription's state."
          },
          "limits": {
            "type": "object",
            "description": "Present on `trial_limit_reached` — the trial allowance, in the units\nthe meter counts: calls, and request body bytes.\n",
            "properties": {
              "requests": {
                "type": "integer"
              },
              "bytes_scanned": {
                "type": "integer"
              }
            }
          }
        }
      }
    }
  }
}
