{
  "openapi": "3.1.0",
  "info": {
    "title": "DocToTable API",
    "version": "1.1.0",
    "summary": "Convert PDF tables to CSV/Excel data",
    "description": "DocToTable extracts tables from native and scanned PDFs using AI and returns them as CSV. Anonymous (unauthenticated) requests convert the first 3 pages of a document and are limited to 5 conversions per day per client. Authenticated requests (Firebase ID token as Bearer) convert full documents. Upload flow: PDFs are first uploaded via the web app (https://doctotable.com/en), which yields the storageId used by this API. See https://doctotable.com/llms.txt for an AI-assistant-oriented overview.",
    "contact": {
      "name": "DocToTable",
      "url": "https://doctotable.com/en/faq"
    }
  },
  "servers": [
    {
      "url": "https://doctotable.com",
      "description": "Production"
    }
  ],
  "components": {
    "securitySchemes": {
      "firebaseIdToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Firebase Authentication ID token. Optional: without it the request runs in the free tier (first 3 pages, 5 conversions/day). With a valid token the full document is converted."
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Free-tier conversions allowed per day.",
        "schema": { "type": "integer", "example": 5 }
      },
      "X-RateLimit-Remaining": {
        "description": "Free-tier conversions remaining today.",
        "schema": { "type": "integer", "example": 3 }
      },
      "X-RateLimit-Reset": {
        "description": "Unix epoch seconds when the free-tier quota resets (next UTC midnight).",
        "schema": { "type": "integer" }
      },
      "X-Access-Mode": {
        "description": "Whether the conversion ran in 'free' (first 3 pages) or 'full' mode.",
        "schema": { "type": "string", "enum": ["free", "full"] }
      },
      "X-Cache": {
        "description": "HIT when the result was served from the conversion cache.",
        "schema": { "type": "string", "enum": ["HIT", "MISS"] }
      },
      "X-Free-Page-Limit": {
        "description": "Number of pages converted in free mode.",
        "schema": { "type": "integer", "example": 3 }
      }
    }
  },
  "paths": {
    "/api/table": {
      "post": {
        "operationId": "convertPdfTable",
        "summary": "Convert a stored PDF into CSV table data.",
        "description": "Converts the PDF identified by storageId into CSV. Columns are auto-detected unless selectedClmns is provided. Free-tier responses include the first 3 pages plus a final 'Unlock full document' CTA row. Limits: PDFs up to 10 MB and 30 pages.",
        "security": [{}, { "firebaseIdToken": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "storageId": {
                    "type": "string",
                    "description": "Storage ID of a previously uploaded PDF (obtained via the DocToTable web upload flow)."
                  },
                  "selectedClmns": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Optional column names to extract. Omit for automatic column detection."
                  },
                  "pageCount": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Optional page count of the document, used for analytics."
                  }
                },
                "required": ["storageId"]
              },
              "example": {
                "storageId": "kg2abc123def456",
                "selectedClmns": ["Date", "Description", "Amount"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "CSV table data. The first line is the header row.",
            "headers": {
              "X-Access-Mode": { "$ref": "#/components/headers/X-Access-Mode" },
              "X-Cache": { "$ref": "#/components/headers/X-Cache" },
              "X-Free-Page-Limit": { "$ref": "#/components/headers/X-Free-Page-Limit" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "text/csv": {
                "schema": { "type": "string" },
                "example": "Date,Description,Amount\n2026-01-15,Office supplies,42.50\n2026-01-16,Software license,99.00\n"
              }
            }
          },
          "401": {
            "description": "The provided Firebase ID token is invalid or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "error": { "type": "string" } }
                },
                "example": { "error": "Invalid authentication token" }
              }
            }
          },
          "429": {
            "description": "Daily free conversion limit reached. Authenticate to convert full documents, or retry after the quota resets (see Retry-After / X-RateLimit-Reset).",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the free-tier quota resets.",
                "schema": { "type": "integer" }
              },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": { "type": "string" },
                    "cta": { "type": "string" }
                  }
                },
                "example": {
                  "error": "Daily free conversion limit reached",
                  "cta": "Unlock full document"
                }
              }
            }
          },
          "500": {
            "description": "Conversion failed (e.g. the PDF could not be processed).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "error": { "type": "string" } }
                },
                "example": { "error": "Failed to process PDF" }
              }
            }
          },
          "503": {
            "description": "Conversion backend is not configured."
          }
        }
      }
    }
  }
}
