{
  "openapi": "3.0.3",
  "info": {
    "title": "DocumentPro API",
    "version": "1.0.0",
    "description": "REST API for uploading documents, running AI extraction Workflows, and classifying documents with DocumentPro. All endpoints are authenticated with the `x-api-key` header. See https://docs.documentpro.ai for prose guides, and https://docs.documentpro.ai/docs/using-api/mcp-server for the MCP server equivalent of this API.",
    "contact": {
      "url": "https://documentpro.ai/contact"
    }
  },
  "servers": [
    { "url": "https://api.documentpro.ai", "description": "Production" }
  ],
  "security": [{ "ApiKeyAuth": [] }],
  "tags": [
    { "name": "Documents", "description": "Upload, list, retrieve, and delete documents." },
    { "name": "Extract", "description": "Run and poll AI extraction Workflows against a document." },
    { "name": "Workflows", "description": "Create, read, update, and delete Workflows (a.k.a. templates/parsers)." },
    { "name": "Classify", "description": "Classify documents inline or with a saved Classifier." }
  ],
  "paths": {
    "/v1/documents": {
      "post": {
        "tags": ["Documents"],
        "summary": "Upload a document",
        "description": "Uploads a document up to 6MB via multipart/form-data. For files over 6MB, first request a pre-signed URL from `GET /v1/documents/upload_url`, PUT the file there, then confirm the upload by calling this same endpoint with `application/json` and the `document_id` from that step.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": { "type": "string", "format": "binary", "description": "The document file (PDF, JPEG, PNG, TIFF), up to 6MB." }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["document_id", "file_name"],
                "description": "Used only to confirm a large-file upload after PUTting to the pre-signed URL from GET /v1/documents/upload_url.",
                "properties": {
                  "document_id": { "type": "string", "format": "uuid" },
                  "file_name": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document uploaded (or confirmed).",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Document" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "get": {
        "tags": ["Documents"],
        "summary": "List documents",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 100 }, "description": "Number of documents to return." },
          { "name": "document_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Filter by a specific document ID." },
          { "name": "created_at", "in": "query", "schema": { "type": "string", "format": "date-time" }, "description": "Filter by creation date." },
          { "name": "search_term", "in": "query", "schema": { "type": "string" }, "description": "Search documents by name or content." }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of documents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "files": { "type": "array", "items": { "$ref": "#/components/schemas/Document" } },
                    "pagination_key": { "$ref": "#/components/schemas/DocumentPaginationKey" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/documents/upload_url": {
      "get": {
        "tags": ["Documents"],
        "summary": "Get a pre-signed upload URL (files over 6MB)",
        "parameters": [
          { "name": "file_name", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Pre-signed URL and a reserved document_id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "upload_url": { "type": "string", "format": "uri", "description": "Temporary pre-signed URL. PUT the file here directly." },
                    "document_id": { "type": "string", "format": "uuid" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/documents/{document_id}": {
      "get": {
        "tags": ["Documents"],
        "summary": "Get a document",
        "parameters": [
          { "name": "document_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Document detail, including its parser_runs history.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Document" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/documents/{document_id}/run_parser": {
      "get": {
        "tags": ["Extract"],
        "summary": "Run a Workflow against a document",
        "description": "Asynchronous. Returns immediately with a `request_id`; poll `GET /files` with that ID until `request_status` is `completed`, `failed`, or `exception`.",
        "parameters": [
          { "name": "document_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
          { "name": "template_id", "in": "query", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "The Workflow to run." },
          { "name": "use_ocr", "in": "query", "schema": { "type": "boolean" }, "description": "Required true if query_model is gpt-3.5-turbo, or if using any OCR-related parameter below." },
          { "name": "query_model", "in": "query", "schema": { "type": "string", "example": "gpt-4o" } },
          { "name": "detect_layout", "in": "query", "schema": { "type": "boolean" }, "description": "Requires use_ocr=true." },
          { "name": "detect_tables", "in": "query", "schema": { "type": "boolean" }, "description": "Requires use_ocr=true." },
          { "name": "page_ranges", "in": "query", "schema": { "type": "string", "example": "1-3,5,7-9" } },
          { "name": "chunk_by_pages", "in": "query", "schema": { "type": "integer" }, "description": "Segmentation method 1: pages per segment." },
          { "name": "rolling_window", "in": "query", "schema": { "type": "integer" }, "description": "Segmentation method 2: window size." },
          { "name": "start_regex", "in": "query", "schema": { "type": "string" }, "description": "Segmentation method 3. Requires use_ocr=true." },
          { "name": "end_regex", "in": "query", "schema": { "type": "string" }, "description": "Segmentation method 3. Requires use_ocr=true." },
          { "name": "split_regex", "in": "query", "schema": { "type": "string" }, "description": "Segmentation method 4. Requires use_ocr=true." },
          { "name": "use_all_matches", "in": "query", "schema": { "type": "boolean" }, "description": "Use all regex matches instead of just the first. Requires use_ocr=true." }
        ],
        "responses": {
          "200": {
            "description": "Parsing job initiated.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExtractionJob" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/files": {
      "get": {
        "tags": ["Extract"],
        "summary": "Poll an extraction job's result",
        "parameters": [
          { "name": "request_id", "in": "query", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Current job state. result_json_data is populated once request_status is completed.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExtractionJob" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "delete": {
        "tags": ["Extract"],
        "summary": "Delete an extraction job's result",
        "description": "Irreversible. Deletes a parsing job and its associated result data.",
        "parameters": [
          { "name": "request_id", "in": "query", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" } } } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/templates": {
      "post": {
        "tags": ["Workflows"],
        "summary": "Create a Workflow",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkflowCreateRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Workflow created.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Workflow" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "get": {
        "tags": ["Workflows"],
        "summary": "List Workflows",
        "parameters": [
          { "name": "pagination_key", "in": "query", "schema": { "type": "string" }, "description": "template_id returned as pagination_key from a previous call." }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of Workflows. Up to 50 per page.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/Workflow" } },
                    "pagination_key": { "type": "string", "nullable": true }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/templates/{template_id}": {
      "get": {
        "tags": ["Workflows"],
        "summary": "Get a Workflow",
        "parameters": [
          { "name": "template_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Workflow detail.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Workflow" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "put": {
        "tags": ["Workflows"],
        "summary": "Update a Workflow",
        "description": "Only fields included in the request body are updated; omitted fields keep their current value.",
        "parameters": [
          { "name": "template_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkflowUpdateRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Workflow updated.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Workflow" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "delete": {
        "tags": ["Workflows"],
        "summary": "Delete a Workflow",
        "description": "Irreversible. Documents previously processed by this Workflow are not deleted; they're just no longer linked to it.",
        "parameters": [
          { "name": "template_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } } } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/classify": {
      "post": {
        "tags": ["Classify"],
        "summary": "Classify a document inline",
        "description": "Classifies a document into one of the categories provided in the request body. No saved Classifier required. The document must already be uploaded and OCR-processed (see Run Extract) before it can be classified.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClassifyRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Classification result.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClassificationResult" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/classifiers": {
      "post": {
        "tags": ["Classify"],
        "summary": "Create a Classifier",
        "description": "A Classifier is a reusable, named set of categories. Create once, then run it against many documents with POST /v1/classifiers/{classifier_id}/classify.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClassifierCreateRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Classifier created.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Classifier" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "get": {
        "tags": ["Classify"],
        "summary": "List Classifiers",
        "parameters": [
          { "name": "pagination_key", "in": "query", "schema": { "type": "string" }, "description": "classifier_id of the last item from a previous response." }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of Classifiers.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/Classifier" } },
                    "pagination_key": { "type": "string", "nullable": true }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/classifiers/{classifier_id}": {
      "get": {
        "tags": ["Classify"],
        "summary": "Get a Classifier",
        "parameters": [
          { "name": "classifier_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Classifier detail.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Classifier" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "put": {
        "tags": ["Classify"],
        "summary": "Update a Classifier",
        "description": "Only fields included in the request body are updated.",
        "parameters": [
          { "name": "classifier_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClassifierUpdateRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Classifier updated.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Classifier" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "delete": {
        "tags": ["Classify"],
        "summary": "Delete a Classifier",
        "description": "Irreversible. Future calls to Run Classification with this classifier_id return 404.",
        "parameters": [
          { "name": "classifier_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } } } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/classifiers/{classifier_id}/classify": {
      "post": {
        "tags": ["Classify"],
        "summary": "Run a saved Classifier against a document",
        "description": "Recommended for automation pipelines that reuse the same label set. The document must already be uploaded and OCR-processed.",
        "parameters": [
          { "name": "classifier_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["document_id"],
                "properties": {
                  "document_id": { "type": "string", "format": "uuid" },
                  "page_range": { "type": "string", "description": "Overrides the Classifier's default page range for this call only." },
                  "query_model": { "type": "string", "enum": ["gpt-4o-mini", "gpt-4o"], "description": "Overrides the Classifier's default model for this call only." }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Classification result.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClassificationResult" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your DocumentPro API key. Same key is used across all Workflows and the MCP server."
      }
    },
    "responses": {
      "BadRequest": { "description": "Malformed request or invalid arguments.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "Unauthorized": { "description": "Missing or invalid x-api-key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "Forbidden": { "description": "API key does not have access to the requested resource, or a plan limit was hit.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "NotFound": { "description": "The requested resource does not exist on this account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "ServerError": { "description": "Something went wrong on DocumentPro's side.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "description": "Standard error shape. error_code, credits_remaining, and page_limit are only present for the two structured error cases (insufficient_credits, page_limit_exceeded) — every other error omits them. See https://docs.documentpro.ai/docs/using-api/error-codes.",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "error": {
            "type": "string",
            "description": "Human-readable description of the error. Not a fixed set of codes — match on HTTP status, or on error_code for the two cases where it's present."
          },
          "error_code": {
            "type": "string",
            "enum": ["insufficient_credits", "page_limit_exceeded"],
            "description": "Only present for these two cases. Absent on every other error."
          },
          "credits_remaining": { "type": "integer", "description": "Only present when error_code is insufficient_credits." },
          "upgrade_url": { "type": "string", "format": "uri", "description": "Only present when error_code is insufficient_credits." },
          "page_limit": { "type": "integer", "description": "Only present when error_code is page_limit_exceeded. 100 pages, 300 for tax-flagged accounts." }
        }
      },
      "TemplateField": {
        "type": "object",
        "required": ["name", "type"],
        "properties": {
          "name": { "type": "string", "maxLength": 50, "description": "Lowercase letters, numbers, or underscore only." },
          "type": { "type": "string", "enum": ["text", "number", "date", "table"] },
          "description": { "type": "string", "maxLength": 150 },
          "required": { "type": "boolean", "default": false },
          "subFields": {
            "type": "array",
            "description": "Required (at least one entry) when type is table.",
            "items": {
              "type": "object",
              "required": ["name", "type"],
              "properties": {
                "name": { "type": "string", "maxLength": 50 },
                "type": { "type": "string", "enum": ["text", "number", "date"] },
                "description": { "type": "string", "maxLength": 150 },
                "required": { "type": "boolean", "default": false }
              }
            }
          }
        }
      },
      "TemplateSchema": {
        "type": "object",
        "properties": {
          "fields": { "type": "array", "items": { "$ref": "#/components/schemas/TemplateField" } }
        }
      },
      "ParserConfig": {
        "type": "object",
        "properties": {
          "parse_email_attachments": { "type": "boolean", "default": true },
          "parse_email_body": { "type": "boolean", "default": false },
          "date_format": { "type": "string", "nullable": true, "example": "%Y-%m-%d" },
          "ocr_config": {
            "type": "object",
            "properties": {
              "use_ocr": { "type": "boolean", "default": false },
              "detect_layout": { "type": "boolean", "default": true },
              "detect_tables": { "type": "boolean", "default": false },
              "remove_headers": { "type": "boolean", "default": false },
              "remove_footers": { "type": "boolean", "default": false },
              "remove_tables": { "type": "boolean", "default": false }
            }
          },
          "query_config": {
            "type": "object",
            "properties": {
              "query_model": { "type": "string", "example": "gpt-4o-mini" },
              "page_ranges": { "type": "string", "example": "1-3,5,7-9" },
              "start_regex": { "type": "string", "nullable": true },
              "end_regex": { "type": "string", "nullable": true },
              "split_regex": { "type": "string", "nullable": true },
              "use_all_matches": { "type": "boolean", "default": false }
            }
          }
        }
      },
      "WorkflowCreateRequest": {
        "type": "object",
        "required": ["template_title", "template_type", "template_schema"],
        "properties": {
          "template_title": { "type": "string", "description": "Must be unique within your account." },
          "template_type": { "type": "string", "example": "invoice" },
          "template_schema": { "$ref": "#/components/schemas/TemplateSchema" },
          "webhook_url": { "type": "string", "format": "uri", "nullable": true },
          "parser_config": { "$ref": "#/components/schemas/ParserConfig" }
        }
      },
      "WorkflowUpdateRequest": {
        "type": "object",
        "description": "All fields optional; only included fields are changed.",
        "properties": {
          "template_type": { "type": "string" },
          "template_schema": { "$ref": "#/components/schemas/TemplateSchema" },
          "webhook_url": { "type": "string", "format": "uri", "nullable": true },
          "parser_config": { "$ref": "#/components/schemas/ParserConfig" }
        }
      },
      "Workflow": {
        "type": "object",
        "properties": {
          "template_id": { "type": "string", "format": "uuid", "description": "template_id and workflow_id are used interchangeably." },
          "template_title": { "type": "string" },
          "template_type": { "type": "string" },
          "template_category": { "type": "string" },
          "template_schema": { "$ref": "#/components/schemas/TemplateSchema" },
          "email_id": { "type": "string", "format": "email", "description": "Auto-generated address for forwarding documents to this Workflow." },
          "webhook_url": { "type": "string", "format": "uri", "nullable": true },
          "parser_config": { "$ref": "#/components/schemas/ParserConfig" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "Document": {
        "type": "object",
        "properties": {
          "document_id": { "type": "string", "format": "uuid" },
          "user_id": { "type": "string", "format": "uuid" },
          "source_name": { "type": "string", "example": "api" },
          "s3_key": { "type": "string", "description": "Temporary S3 URL for the source file." },
          "file_name": { "type": "string" },
          "file_extension": { "type": "string" },
          "num_pages": { "type": "integer" },
          "meta_tags": { "type": "object" },
          "parser_runs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "template_id": { "type": "string", "format": "uuid" },
                "template_title": { "type": "string" },
                "request_id": { "type": "string", "format": "uuid" },
                "params": { "type": "object" },
                "datetime": { "type": "string", "format": "date-time" }
              }
            }
          },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "DocumentPaginationKey": {
        "type": "object",
        "nullable": true,
        "properties": {
          "document_id": { "type": "string", "format": "uuid" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "ExtractionJob": {
        "type": "object",
        "properties": {
          "request_id": { "type": "string", "format": "uuid" },
          "request_status": { "type": "string", "enum": ["pending", "processing", "completed", "failed", "exception"] },
          "response_body": {
            "type": "object",
            "properties": {
              "file_name": { "type": "string" },
              "file_presigned_url": { "type": "string", "format": "uri", "nullable": true },
              "user_error_msg": { "type": "string", "nullable": true },
              "template_id": { "type": "string", "format": "uuid" },
              "template_type": { "type": "string" },
              "template_title": { "type": "string" },
              "num_pages": { "type": "integer" },
              "human_verification_status": { "type": "string", "enum": ["pending", "approved", "rejected"] },
              "has_missing_required_fields": { "type": "boolean" },
              "result_json_data": { "type": "object", "nullable": true, "description": "Populated once request_status is completed. Shape depends on the Workflow's template_schema." }
            }
          },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "ClassCategory": {
        "type": "object",
        "required": ["label", "description"],
        "properties": {
          "label": { "type": "string", "example": "invoice" },
          "description": { "type": "string", "example": "A document requesting payment for goods or services rendered" }
        }
      },
      "ClassifyRequest": {
        "type": "object",
        "required": ["document_id", "classification_schema"],
        "properties": {
          "document_id": { "type": "string", "format": "uuid" },
          "classification_schema": { "type": "array", "minItems": 2, "items": { "$ref": "#/components/schemas/ClassCategory" } },
          "page_range": { "type": "string", "example": "1-3" },
          "query_model": { "type": "string", "enum": ["gpt-4o-mini", "gpt-4o"], "default": "gpt-4o-mini" }
        }
      },
      "ClassifierConfigs": {
        "type": "object",
        "required": ["classes"],
        "properties": {
          "classes": { "type": "array", "minItems": 2, "items": { "$ref": "#/components/schemas/ClassCategory" } },
          "classifier_type": { "type": "string", "default": "document" },
          "query_model": { "type": "string", "enum": ["gpt-4o-mini", "gpt-4o"], "default": "gpt-4o-mini" },
          "page_range": { "type": "string", "example": "1-2" }
        }
      },
      "ClassifierCreateRequest": {
        "type": "object",
        "required": ["name", "configs"],
        "properties": {
          "name": { "type": "string", "example": "Document Type Router" },
          "configs": { "$ref": "#/components/schemas/ClassifierConfigs" }
        }
      },
      "ClassifierUpdateRequest": {
        "type": "object",
        "description": "All fields optional; only included fields are changed.",
        "properties": {
          "name": { "type": "string" },
          "configs": { "$ref": "#/components/schemas/ClassifierConfigs" }
        }
      },
      "Classifier": {
        "type": "object",
        "properties": {
          "classifier_id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "user_id": { "type": "string", "format": "uuid" },
          "configs": { "$ref": "#/components/schemas/ClassifierConfigs" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "ClassificationResult": {
        "type": "object",
        "properties": {
          "request_id": { "type": "string", "format": "uuid" },
          "document_id": { "type": "string", "format": "uuid" },
          "classifier_id": { "type": "string", "format": "uuid", "nullable": true, "description": "null for inline classification via POST /v1/classify." },
          "classification": { "type": "string", "description": "The best-matching label." },
          "confidence_scores": { "type": "object", "additionalProperties": { "type": "number", "format": "float" }, "description": "Score 0.0-1.0 per label, summing to ~1.0." },
          "request_status": { "type": "string", "enum": ["completed", "failed", "exception"] },
          "credits_used": { "type": "integer" },
          "num_pages": { "type": "integer" },
          "duration": { "type": "number", "format": "float", "description": "Seconds." }
        }
      }
    }
  }
}
