{
  "openapi": "3.1.0",
  "info": {
    "title": "ZeroTrace AI API",
    "version": "1.0.0",
    "description": "Find and remove invisible Unicode characters, steganographic payloads and hidden-text prompt injections. Submitted text is never stored or logged.",
    "contact": {
      "url": "https://zerotraceai.net/docs"
    }
  },
  "servers": [
    {
      "url": "https://api.zerotraceai.net/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/clean": {
      "post": {
        "summary": "Clean text and report every finding",
        "operationId": "cleanText",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CleanRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cleaned text with findings",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CleanResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/detect": {
      "post": {
        "summary": "Report findings without returning the cleaned text",
        "description": "Same body and same price as /clean; omits the `cleaned` field.",
        "operationId": "detectText",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CleanRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Findings only",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CleanResponse"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "summary": "Plan, limits, remaining quota and credit balance",
        "operationId": "getAccount",
        "responses": {
          "200": {
            "description": "Account summary"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "summary": "Paginated usage history",
        "operationId": "getUsage",
        "responses": {
          "200": {
            "description": "Usage events"
          }
        }
      }
    },
    "/health": {
      "get": {
        "summary": "Liveness check",
        "operationId": "getHealth",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is up"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key created in the dashboard, prefixed `zt_live_`."
      }
    },
    "responses": {
      "Error": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "CleanRequest": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 1000000,
            "description": "The text to process. The per-request limit depends on your plan: free 30,000, pro 100,000, scale 500,000. Without an account the playground allows 5,000."
          },
          "options": {
            "$ref": "#/components/schemas/CleanOptions"
          }
        }
      },
      "CleanOptions": {
        "type": "object",
        "properties": {
          "profile": {
            "type": "string",
            "enum": [
              "safe",
              "aggressive"
            ],
            "default": "safe",
            "description": "safe keeps legitimate emoji joiners, script joiners, CJK variation selectors and subdivision flag emoji. aggressive removes every invisible character and strips the categories that are otherwise only reported."
          },
          "typography": {
            "type": "boolean",
            "default": false,
            "description": "Convert smart quotes, dashes, ellipses and primes to ASCII. Detection runs either way."
          },
          "nfkc": {
            "type": "boolean",
            "default": false,
            "description": "Apply NFKC normalization after cleaning."
          },
          "homoglyphs": {
            "type": "boolean",
            "default": false,
            "description": "Flag mixed-script look-alike letters. Never replaced automatically."
          }
        }
      },
      "CleanResponse": {
        "type": "object",
        "properties": {
          "cleaned": {
            "type": "string",
            "description": "Present on /clean, omitted on /detect."
          },
          "findings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Finding"
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "by_category": {
                "type": "object",
                "additionalProperties": {
                  "type": "integer"
                }
              },
              "detectors": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Signature"
                }
              },
              "typography": {
                "type": "object",
                "properties": {
                  "applied": {
                    "type": "boolean"
                  },
                  "changes": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "chars_in": {
                "type": "integer"
              },
              "credits_charged": {
                "type": "integer"
              },
              "quota_charged": {
                "type": "integer"
              },
              "quota_remaining": {
                "type": "integer"
              },
              "credits_remaining": {
                "type": "integer"
              }
            }
          },
          "engine_version": {
            "type": "string"
          }
        }
      },
      "Finding": {
        "type": "object",
        "properties": {
          "index": {
            "type": "integer",
            "description": "UTF-16 code-unit index in the original text."
          },
          "cp": {
            "type": "integer"
          },
          "hex": {
            "type": "string",
            "example": "U+200B"
          },
          "name": {
            "type": "string",
            "example": "ZERO WIDTH SPACE"
          },
          "category": {
            "type": "string",
            "enum": [
              "control",
              "line_separator",
              "soft_hyphen",
              "exotic_space",
              "zero_width",
              "joiner",
              "bidi",
              "invisible_math",
              "cgj",
              "variation_selector",
              "tag",
              "filler",
              "deprecated_format",
              "script_format",
              "reserved_ignorable",
              "noncharacter",
              "private_use",
              "surrogate"
            ]
          },
          "action": {
            "type": "string",
            "enum": [
              "strip",
              "space",
              "newline",
              "flag",
              "keep"
            ]
          }
        }
      },
      "Signature": {
        "type": "object",
        "description": "An identified payload, not just a character count.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "stegcloak",
              "zero_width_base_n",
              "unicode_tags",
              "bidi_spoof",
              "whitespace_pattern"
            ]
          },
          "detail": {
            "type": "string"
          },
          "decoded": {
            "type": "string",
            "description": "The recovered message, when one could be decoded."
          },
          "estBytes": {
            "type": "integer"
          },
          "index": {
            "type": "integer"
          },
          "length": {
            "type": "integer"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "validation_error",
                  "unauthorized",
                  "invalid_api_key",
                  "insufficient_credits",
                  "forbidden",
                  "key_revoked",
                  "not_found",
                  "text_too_large",
                  "rate_limited",
                  "internal_error"
                ]
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object"
              }
            }
          }
        }
      }
    }
  }
}