{
  "openapi": "3.1.0",
  "info": {
    "title": "ImageToText API",
    "description": "Extract text from images or URLs using Tesseract OCR. Send a screenshot or a URL, get back all readable text. $0.01 per extraction.",
    "version": "1.0.0",
    "contact": {
      "name": "ImageToText API",
      "url": "https://imagetotextapi.com"
    }
  },
  "servers": [
    {
      "url": "https://api.imagetotextapi.com/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/extract": {
      "post": {
        "operationId": "extractText",
        "summary": "Extract text from an image",
        "description": "Upload an image file and get back all readable text. Supports JPEG, PNG, WebP, TIFF, BMP. Max 20MB. Costs 1 credit.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Image file to extract text from"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Text extracted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractResponse"
                }
              }
            }
          },
          "401": { "description": "Missing or invalid API key" },
          "402": { "description": "Insufficient credits" },
          "413": { "description": "Image exceeds 20MB limit" },
          "422": { "description": "Unsupported image format or corrupt file" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    },
    "/extract/url": {
      "post": {
        "operationId": "extractTextFromUrl",
        "summary": "Extract text from a URL",
        "description": "Send a URL. We render the page in a headless browser (1440x900 viewport), capture the above-the-fold screenshot, run OCR, and return all visible text. The screenshot is never stored. Costs 1 credit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url"],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL to render and extract text from. Must be http or https. Private/internal IPs are rejected."
                  },
                  "full_page": {
                    "type": "boolean",
                    "default": false,
                    "description": "If true, capture the entire scrollable page. If false (default), capture only the viewport (above the fold)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Text extracted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractResponse"
                }
              }
            }
          },
          "401": { "description": "Missing or invalid API key" },
          "402": { "description": "Insufficient credits" },
          "422": { "description": "Invalid URL, non-http scheme, or private/internal IP" },
          "429": { "description": "Rate limit exceeded" },
          "502": { "description": "Could not load URL (DNS failure, connection error)" },
          "503": { "description": "Browser service unavailable" },
          "504": { "description": "Page load timed out (30s limit)" }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Health check",
        "description": "Check API health and Tesseract availability. Free, no auth required.",
        "security": [],
        "responses": {
          "200": {
            "description": "Service status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/register": {
      "post": {
        "operationId": "register",
        "summary": "Create account",
        "description": "Register with email. Sends a 6-digit verification code.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Verification code sent" }
        }
      }
    },
    "/auth/verify": {
      "post": {
        "operationId": "verify",
        "summary": "Verify email",
        "description": "Verify email with the 6-digit code received via email.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "code"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "code": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Email verified" }
        }
      }
    },
    "/auth/api-key": {
      "post": {
        "operationId": "generateApiKey",
        "summary": "Generate API key",
        "description": "Generate or regenerate API key. First generation includes 5 free credits.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key generated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "api_key": { "type": "string" },
                    "credits": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/account": {
      "get": {
        "operationId": "getAccount",
        "summary": "View account",
        "description": "View balance, usage statistics, and recent queries.",
        "responses": {
          "200": { "description": "Account details" }
        }
      }
    },
    "/credits/packs": {
      "get": {
        "operationId": "listPacks",
        "summary": "List credit packs",
        "description": "List available credit packs and prices.",
        "security": [],
        "responses": {
          "200": { "description": "Available credit packs" }
        }
      }
    },
    "/credits/purchase": {
      "post": {
        "operationId": "purchaseCredits",
        "summary": "Buy credits",
        "description": "Purchase credits via Stripe Checkout. Returns checkout URL.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["pack_id"],
                "properties": {
                  "pack_id": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout URL",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "checkout_url": { "type": "string", "format": "uri" }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    },
    "schemas": {
      "ExtractResponse": {
        "type": "object",
        "required": ["text", "characters", "lines"],
        "properties": {
          "text": {
            "type": "string",
            "description": "All readable text extracted from the image"
          },
          "characters": {
            "type": "integer",
            "description": "Total character count"
          },
          "lines": {
            "type": "integer",
            "description": "Number of non-empty lines"
          }
        }
      },
      "HealthResponse": {
        "type": "object",
        "required": ["status", "tesseract_available"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["ok", "degraded"]
          },
          "tesseract_available": {
            "type": "boolean"
          }
        }
      }
    }
  }
}
