{
  "openapi": "3.1.0",
  "info": {
    "title": "BankExcel OCR and Conversion API",
    "version": "1.1.0",
    "description": "Upload bank-statement files for OCR or convert transaction files into spreadsheet and accounting formats. Review recognized rows before import or posting."
  },
  "servers": [{"url": "https://bankexcelconverter.com"}],
  "paths": {
    "/api/ocr": {
      "post": {
        "operationId": "ocrStatementFile",
        "summary": "OCR a PDF or image statement",
        "description": "Upload one PDF, JPG, JPEG, or PNG file, up to 25 pages. Request body limit: 10 MiB. Uses remaining paid pages. Provider approval is required; unavailable paths return 503. Cloudflare Workers AI runs OCR; this is not the browser PDF.js/Tesseract pipeline.",
        "security": [{"bearerAuth": []}, {"apiKeyAuth": []}],
        "requestBody": {
          "required": true,
          "content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/OcrUpload"}}}
        },
        "responses": {
          "200": {"description": "Every selected page was processed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OcrResponse"}}}},
          "400": {"$ref": "#/components/responses/Error"},
          "401": {"$ref": "#/components/responses/Error"},
          "402": {"$ref": "#/components/responses/Error"},
          "405": {"$ref": "#/components/responses/Error"},
          "413": {"$ref": "#/components/responses/Error"},
          "415": {"$ref": "#/components/responses/Error"},
          "429": {"description": "Request rate, concurrency or processing budget exceeded."},
          "422": {"$ref": "#/components/responses/PageError"},
          "502": {"$ref": "#/components/responses/PageError"},
          "503": {"$ref": "#/components/responses/Error"}
        }
      }
    },
    "/api/convert": {
      "post": {
        "operationId": "convertFinancialFile",
        "summary": "Convert a statement or transaction file",
        "description": "PDF and image inputs use Workers AI OCR. Structured inputs are parsed without OCR. Remaining paid pages are required. Request body limit: 10 MiB. Each successful structured-file conversion uses one paid page.",
        "security": [{"bearerAuth": []}, {"apiKeyAuth": []}],
        "requestBody": {
          "required": true,
          "content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/ConvertUpload"}}}
        },
        "responses": {
          "200": {
            "description": "Generated file. X-Transaction-Count reports the number of rows written.",
            "headers": {
              "X-Transaction-Count": {"schema": {"type": "integer"}},
              "X-Processing-Mode": {"schema": {"type": "string", "enum": ["ocr", "deterministic"]}}
            },
            "content": {
              "application/octet-stream": {"schema": {"type": "string", "contentEncoding": "binary"}},
              "text/csv": {"schema": {"type": "string"}},
              "application/pdf": {"schema": {"type": "string", "contentEncoding": "binary"}},
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {"schema": {"type": "string", "contentEncoding": "binary"}}
            }
          },
          "400": {"$ref": "#/components/responses/Error"},
          "401": {"$ref": "#/components/responses/Error"},
          "402": {"$ref": "#/components/responses/Error"},
          "405": {"$ref": "#/components/responses/Error"},
          "413": {"$ref": "#/components/responses/Error"},
          "415": {"$ref": "#/components/responses/Error"},
          "429": {"description": "Request rate, concurrency or processing budget exceeded."},
          "422": {"$ref": "#/components/responses/Error"},
          "502": {"$ref": "#/components/responses/Error"},
          "503": {"$ref": "#/components/responses/Error"}
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "bec_ API key"},
      "apiKeyAuth": {"type": "apiKey", "in": "header", "name": "x-api-key"}
    },
    "schemas": {
      "OcrUpload": {
        "type": "object",
        "required": ["file"],
        "properties": {
          "file": {"type": "string", "contentEncoding": "binary", "description": "PDF, JPG, JPEG, or PNG."},
          "opening_balance": {"type": "string"},
          "closing_balance": {"type": "string"}
        }
      },
      "ConvertUpload": {
        "type": "object",
        "required": ["file", "input_format", "output_format"],
        "properties": {
          "file": {"type": "string", "contentEncoding": "binary"},
          "input_format": {"type": "string", "description": "Use JPG for JPG, JPEG, or PNG image files.", "enum": ["PDF", "JPG", "CSV", "XLSX", "OFX", "QFX", "QBO", "QIF", "IIF", "XML"]},
          "output_format": {"type": "string", "enum": ["CSV", "XLSX", "OFX", "QFX", "QBO", "QIF", "IIF", "XML", "TXT", "PDF"]}
        }
      },
      "Page": {
        "type": "object", "required": ["page", "text"],
        "properties": {"page": {"type": "integer", "minimum": 1}, "text": {"type": "string"}}
      },
      "Transaction": {
        "type": "object",
        "required": ["date", "description", "amount", "debit", "credit", "balance", "page", "rawText", "sourceBounds", "confidence", "validationFlags"],
        "properties": {
          "date": {"type": "string"}, "description": {"type": "string"}, "amount": {"type": "string"},
          "debit": {"type": "string"}, "credit": {"type": "string"}, "balance": {"type": "string"},
          "page": {"type": "integer", "minimum": 1}, "rawText": {"type": "string"},
          "sourceBounds": {"type": "null"}, "confidence": {"type": "null"},
          "validationFlags": {"type": "array", "items": {"type": "string"}}
        },
        "additionalProperties": true
      },
      "OcrResponse": {
        "type": "object",
        "required": ["pages", "requestedPages", "processedPages", "failedPages", "openingBalance", "closingBalance", "currency", "transactions"],
        "properties": {
          "pages": {"type": "array", "items": {"$ref": "#/components/schemas/Page"}},
          "requestedPages": {"type": "array", "items": {"type": "integer"}},
          "processedPages": {"type": "array", "items": {"type": "integer"}},
          "failedPages": {"type": "array", "maxItems": 0, "items": {"type": "integer"}},
          "openingBalance": {"type": ["string", "null"]}, "closingBalance": {"type": ["string", "null"]},
          "currency": {"type": "string"},
          "transactions": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/Transaction"}}
        }
      },
      "Error": {"type": "object", "required": ["error"], "properties": {"error": {"type": "string"}}},
      "PageError": {
        "allOf": [{"$ref": "#/components/schemas/Error"}, {"type": "object", "properties": {
          "requestedPages": {"type": "array", "items": {"type": "integer"}},
          "processedPages": {"type": "array", "items": {"type": "integer"}},
          "failedPages": {"type": "array", "items": {"type": "integer"}}
        }}]
      }
    },
    "responses": {
      "Error": {"description": "Request failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}},
      "PageError": {"description": "OCR processing failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PageError"}}}}
    }
  }
}
