{
  "openapi": "3.1.0",
  "info": {
    "title": "Rahunko API",
    "version": "1",
    "description": "Explicit public OpenAPI catalog for Rahunko's external /api/v1 workspace API. Cookie/session/admin handlers are intentionally excluded."
  },
  "servers": [
    {
      "url": "https://rahunko.com",
      "description": "Rahunko production API"
    }
  ],
  "tags": [
    {
      "name": "Documents",
      "description": "Workspace document records and lifecycle."
    },
    {
      "name": "Uploads",
      "description": "Bounded resumable multipart source uploads."
    },
    {
      "name": "Jobs",
      "description": "Asynchronous extraction status and result polling."
    },
    {
      "name": "Review",
      "description": "Source-backed corrections and explicit review completion."
    },
    {
      "name": "Evidence",
      "description": "Private source evidence reads."
    },
    {
      "name": "Exports",
      "description": "Revision-fenced JSON, CSV, and XLSX exports."
    },
    {
      "name": "Quota",
      "description": "Workspace page-unit quota state."
    },
    {
      "name": "Webhooks",
      "description": "Operator-provisioned webhook endpoint records."
    },
    {
      "name": "Lifecycle",
      "description": "Document processing and deletion lifecycle operations."
    }
  ],
  "paths": {
    "/api/v1/workspaces/{workspaceId}/documents": {
      "get": {
        "operationId": "listDocuments",
        "summary": "List workspace documents",
        "description": "Returns a cursor-paginated list of documents in the authorized workspace.",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Number of documents to return; defaults to 50 and may be 1–100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "required": false
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque cursor returned as nextCursor.",
            "schema": {
              "type": "string"
            },
            "required": false
          }
        ],
        "responses": {
          "200": {
            "description": "Document page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid limit or cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:read"
      }
    },
    "/api/v1/workspaces/{workspaceId}/documents/{documentId}": {
      "get": {
        "operationId": "getDocument",
        "summary": "Get a document",
        "description": "Returns document lifecycle and processing metadata, sources, run metadata, and page records.",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Document detail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentDetailResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Document is not available in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:read"
      },
      "delete": {
        "operationId": "deleteDocument",
        "summary": "Delete a document",
        "description": "Requests revision-fenced document deletion. Send JSON {revision}; the public gateway converts that bounded request into the internal deletion fence. Retries with an old revision are rejected; deletion is not restored by retry.",
        "tags": [
          "Documents",
          "Lifecycle"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Delete this exact document revision.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "revision": {
                    "type": "integer",
                    "minimum": 0
                  }
                },
                "required": [
                  "revision"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document tombstone/lifecycle state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentLifecycleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid JSON delete revision body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Document is not available in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The supplied revision is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/documents/{documentId}/cancel": {
      "post": {
        "operationId": "cancelDocument",
        "summary": "Cancel document processing",
        "description": "Requests cancellation against the supplied document revision.",
        "tags": [
          "Documents",
          "Lifecycle"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Cancel processing for this exact document revision.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "revision": {
                    "type": "integer",
                    "minimum": 0
                  }
                },
                "required": [
                  "revision"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated document lifecycle state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentLifecycleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON revision body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The supplied revision is stale or cancellation lost a processing race.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/documents/{documentId}/evidence": {
      "get": {
        "operationId": "getDocumentEvidence",
        "summary": "Get complete document evidence",
        "description": "Returns the stored parser evidence and completed finance extraction artifact. The response is private and never cacheable publicly.",
        "tags": [
          "Evidence"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Parser evidence and extraction.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentEvidenceResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Evidence is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Evidence is not ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "Evidence exceeds the endpoint size limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "503": {
            "description": "Stored evidence is invalid or unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:read"
      }
    },
    "/api/v1/workspaces/{workspaceId}/documents/{documentId}/evidence/pages/{pageNumber}": {
      "get": {
        "operationId": "getDocumentEvidencePage",
        "summary": "Get one evidence page",
        "description": "Returns one verified evidence page for the requested document revision. Page numbers are 1-based and bounded to 500; evidence is private.",
        "tags": [
          "Evidence"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          },
          {
            "name": "pageNumber",
            "in": "path",
            "description": "1-based page number.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            },
            "required": true
          },
          {
            "name": "revision",
            "in": "query",
            "description": "Document revision used to fence the evidence read.",
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Verified evidence page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvidencePageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid page or revision.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Evidence page is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Evidence is not ready or revision changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "503": {
            "description": "Evidence is invalid or unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:read"
      }
    },
    "/api/v1/workspaces/{workspaceId}/documents/{documentId}/export": {
      "get": {
        "operationId": "exportDocument",
        "summary": "Export a document revision",
        "description": "Exports the exact requested document and review revision as JSON, CSV, or XLSX. The optional QuickBooks profile is valid only for CSV and requires a reviewed/check-passed document.",
        "tags": [
          "Exports"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          },
          {
            "name": "format",
            "in": "query",
            "description": "Export format. Defaults to json.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv",
                "xlsx"
              ],
              "default": "json"
            },
            "required": false
          },
          {
            "name": "revision",
            "in": "query",
            "description": "Exact document and review revision to export.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,9}$"
            },
            "required": true
          },
          {
            "name": "profile",
            "in": "query",
            "description": "Optional CSV import profile.",
            "schema": {
              "type": "string",
              "enum": [
                "quickbooks-online-us-bank-csv-v1"
              ]
            },
            "required": false
          }
        ],
        "responses": {
          "200": {
            "description": "Export bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schemaVersion": {
                      "const": "finance-extraction-1"
                    },
                    "processingStatus": {
                      "const": "completed"
                    },
                    "documentId": {
                      "type": "string"
                    },
                    "transactions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ExtractionTransaction"
                      }
                    },
                    "documents": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ExtractionDocument"
                      }
                    },
                    "checks": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ExtractionCheck"
                      }
                    },
                    "review": {
                      "$ref": "#/components/schemas/ReviewSummary"
                    }
                  },
                  "required": [
                    "schemaVersion",
                    "processingStatus",
                    "documentId",
                    "transactions",
                    "documents",
                    "checks",
                    "review"
                  ],
                  "additionalProperties": false
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "text/csv"
                }
              },
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            },
            "headers": {
              "x-document-revision": {
                "description": "Revision exported.",
                "required": true,
                "schema": {
                  "type": "string",
                  "pattern": "^\\d{1,9}$"
                }
              },
              "content-disposition": {
                "description": "Attachment filename selected by the server.",
                "required": true,
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid format, revision, or profile combination.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Document/evidence is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Revision is stale, review is required for the selected profile, or export is not ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "422": {
            "description": "Export projection failed or is too large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "503": {
            "description": "Export evidence is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "exports:read"
      }
    },
    "/api/v1/workspaces/{workspaceId}/documents/{documentId}/review": {
      "get": {
        "operationId": "getDocumentReview",
        "summary": "Read document review state",
        "description": "Returns review fields, source references, issues, transaction overrides, and the revision to use for the next fenced mutation.",
        "tags": [
          "Review"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Review state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReviewApiResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Document or evidence is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Review evidence is not ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "503": {
            "description": "Review projection is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:read"
      },
      "patch": {
        "operationId": "updateDocumentReview",
        "summary": "Apply review corrections",
        "description": "Applies source-backed field or transaction changes against an exact revision and returns the projected review. This changes review state but does not acknowledge/complete it.",
        "tags": [
          "Review"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Apply source-backed field corrections and/or transaction include, exclude, or add changes against the exact current revision. The server reprojects checks; this does not acknowledge the review.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "revision": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "field": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        },
                        "value": {
                          "type": "string",
                          "maxLength": 20000
                        },
                        "sourceRefs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SourceReference"
                          }
                        },
                        "confidence": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "field",
                        "value",
                        "sourceRefs"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "transactions": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "oneOf": [
                        {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string",
                              "pattern": "^[A-Za-z0-9_-]{1,160}$"
                            },
                            "action": {
                              "type": "string",
                              "enum": [
                                "include",
                                "exclude"
                              ]
                            }
                          },
                          "required": [
                            "id",
                            "action"
                          ],
                          "additionalProperties": false
                        },
                        {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string",
                              "pattern": "^[A-Za-z0-9_-]{1,160}$"
                            },
                            "action": {
                              "const": "add"
                            },
                            "transaction": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "pattern": "^[A-Za-z0-9_-]{1,160}$"
                                },
                                "postingDate": {
                                  "type": "string"
                                },
                                "valueDate": {
                                  "type": "string"
                                },
                                "description": {
                                  "type": "string"
                                },
                                "amount": {
                                  "type": "object",
                                  "properties": {
                                    "coefficient": {
                                      "type": "string",
                                      "pattern": "^(?:0|-?[1-9]\\d*)$",
                                      "maxLength": 80
                                    },
                                    "scale": {
                                      "type": "integer",
                                      "minimum": 0,
                                      "maximum": 9
                                    },
                                    "currency": {
                                      "type": "string",
                                      "pattern": "^[A-Z]{3}$"
                                    }
                                  },
                                  "required": [
                                    "coefficient",
                                    "scale",
                                    "currency"
                                  ],
                                  "additionalProperties": false
                                },
                                "rawAmount": {
                                  "type": "string"
                                },
                                "sourceRefs": {
                                  "type": "array",
                                  "items": {
                                    "$ref": "#/components/schemas/SourceReference"
                                  }
                                }
                              },
                              "required": [
                                "id",
                                "sourceRefs"
                              ],
                              "additionalProperties": false
                            }
                          },
                          "required": [
                            "id",
                            "action",
                            "transaction"
                          ],
                          "additionalProperties": false
                        }
                      ]
                    }
                  }
                },
                "required": [
                  "revision"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated review state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReviewApiResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid review update body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The supplied revision is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "422": {
            "description": "A correction or review projection is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "503": {
            "description": "Evidence needed for projection is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/documents/{documentId}/review/complete": {
      "post": {
        "operationId": "completeDocumentReview",
        "summary": "Complete document review",
        "description": "Explicitly acknowledges the supplied review revision and may enqueue configured webhook events. This is intentionally separate from corrections and is not performed by the quickstart sample.",
        "tags": [
          "Review"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "Document identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Explicitly complete review for this exact revision.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "revision": {
                    "type": "integer",
                    "minimum": 0
                  }
                },
                "required": [
                  "revision"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Review completion result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReviewCompleteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid review revision body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The supplied revision is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/jobs/{jobId}": {
      "get": {
        "operationId": "getJob",
        "summary": "Get processing job status",
        "description": "Returns processing status, progress, review status, revision, and bounded issues for a workspace job.",
        "tags": [
          "Jobs"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "jobId",
            "in": "path",
            "description": "Processing job identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Job status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Job is not available in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "jobs:read"
      }
    },
    "/api/v1/workspaces/{workspaceId}/jobs/{jobId}/result": {
      "get": {
        "operationId": "getJobResult",
        "summary": "Poll for a job result",
        "description": "Returns waiting, failed, or ready. A ready response includes the immutable document revision and export URLs; waiting uses HTTP 409 while the result is not ready.",
        "tags": [
          "Jobs",
          "Exports"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "jobId",
            "in": "path",
            "description": "Processing job identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Ready or failed job result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Job is not available in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Job is still waiting; inspect status and poll again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "503": {
            "description": "A completed job has no available result document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "jobs:read"
      }
    },
    "/api/v1/workspaces/{workspaceId}/quota": {
      "get": {
        "operationId": "getQuota",
        "summary": "Read workspace quota",
        "description": "Returns page-unit policy, periods, reservations, settled units, and available capacity for the authorized workspace.",
        "tags": [
          "Quota"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Quota summary.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuotaSummaryResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Workspace is not available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:read"
      }
    },
    "/api/v1/workspaces/{workspaceId}/uploads": {
      "post": {
        "operationId": "createUploadIntent",
        "summary": "Create a multipart upload intent",
        "description": "Creates a workspace-scoped immutable upload intent. Files are bounded to 52428800 bytes; the client batch is bounded to 100 files, 524288000 bytes, and 2000 page units. The intent expires after approximately 60 minutes.",
        "tags": [
          "Uploads"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Client-generated idempotency key; 8–128 characters matching [A-Za-z0-9._:-].",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]{8,128}$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Create an upload intent. batchId is required and groups client-side batch accounting; it is not an authorization boundary.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "batchId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._:-]{8,128}$",
                    "minLength": 8,
                    "maxLength": 128
                  },
                  "fileName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 180
                  },
                  "mediaType": {
                    "type": "string",
                    "enum": [
                      "application/pdf",
                      "image/png",
                      "image/jpeg",
                      "image/webp",
                      "image/heic",
                      "image/heif"
                    ]
                  },
                  "byteLength": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 52428800
                  },
                  "sha256": {
                    "type": "string",
                    "pattern": "^[a-fA-F0-9]{64}$"
                  },
                  "sourceKind": {
                    "type": "string",
                    "enum": [
                      "pdf",
                      "image"
                    ]
                  }
                },
                "required": [
                  "batchId",
                  "fileName",
                  "mediaType",
                  "byteLength",
                  "sha256",
                  "sourceKind"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replay of the same idempotent intent request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadIntentResponse"
                }
              }
            }
          },
          "201": {
            "description": "New upload intent and endpoint URLs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadIntentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid upload metadata or idempotency key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Processing access or API scope is denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was reused with a different request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "Workspace batch or upload size limit is exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/uploads/{uploadId}": {
      "get": {
        "operationId": "getUpload",
        "summary": "Read multipart upload state",
        "description": "Returns the current upload state and already accepted parts. Expired intents are aborted before the state is returned.",
        "tags": [
          "Uploads"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "uploadId",
            "in": "path",
            "description": "Multipart upload identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Upload state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadStateResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Upload is not available in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/uploads/{uploadId}/abort": {
      "post": {
        "operationId": "abortUpload",
        "summary": "Abort a multipart upload",
        "description": "Aborts an unfinished multipart object and marks the workspace upload aborted. It does not create a document.",
        "tags": [
          "Uploads"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "uploadId",
            "in": "path",
            "description": "Multipart upload identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Send an empty JSON object.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Aborted upload state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadAbortResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Upload is not available in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Upload cannot be aborted in its current state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/uploads/{uploadId}/complete": {
      "post": {
        "operationId": "completeUpload",
        "summary": "Complete multipart assembly",
        "description": "Assembles all accepted R2 parts after every part is uploaded. This is not processing/finalization; call finalize next.",
        "tags": [
          "Uploads"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "uploadId",
            "in": "path",
            "description": "Multipart upload identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Send an empty JSON object.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Completed upload state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadCompleteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Upload is not available in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Parts are incomplete, invalid, expired, or storage state conflicts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/uploads/{uploadId}/finalize": {
      "post": {
        "operationId": "finalizeUpload",
        "summary": "Finalize an uploaded document",
        "description": "Validates the completed source, applies quota/page checks, creates or replays one document/job, and returns HTTP 202 while extraction proceeds asynchronously.",
        "tags": [
          "Uploads",
          "Jobs"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "uploadId",
            "in": "path",
            "description": "Multipart upload identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Finalize the completed multipart upload. The JSON object may be empty. PDF passwords are accepted only for PDFs and are limited to 256 characters; OCR language is optional.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "password": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256
                  },
                  "ocrLanguage": {
                    "type": "string",
                    "enum": [
                      "eng",
                      "ukr",
                      "deu",
                      "spa",
                      "eng+ukr+deu+spa"
                    ]
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Document and asynchronous extraction job.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FinalizeUploadResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid finalize body or password/media combination.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Processing access or API scope is denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Upload is expired/incomplete or quota/page limit is exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "503": {
            "description": "Document password support is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/uploads/{uploadId}/parts/{partNumber}": {
      "put": {
        "operationId": "uploadPart",
        "summary": "Upload one multipart part",
        "description": "Uploads one binary part. The server requires exact Content-Length, application/octet-stream, an idempotency key, and the SHA-256 of these exact bytes. Parts are bounded by the negotiated part size (8388608 bytes, except the final part).",
        "tags": [
          "Uploads"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "uploadId",
            "in": "path",
            "description": "Multipart upload identifier.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,160}$"
            },
            "required": true
          },
          {
            "name": "partNumber",
            "in": "path",
            "description": "1-based part number from upload.partCount.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "required": true
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Client-generated idempotency key; 8–128 characters matching [A-Za-z0-9._:-].",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]{8,128}$"
            },
            "required": true
          },
          {
            "name": "X-Content-SHA256",
            "in": "header",
            "description": "Lowercase or uppercase SHA-256 digest of the exact request bytes.",
            "schema": {
              "type": "string",
              "pattern": "^[a-fA-F0-9]{64}$"
            },
            "required": true
          },
          {
            "name": "Content-Length",
            "in": "header",
            "description": "Exact byte length of the request body.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 8388608
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Raw part bytes; do not send multipart/form-data.",
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay of an accepted part.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadPartResponse"
                }
              }
            }
          },
          "201": {
            "description": "Part accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadPartResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid part, length, or idempotency key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "Part claim conflicts with the current upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "Content type or first-part file magic is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "422": {
            "description": "The supplied SHA-256 does not match the bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "502": {
            "description": "Object storage could not accept the part.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "documents:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/webhooks": {
      "get": {
        "operationId": "listWebhookEndpoints",
        "summary": "List webhook endpoints",
        "description": "Lists only endpoint records. Destination URLs and signing secrets are operator-provisioned and are not returned by this API.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook endpoint records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointListResponse"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The key is revoked or lacks the required workspace scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Workspace is not available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "webhooks:read"
      },
      "post": {
        "operationId": "registerWebhookEndpoint",
        "summary": "Register an operator-provisioned webhook endpoint",
        "description": "Registers a configured endpointId. The external API does not accept an arbitrary callback URL and never returns the destination secret.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The endpointId must already be provisioned by the operator.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "endpointId": {
                    "type": "string",
                    "pattern": "^ep_[A-Za-z0-9_-]{8,80}$"
                  }
                },
                "required": [
                  "endpointId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registered webhook endpoint record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointResponse"
                }
              }
            }
          },
          "400": {
            "description": "The endpointId is missing or not provisioned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Workspace or endpoint is not available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "webhooks:write"
      }
    },
    "/api/v1/workspaces/{workspaceId}/webhooks/{endpointId}": {
      "delete": {
        "operationId": "deleteWebhookEndpoint",
        "summary": "Disable a webhook endpoint",
        "description": "Disables the operator-provisioned endpoint record for this workspace. It does not expose or delete the operator configuration.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "description": "Workspace identifier. Only the workspace named by the API key is accessible.",
            "schema": {
              "type": "string",
              "pattern": "^ws_[A-Za-z0-9]+$"
            },
            "required": true
          },
          {
            "name": "endpointId",
            "in": "path",
            "description": "Operator-provisioned webhook endpoint identifier.",
            "schema": {
              "type": "string",
              "pattern": "^ep_[A-Za-z0-9_-]{8,80}$"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Disabled webhook endpoint record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointResponse"
                }
              }
            }
          },
          "400": {
            "description": "Workspace or endpoint identifier is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "The Authorization header is missing or is not a valid Rahunko API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "A mutation without a valid Rahunko bearer may be rejected by origin middleware with request_origin_not_allowed; a valid but unauthorized key returns api_key_scope_denied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint is not available in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The API-key rate limit was exceeded (600 requests per IP or 300 per key in 60 seconds). Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "required": true,
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-required-scope": "webhooks:write"
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "rk_ plus 40 alphanumeric characters",
        "description": "Workspace-scoped Rahunko API key. Each operation documents its required x-required-scope; this is a bearer key, not OAuth."
      }
    },
    "schemas": {
      "ApiError": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "integer"
          },
          "statusMessage": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              }
            },
            "required": [
              "code"
            ],
            "additionalProperties": false
          }
        },
        "additionalProperties": true
      },
      "ApiKeyScope": {
        "type": "string",
        "enum": [
          "documents:read",
          "documents:write",
          "exports:read",
          "jobs:read",
          "webhooks:read",
          "webhooks:write"
        ]
      },
      "DocumentProcessingStatus": {
        "type": "string",
        "enum": [
          "uploading",
          "validating",
          "extracting",
          "checking",
          "completed",
          "failed",
          "unsupported",
          "cancelled"
        ]
      },
      "DocumentReviewStatus": {
        "type": "string",
        "enum": [
          "unreviewed",
          "needs_review",
          "checks_passed",
          "user_reviewed"
        ]
      },
      "SourceReference": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "page",
              "region",
              "token_span",
              "unresolved"
            ]
          },
          "sourceId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "pageNumber": {
            "type": "integer",
            "minimum": 1
          },
          "region": {
            "type": "object",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "width": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "height": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              }
            },
            "required": [
              "x",
              "y",
              "width",
              "height"
            ],
            "additionalProperties": false
          },
          "tokenStart": {
            "type": "integer",
            "minimum": 0
          },
          "tokenEnd": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "kind",
          "sourceId"
        ],
        "additionalProperties": false
      },
      "DocumentRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "workspaceId": {
            "type": "string",
            "pattern": "^ws_[A-Za-z0-9]+$"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "bank_statement",
              "invoice",
              "receipt",
              "mixed",
              "unknown"
            ]
          },
          "processingStatus": {
            "type": "string",
            "enum": [
              "uploading",
              "validating",
              "extracting",
              "checking",
              "completed",
              "failed",
              "unsupported",
              "cancelled"
            ]
          },
          "reviewStatus": {
            "type": "string",
            "enum": [
              "unreviewed",
              "needs_review",
              "checks_passed",
              "user_reviewed"
            ]
          },
          "lifecycleStatus": {
            "type": "string",
            "enum": [
              "active",
              "deleting",
              "deleted"
            ]
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "workspaceId",
          "name",
          "kind",
          "processingStatus",
          "reviewStatus",
          "lifecycleStatus",
          "revision",
          "createdAt",
          "updatedAt"
        ],
        "additionalProperties": false
      },
      "DocumentSourceRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "documentId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "workspaceId": {
            "type": "string",
            "pattern": "^ws_[A-Za-z0-9]+$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "pdf",
              "image"
            ]
          },
          "mediaType": {
            "type": "string",
            "enum": [
              "application/pdf",
              "image/png",
              "image/jpeg",
              "image/webp",
              "image/heic",
              "image/heif"
            ]
          },
          "byteLength": {
            "type": "integer",
            "minimum": 1,
            "maximum": 52428800
          },
          "sha256": {
            "type": "string",
            "pattern": "^[a-fA-F0-9]{64}$"
          },
          "pageCount": {
            "type": "integer",
            "minimum": 1
          },
          "storageKey": {
            "type": "string"
          },
          "ocrLanguage": {
            "type": "string",
            "enum": [
              "eng",
              "ukr",
              "deu",
              "spa",
              "eng+ukr+deu+spa"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "documentId",
          "workspaceId",
          "kind",
          "mediaType",
          "byteLength",
          "sha256",
          "storageKey",
          "createdAt"
        ],
        "additionalProperties": false
      },
      "DocumentPageRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "documentId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "pageIndex": {
            "type": "integer",
            "minimum": 0
          },
          "evidence": {
            "type": "object",
            "additionalProperties": true
          },
          "artifactKey": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "documentId",
          "pageIndex"
        ],
        "additionalProperties": false
      },
      "ExtractionRunRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "documentId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "workspaceId": {
            "type": "string",
            "pattern": "^ws_[A-Za-z0-9]+$"
          },
          "parserVersion": {
            "type": "string"
          },
          "schemaVersion": {
            "type": "string"
          },
          "processingStatus": {
            "$ref": "#/components/schemas/DocumentProcessingStatus"
          },
          "reviewStatus": {
            "$ref": "#/components/schemas/DocumentReviewStatus"
          },
          "pageCount": {
            "type": "integer",
            "minimum": 0
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "completedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "documentId",
          "workspaceId",
          "parserVersion",
          "schemaVersion",
          "processingStatus",
          "reviewStatus",
          "pageCount",
          "revision",
          "createdAt"
        ],
        "additionalProperties": false
      },
      "ExactMoney": {
        "type": "object",
        "properties": {
          "coefficient": {
            "type": "string",
            "pattern": "^(?:0|-?[1-9]\\d*)$",
            "maxLength": 80
          },
          "scale": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          }
        },
        "required": [
          "coefficient",
          "scale",
          "currency"
        ],
        "additionalProperties": false
      },
      "ReviewIssue": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": [
              "ambiguous_date",
              "ambiguous_currency",
              "low_confidence",
              "arithmetic_mismatch",
              "missing_field",
              "unsupported"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warning",
              "error"
            ]
          },
          "message": {
            "type": "string"
          },
          "field": {
            "type": "string"
          },
          "sourceRefs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceReference"
            }
          }
        },
        "required": [
          "id",
          "code",
          "severity",
          "message",
          "sourceRefs"
        ],
        "additionalProperties": false
      },
      "FieldEvidence": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string"
          },
          "value": {
            "type": "string"
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "sourceRefs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceReference"
            }
          },
          "correctedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "field",
          "value",
          "sourceRefs"
        ],
        "additionalProperties": false
      },
      "ReviewTransactionDraft": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "postingDate": {
            "type": "string"
          },
          "valueDate": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "rawAmount": {
            "type": "string"
          },
          "sourceRefs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceReference"
            }
          }
        },
        "required": [
          "id",
          "sourceRefs"
        ],
        "additionalProperties": false
      },
      "ReviewTransactionChange": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{1,160}$"
              },
              "action": {
                "type": "string",
                "enum": [
                  "include",
                  "exclude"
                ]
              }
            },
            "required": [
              "id",
              "action"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{1,160}$"
              },
              "action": {
                "const": "add"
              },
              "transaction": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{1,160}$"
                  },
                  "postingDate": {
                    "type": "string"
                  },
                  "valueDate": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "object",
                    "properties": {
                      "coefficient": {
                        "type": "string",
                        "pattern": "^(?:0|-?[1-9]\\d*)$",
                        "maxLength": 80
                      },
                      "scale": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      }
                    },
                    "required": [
                      "coefficient",
                      "scale",
                      "currency"
                    ],
                    "additionalProperties": false
                  },
                  "rawAmount": {
                    "type": "string"
                  },
                  "sourceRefs": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/SourceReference"
                    }
                  }
                },
                "required": [
                  "id",
                  "sourceRefs"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "id",
              "action",
              "transaction"
            ],
            "additionalProperties": false
          }
        ]
      },
      "ReviewTransactionOverride": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{1,160}$"
              },
              "action": {
                "type": "string",
                "enum": [
                  "include",
                  "exclude"
                ]
              }
            },
            "required": [
              "id",
              "action"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{1,160}$"
              },
              "action": {
                "const": "add"
              },
              "transaction": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{1,160}$"
                  },
                  "postingDate": {
                    "type": "string"
                  },
                  "valueDate": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "object",
                    "properties": {
                      "coefficient": {
                        "type": "string",
                        "pattern": "^(?:0|-?[1-9]\\d*)$",
                        "maxLength": 80
                      },
                      "scale": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      }
                    },
                    "required": [
                      "coefficient",
                      "scale",
                      "currency"
                    ],
                    "additionalProperties": false
                  },
                  "rawAmount": {
                    "type": "string"
                  },
                  "sourceRefs": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/SourceReference"
                    }
                  }
                },
                "required": [
                  "id",
                  "sourceRefs"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "id",
              "action",
              "transaction"
            ],
            "additionalProperties": false
          }
        ]
      },
      "ReviewSummary": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "unreviewed",
              "needs_review",
              "checks_passed",
              "user_reviewed"
            ]
          },
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReviewIssue"
            }
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldEvidence"
            }
          },
          "transactionOverrides": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^[A-Za-z0-9_-]{1,160}$"
                    },
                    "action": {
                      "type": "string",
                      "enum": [
                        "include",
                        "exclude"
                      ]
                    }
                  },
                  "required": [
                    "id",
                    "action"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^[A-Za-z0-9_-]{1,160}$"
                    },
                    "action": {
                      "const": "add"
                    },
                    "transaction": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9_-]{1,160}$"
                        },
                        "postingDate": {
                          "type": "string"
                        },
                        "valueDate": {
                          "type": "string"
                        },
                        "description": {
                          "type": "string"
                        },
                        "amount": {
                          "type": "object",
                          "properties": {
                            "coefficient": {
                              "type": "string",
                              "pattern": "^(?:0|-?[1-9]\\d*)$",
                              "maxLength": 80
                            },
                            "scale": {
                              "type": "integer",
                              "minimum": 0,
                              "maximum": 9
                            },
                            "currency": {
                              "type": "string",
                              "pattern": "^[A-Z]{3}$"
                            }
                          },
                          "required": [
                            "coefficient",
                            "scale",
                            "currency"
                          ],
                          "additionalProperties": false
                        },
                        "rawAmount": {
                          "type": "string"
                        },
                        "sourceRefs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SourceReference"
                          }
                        }
                      },
                      "required": [
                        "id",
                        "sourceRefs"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "id",
                    "action",
                    "transaction"
                  ],
                  "additionalProperties": false
                }
              ]
            }
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "status",
          "issues",
          "fields",
          "revision"
        ],
        "additionalProperties": false
      },
      "JobRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "workspaceId": {
            "type": "string",
            "pattern": "^ws_[A-Za-z0-9]+$"
          },
          "documentId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "type": {
            "type": "string",
            "enum": [
              "extraction",
              "export",
              "cleanup"
            ]
          },
          "processingStatus": {
            "$ref": "#/components/schemas/DocumentProcessingStatus"
          },
          "reviewStatus": {
            "$ref": "#/components/schemas/DocumentReviewStatus"
          },
          "progress": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          },
          "issues": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "$ref": "#/components/schemas/ReviewIssue"
                }
              ]
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "workspaceId",
          "type",
          "processingStatus",
          "reviewStatus",
          "progress",
          "revision",
          "issues",
          "createdAt",
          "updatedAt"
        ],
        "additionalProperties": false
      },
      "UploadPart": {
        "type": "object",
        "properties": {
          "partNumber": {
            "type": "integer",
            "minimum": 1
          },
          "byteLength": {
            "type": "integer",
            "minimum": 1,
            "maximum": 8388608
          },
          "sha256": {
            "type": "string",
            "pattern": "^[a-fA-F0-9]{64}$"
          },
          "etag": {
            "type": "string"
          }
        },
        "required": [
          "partNumber",
          "byteLength",
          "sha256",
          "etag"
        ],
        "additionalProperties": false
      },
      "UploadIntent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "workspaceId": {
            "type": "string",
            "pattern": "^ws_[A-Za-z0-9]+$"
          },
          "batchId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9._:-]{8,128}$",
            "minLength": 8,
            "maxLength": 128
          },
          "sourceKind": {
            "type": "string",
            "enum": [
              "pdf",
              "image"
            ]
          },
          "expectedMediaType": {
            "type": "string",
            "enum": [
              "application/pdf",
              "image/png",
              "image/jpeg",
              "image/webp",
              "image/heic",
              "image/heif"
            ]
          },
          "expectedByteLength": {
            "type": "integer",
            "minimum": 1,
            "maximum": 52428800
          },
          "expectedSha256": {
            "type": "string",
            "pattern": "^[a-fA-F0-9]{64}$"
          },
          "storageKey": {
            "type": "string"
          },
          "partSize": {
            "type": "integer",
            "const": 8388608
          },
          "partCount": {
            "type": "integer",
            "minimum": 1
          },
          "uploadedByteLength": {
            "type": "integer",
            "minimum": 0,
            "maximum": 52428800
          },
          "parts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UploadPart"
            }
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": [
              "created",
              "uploading",
              "completed",
              "finalized",
              "expired",
              "aborted"
            ]
          }
        },
        "required": [
          "id",
          "workspaceId",
          "batchId",
          "sourceKind",
          "expectedMediaType",
          "expectedByteLength",
          "expectedSha256",
          "storageKey",
          "partSize",
          "partCount",
          "uploadedByteLength",
          "parts",
          "expiresAt",
          "status"
        ],
        "additionalProperties": false
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^ep_[A-Za-z0-9_-]{8,80}$"
          },
          "workspaceId": {
            "type": "string",
            "pattern": "^ws_[A-Za-z0-9]+$"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "workspaceId",
          "status",
          "createdAt"
        ],
        "additionalProperties": false
      },
      "QuotaPeriodSummary": {
        "type": "object",
        "properties": {
          "periodKey": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "free_lifetime",
              "billing_period"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "free",
              "paddle",
              "revenuecat"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "free",
              "active",
              "trialing"
            ]
          },
          "plan": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "const": null
              }
            ]
          },
          "subscriptionId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "const": null
              }
            ]
          },
          "periodStartedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "const": null
              }
            ]
          },
          "periodEndsAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "const": null
              }
            ]
          },
          "limitUnits": {
            "type": "integer",
            "minimum": 1
          },
          "verifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "reservedUnits": {
            "type": "integer",
            "minimum": 0
          },
          "settledUnits": {
            "type": "integer",
            "minimum": 0
          },
          "availableUnits": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "periodKey",
          "kind",
          "source",
          "status",
          "plan",
          "subscriptionId",
          "periodStartedAt",
          "periodEndsAt",
          "limitUnits",
          "verifiedAt",
          "reservedUnits",
          "settledUnits",
          "availableUnits"
        ],
        "additionalProperties": false
      },
      "DocumentDetailResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "document": {
            "$ref": "#/components/schemas/DocumentRecord"
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentSourceRecord"
            }
          },
          "run": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ExtractionRunRecord"
              },
              {
                "const": null
              }
            ]
          },
          "pages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentPageRecord"
            }
          }
        },
        "required": [
          "ok",
          "document",
          "sources",
          "run",
          "pages"
        ],
        "additionalProperties": false
      },
      "DocumentListResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentRecord"
            }
          },
          "nextCursor": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "documents"
        ],
        "additionalProperties": false
      },
      "DocumentLifecycleResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "document": {
            "$ref": "#/components/schemas/DocumentRecord"
          },
          "cleanupRequired": {
            "type": "boolean"
          }
        },
        "required": [
          "ok",
          "document"
        ],
        "additionalProperties": false
      },
      "ReviewApiResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "review": {
            "$ref": "#/components/schemas/ReviewSummary"
          },
          "document": {
            "$ref": "#/components/schemas/DocumentRecord"
          }
        },
        "required": [
          "ok",
          "review"
        ],
        "additionalProperties": false
      },
      "ReviewCompleteResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "document": {
            "type": "object",
            "additionalProperties": true
          },
          "webhookEvents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "eventId": {
                  "type": "string"
                },
                "endpointId": {
                  "type": "string"
                },
                "revision": {
                  "type": "integer"
                }
              },
              "required": [
                "eventId",
                "endpointId",
                "revision"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "ok",
          "document"
        ],
        "additionalProperties": true
      },
      "JobResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "job": {
            "$ref": "#/components/schemas/JobRecord"
          }
        },
        "required": [
          "ok",
          "job"
        ],
        "additionalProperties": false
      },
      "JobResultResponse": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "ok": {
                "const": true
              },
              "status": {
                "const": "waiting"
              },
              "job": {
                "$ref": "#/components/schemas/JobRecord"
              }
            },
            "required": [
              "ok",
              "status",
              "job"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "ok": {
                "const": true
              },
              "status": {
                "const": "failed"
              },
              "job": {
                "$ref": "#/components/schemas/JobRecord"
              }
            },
            "required": [
              "ok",
              "status",
              "job"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "ok": {
                "const": true
              },
              "status": {
                "const": "ready"
              },
              "job": {
                "$ref": "#/components/schemas/JobRecord"
              },
              "documentId": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{1,160}$"
              },
              "revision": {
                "type": "integer",
                "minimum": 0
              },
              "reviewStatus": {
                "$ref": "#/components/schemas/DocumentReviewStatus"
              },
              "exports": {
                "type": "object",
                "properties": {
                  "json": {
                    "type": "string",
                    "format": "uri-reference"
                  },
                  "csv": {
                    "type": "string",
                    "format": "uri-reference"
                  },
                  "xlsx": {
                    "type": "string",
                    "format": "uri-reference"
                  }
                },
                "required": [
                  "json",
                  "csv",
                  "xlsx"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "ok",
              "status",
              "job",
              "documentId",
              "revision",
              "reviewStatus",
              "exports"
            ],
            "additionalProperties": false
          }
        ]
      },
      "UploadIntentResponse": {
        "type": "object",
        "properties": {
          "upload": {
            "$ref": "#/components/schemas/UploadIntent"
          },
          "uploadUrl": {
            "type": "string",
            "format": "uri-reference"
          },
          "partsUrl": {
            "type": "string",
            "format": "uri-reference"
          },
          "completeUrl": {
            "type": "string",
            "format": "uri-reference"
          },
          "abortUrl": {
            "type": "string",
            "format": "uri-reference"
          },
          "replayed": {
            "type": "boolean"
          }
        },
        "required": [
          "upload",
          "uploadUrl",
          "partsUrl",
          "completeUrl",
          "abortUrl"
        ],
        "additionalProperties": false
      },
      "UploadStateResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "upload": {
            "$ref": "#/components/schemas/UploadIntent"
          }
        },
        "required": [
          "ok",
          "upload"
        ],
        "additionalProperties": false
      },
      "UploadPartResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "part": {
            "$ref": "#/components/schemas/UploadPart"
          },
          "replayed": {
            "type": "boolean"
          }
        },
        "required": [
          "ok",
          "part"
        ],
        "additionalProperties": false
      },
      "UploadCompleteResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "upload": {
            "$ref": "#/components/schemas/UploadIntent"
          },
          "replayed": {
            "type": "boolean"
          }
        },
        "required": [
          "ok",
          "upload"
        ],
        "additionalProperties": false
      },
      "UploadAbortResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "upload": {
            "$ref": "#/components/schemas/UploadIntent"
          },
          "aborted": {
            "type": "boolean"
          }
        },
        "required": [
          "ok",
          "upload",
          "aborted"
        ],
        "additionalProperties": false
      },
      "FinalizeUploadResponse": {
        "type": "object",
        "properties": {
          "upload": {
            "$ref": "#/components/schemas/UploadIntent"
          },
          "document": {
            "$ref": "#/components/schemas/DocumentRecord"
          },
          "job": {
            "$ref": "#/components/schemas/JobRecord"
          },
          "replayed": {
            "type": "boolean"
          }
        },
        "required": [
          "upload",
          "document",
          "job"
        ],
        "additionalProperties": false
      },
      "QuotaSummaryResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "policy": {
            "type": "object",
            "properties": {
              "period": {
                "type": "string",
                "enum": [
                  "workspace_lifetime",
                  "billing_period",
                  "combined"
                ]
              },
              "unit": {
                "const": "page"
              },
              "allocation": {
                "const": "single_period"
              },
              "defaultLimit": {
                "type": "integer",
                "minimum": 1
              },
              "freeLifetimeLimit": {
                "type": "integer",
                "minimum": 1
              }
            },
            "required": [
              "period",
              "unit",
              "allocation",
              "defaultLimit",
              "freeLifetimeLimit"
            ],
            "additionalProperties": false
          },
          "periods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QuotaPeriodSummary"
            }
          },
          "reservedUnits": {
            "type": "integer",
            "minimum": 0
          },
          "settledUnits": {
            "type": "integer",
            "minimum": 0
          },
          "totalAvailableUnits": {
            "type": "integer",
            "minimum": 0
          },
          "availableUnits": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "ok",
          "policy",
          "periods",
          "reservedUnits",
          "settledUnits",
          "totalAvailableUnits",
          "availableUnits"
        ],
        "additionalProperties": false
      },
      "WebhookEndpointListResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "endpoints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEndpoint"
            }
          }
        },
        "required": [
          "ok",
          "endpoints"
        ],
        "additionalProperties": false
      },
      "WebhookEndpointResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "endpoint": {
            "$ref": "#/components/schemas/WebhookEndpoint"
          }
        },
        "required": [
          "ok",
          "endpoint"
        ],
        "additionalProperties": false
      },
      "DocumentEvidenceResponse": {
        "type": "object",
        "properties": {
          "parser": {
            "type": "object",
            "properties": {
              "manifest": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "sha256": {
                    "type": "string",
                    "pattern": "^[a-fA-F0-9]{64}$"
                  },
                  "pageCount": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "parserVersion": {
                    "type": "string"
                  },
                  "contractVersion": {
                    "const": "parser-evidence-1"
                  }
                },
                "required": [
                  "id",
                  "sha256",
                  "pageCount",
                  "parserVersion",
                  "contractVersion"
                ],
                "additionalProperties": false
              },
              "pages": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EvidencePage"
                }
              }
            },
            "required": [
              "manifest",
              "pages"
            ],
            "additionalProperties": false
          },
          "extraction": {
            "type": "object",
            "properties": {
              "schemaVersion": {
                "const": "finance-extraction-1"
              },
              "processingStatus": {
                "const": "completed"
              },
              "documentId": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{1,160}$"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "bank_statement",
                  "invoice",
                  "receipt",
                  "mixed",
                  "unknown"
                ]
              },
              "profile": {
                "type": "string",
                "enum": [
                  "bank_statement",
                  "invoice",
                  "receipt",
                  "auto"
                ]
              },
              "accountType": {
                "type": "string",
                "enum": [
                  "bank",
                  "credit"
                ]
              },
              "transactions": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ExtractionTransaction"
                }
              },
              "documents": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ExtractionDocument"
                }
              },
              "checks": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ExtractionCheck"
                }
              },
              "review": {
                "$ref": "#/components/schemas/ReviewSummary"
              }
            },
            "required": [
              "schemaVersion",
              "processingStatus",
              "documentId",
              "kind",
              "profile",
              "accountType",
              "transactions",
              "documents",
              "checks",
              "review"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "parser",
          "extraction"
        ],
        "additionalProperties": false
      },
      "EvidencePageResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "documentId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "documentRevision": {
            "type": "integer",
            "minimum": 0
          },
          "jobId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "jobRevision": {
            "type": "integer",
            "minimum": 1
          },
          "manifest": {
            "type": "object",
            "properties": {
              "contractVersion": {
                "const": "parser-evidence-1"
              },
              "id": {
                "type": "string"
              },
              "sha256": {
                "type": "string",
                "pattern": "^[a-fA-F0-9]{64}$"
              },
              "bytes": {
                "type": "integer",
                "minimum": 1,
                "maximum": 8388608
              },
              "mediaType": {
                "type": "string",
                "enum": [
                  "application/pdf",
                  "image/png",
                  "image/jpeg",
                  "image/webp",
                  "image/heic",
                  "image/heif"
                ]
              },
              "sourceType": {
                "type": "string",
                "enum": [
                  "pdf",
                  "image"
                ]
              },
              "pageCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 500
              },
              "parserVersion": {
                "type": "string"
              },
              "rendererVersion": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "const": null
                  }
                ]
              },
              "ocrVersion": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "const": null
                  }
                ]
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "contractVersion",
              "id",
              "sha256",
              "bytes",
              "mediaType",
              "sourceType",
              "pageCount",
              "parserVersion",
              "rendererVersion",
              "ocrVersion",
              "warnings"
            ],
            "additionalProperties": false
          },
          "page": {
            "$ref": "#/components/schemas/ParserWindowEvidencePage"
          }
        },
        "required": [
          "ok",
          "documentId",
          "documentRevision",
          "jobId",
          "jobRevision",
          "manifest",
          "page"
        ],
        "additionalProperties": false
      },
      "EvidencePage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "index": {
            "type": "integer",
            "minimum": 0
          },
          "source": {
            "type": "string"
          },
          "dimensions": {
            "type": "object",
            "properties": {
              "width": {
                "type": "number"
              },
              "height": {
                "type": "number"
              },
              "unit": {
                "type": "string"
              },
              "rotation": {
                "type": "integer"
              },
              "cropBox": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              }
            },
            "required": [
              "width",
              "height",
              "unit",
              "rotation",
              "cropBox"
            ],
            "additionalProperties": false
          },
          "blocks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "order": {
                  "type": "integer"
                },
                "tokenIds": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "id",
                "order",
                "tokenIds"
              ],
              "additionalProperties": false
            }
          },
          "tokens": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "order": {
                  "type": "integer"
                },
                "box": {
                  "type": "object",
                  "properties": {
                    "x": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "y": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "width": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "height": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    }
                  },
                  "required": [
                    "x",
                    "y",
                    "width",
                    "height"
                  ],
                  "additionalProperties": false
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "native-text",
                    "ocr"
                  ]
                },
                "ocr": {
                  "type": "object",
                  "properties": {
                    "confidence": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 100
                    }
                  },
                  "required": [
                    "confidence"
                  ],
                  "additionalProperties": false
                }
              },
              "required": [
                "id",
                "text",
                "order",
                "box",
                "source"
              ],
              "additionalProperties": false
            }
          },
          "text": {
            "type": "string"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "index",
          "source",
          "dimensions",
          "blocks",
          "tokens",
          "text",
          "warnings"
        ],
        "additionalProperties": false
      },
      "ParserWindowEvidencePage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,160}$"
          },
          "index": {
            "type": "integer",
            "minimum": 0
          },
          "source": {
            "type": "string"
          },
          "dimensions": {
            "type": "object",
            "properties": {
              "width": {
                "type": "number"
              },
              "height": {
                "type": "number"
              },
              "unit": {
                "type": "string"
              },
              "rotation": {
                "type": "integer"
              },
              "cropBox": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              }
            },
            "required": [
              "width",
              "height",
              "unit",
              "rotation",
              "cropBox"
            ],
            "additionalProperties": false
          },
          "blocks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "order": {
                  "type": "integer"
                },
                "tokenIds": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "id",
                "order",
                "tokenIds"
              ],
              "additionalProperties": false
            }
          },
          "tokens": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "order": {
                  "type": "integer"
                },
                "box": {
                  "type": "object",
                  "properties": {
                    "x": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "y": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "width": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "height": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    }
                  },
                  "required": [
                    "x",
                    "y",
                    "width",
                    "height"
                  ],
                  "additionalProperties": false
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "native-text",
                    "ocr"
                  ]
                },
                "ocr": {
                  "type": "object",
                  "properties": {
                    "confidence": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 100
                    }
                  },
                  "required": [
                    "confidence"
                  ],
                  "additionalProperties": false
                }
              },
              "required": [
                "id",
                "text",
                "order",
                "box",
                "source"
              ],
              "additionalProperties": false
            }
          },
          "text": {
            "type": "string"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "coordinateSpace": {
            "type": "object",
            "properties": {
              "type": {
                "const": "normalized-visible-page"
              },
              "origin": {
                "const": "top-left"
              },
              "version": {
                "const": "parser-evidence-1"
              }
            },
            "required": [
              "type",
              "origin",
              "version"
            ],
            "additionalProperties": false
          },
          "artifact": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "kind": {
                "const": "immutable-source-page"
              },
              "mediaType": {
                "type": "string",
                "enum": [
                  "application/pdf",
                  "image/png",
                  "image/jpeg",
                  "image/webp",
                  "image/heic",
                  "image/heif"
                ]
              }
            },
            "required": [
              "id",
              "kind",
              "mediaType"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "index",
          "source",
          "dimensions",
          "blocks",
          "tokens",
          "text",
          "warnings",
          "coordinateSpace",
          "artifact"
        ],
        "additionalProperties": false
      },
      "ExtractionTransaction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "runId": {
            "type": "string"
          },
          "postingDate": {
            "type": "string"
          },
          "valueDate": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "runningBalance": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "sourceRefs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceReference"
            }
          },
          "currencyResolved": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "runId",
          "sourceRefs"
        ],
        "additionalProperties": false
      },
      "ExtractionDocument": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "invoice",
              "receipt"
            ]
          },
          "merchant": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string"
              },
              "value": {
                "type": "string"
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "sourceRefs": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SourceReference"
                }
              },
              "correctedAt": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "field",
              "value",
              "sourceRefs"
            ],
            "additionalProperties": false
          },
          "documentNumber": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string"
              },
              "value": {
                "type": "string"
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "sourceRefs": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SourceReference"
                }
              },
              "correctedAt": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "field",
              "value",
              "sourceRefs"
            ],
            "additionalProperties": false
          },
          "date": {
            "type": "object",
            "additionalProperties": true
          },
          "total": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "subtotal": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "tax": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "lineItems": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "sourceRefs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceReference"
            }
          }
        },
        "required": [
          "id",
          "kind",
          "lineItems",
          "sourceRefs"
        ],
        "additionalProperties": true
      },
      "ExtractionCheck": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": [
              "balance",
              "intermediate_balance",
              "subtotal_plus_tax",
              "line_items_total"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "passed",
              "failed",
              "not_available"
            ]
          },
          "expected": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "actual": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "openingBalance": {
            "type": "object",
            "properties": {
              "coefficient": {
                "type": "string",
                "pattern": "^(?:0|-?[1-9]\\d*)$",
                "maxLength": 80
              },
              "scale": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              }
            },
            "required": [
              "coefficient",
              "scale",
              "currency"
            ],
            "additionalProperties": false
          },
          "sourceRefs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceReference"
            }
          },
          "issue": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "code": {
                "type": "string",
                "enum": [
                  "ambiguous_date",
                  "ambiguous_currency",
                  "low_confidence",
                  "arithmetic_mismatch",
                  "missing_field",
                  "unsupported"
                ]
              },
              "severity": {
                "type": "string",
                "enum": [
                  "info",
                  "warning",
                  "error"
                ]
              },
              "message": {
                "type": "string"
              },
              "field": {
                "type": "string"
              },
              "sourceRefs": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SourceReference"
                }
              }
            },
            "required": [
              "id",
              "code",
              "severity",
              "message",
              "sourceRefs"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "code",
          "status",
          "sourceRefs"
        ],
        "additionalProperties": false
      }
    }
  }
}
