{
  "openapi": "3.0.3",
  "info": {
    "title": "DocFast API",
    "version": "1.0.0",
    "description": "Convert HTML, Markdown, and URLs to pixel-perfect PDFs. Built-in invoice & receipt templates.\n\n## Authentication\nAll conversion and template endpoints require an API key via `Authorization: Bearer <key>` or `X-API-Key: <key>` header.\n\n## Rate Limits\n- Free tier: 100 PDFs/month, 10 req/min\n- Pro tier: 10,000 PDFs/month, 30 req/min\n\n## Getting Started\n1. Sign up at [docfast.dev](https://docfast.dev) or via `POST /v1/signup/free`\n2. Verify your email with the 6-digit code\n3. Use your API key to convert documents",
    "contact": { "name": "DocFast", "url": "https://docfast.dev", "email": "support@docfast.dev" }
  },
  "servers": [{ "url": "https://docfast.dev", "description": "Production" }],
  "tags": [
    { "name": "Conversion", "description": "Convert HTML, Markdown, or URLs to PDF" },
    { "name": "Templates", "description": "Built-in document templates" },
    { "name": "Account", "description": "Signup, key recovery, and email management" },
    { "name": "Billing", "description": "Stripe-powered subscription management" },
    { "name": "System", "description": "Health checks and usage stats" }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": { "type": "http", "scheme": "bearer", "description": "API key as Bearer token" },
      "ApiKeyHeader": { "type": "apiKey", "in": "header", "name": "X-API-Key", "description": "API key via X-API-Key header" }
    },
    "schemas": {
      "PdfOptions": {
        "type": "object",
        "properties": {
          "format": { "type": "string", "enum": ["A4", "Letter", "Legal", "A3", "A5", "Tabloid"], "default": "A4", "description": "Page size" },
          "landscape": { "type": "boolean", "default": false, "description": "Landscape orientation" },
          "margin": {
            "type": "object",
            "properties": {
              "top": { "type": "string", "example": "20mm" },
              "bottom": { "type": "string", "example": "20mm" },
              "left": { "type": "string", "example": "15mm" },
              "right": { "type": "string", "example": "15mm" }
            }
          },
          "printBackground": { "type": "boolean", "default": true, "description": "Print background graphics" },
          "filename": { "type": "string", "default": "document.pdf", "description": "Suggested filename for the PDF" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "description": "Error message" }
        }
      }
    }
  },
  "paths": {
    "/v1/convert/html": {
      "post": {
        "tags": ["Conversion"],
        "summary": "Convert HTML to PDF",
        "description": "Renders HTML content as a PDF. Supports full CSS including flexbox, grid, and custom fonts. Bare HTML fragments are auto-wrapped.",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "type": "object",
                    "required": ["html"],
                    "properties": {
                      "html": { "type": "string", "description": "HTML content to convert", "example": "<h1>Hello World</h1><p>Your first PDF</p>" },
                      "css": { "type": "string", "description": "Optional CSS to inject (for HTML fragments)" }
                    }
                  },
                  { "$ref": "#/components/schemas/PdfOptions" }
                ]
              }
            }
          }
        },
        "responses": {
          "200": { "description": "PDF file", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
          "400": { "description": "Invalid request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "401": { "description": "Missing or invalid API key" },
          "415": { "description": "Unsupported Content-Type" },
          "429": { "description": "Rate limit exceeded or server busy" }
        }
      }
    },
    "/v1/convert/markdown": {
      "post": {
        "tags": ["Conversion"],
        "summary": "Convert Markdown to PDF",
        "description": "Converts Markdown content to a beautifully styled PDF with syntax highlighting.",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "type": "object",
                    "required": ["markdown"],
                    "properties": {
                      "markdown": { "type": "string", "description": "Markdown content to convert", "example": "# Hello World\n\nThis is **bold** and this is *italic*.\n\n- Item 1\n- Item 2" },
                      "css": { "type": "string", "description": "Optional custom CSS" }
                    }
                  },
                  { "$ref": "#/components/schemas/PdfOptions" }
                ]
              }
            }
          }
        },
        "responses": {
          "200": { "description": "PDF file", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
          "400": { "description": "Invalid request" },
          "401": { "description": "Missing or invalid API key" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    },
    "/v1/convert/url": {
      "post": {
        "tags": ["Conversion"],
        "summary": "Convert URL to PDF",
        "description": "Fetches a URL and converts the rendered page to PDF. Only http/https URLs are supported. Private/reserved IPs are blocked (SSRF protection).",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "type": "object",
                    "required": ["url"],
                    "properties": {
                      "url": { "type": "string", "format": "uri", "description": "URL to convert", "example": "https://example.com" },
                      "waitUntil": { "type": "string", "enum": ["load", "domcontentloaded", "networkidle0", "networkidle2"], "default": "networkidle0", "description": "When to consider navigation complete" }
                    }
                  },
                  { "$ref": "#/components/schemas/PdfOptions" }
                ]
              }
            }
          }
        },
        "responses": {
          "200": { "description": "PDF file", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
          "400": { "description": "Invalid URL or DNS failure" },
          "401": { "description": "Missing or invalid API key" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    },
    "/v1/templates": {
      "get": {
        "tags": ["Templates"],
        "summary": "List available templates",
        "description": "Returns all available document templates with their field definitions.",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "responses": {
          "200": {
            "description": "Template list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "templates": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string", "example": "invoice" },
                          "name": { "type": "string", "example": "Invoice" },
                          "description": { "type": "string" },
                          "fields": { "type": "array", "items": { "type": "string" } }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/templates/{id}/render": {
      "post": {
        "tags": ["Templates"],
        "summary": "Render a template to PDF",
        "description": "Renders a template with the provided data and returns a PDF.",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Template ID (e.g., 'invoice', 'receipt')" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": { "type": "object", "description": "Template data fields", "example": { "company": "Acme Corp", "items": [{ "description": "Widget", "quantity": 5, "price": 9.99 }] } }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "PDF file", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
          "404": { "description": "Template not found" }
        }
      }
    },
    "/v1/signup/free": {
      "post": {
        "tags": ["Account"],
        "summary": "Request a free API key",
        "description": "Sends a 6-digit verification code to your email. Use `/v1/signup/verify` to complete signup.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email", "example": "you@example.com" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification code sent",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "verification_required" }, "message": { "type": "string" } } } } }
          },
          "409": { "description": "Email already registered" },
          "429": { "description": "Too many signup attempts" }
        }
      }
    },
    "/v1/signup/verify": {
      "post": {
        "tags": ["Account"],
        "summary": "Verify email and get API key",
        "description": "Verify your email with the 6-digit code to receive your API key.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "code"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "code": { "type": "string", "example": "123456", "description": "6-digit verification code" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key issued",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "verified" }, "apiKey": { "type": "string", "example": "df_free_abc123..." }, "tier": { "type": "string", "example": "free" } } } } }
          },
          "400": { "description": "Invalid code" },
          "410": { "description": "Code expired" },
          "429": { "description": "Too many attempts" }
        }
      }
    },
    "/v1/recover": {
      "post": {
        "tags": ["Account"],
        "summary": "Request API key recovery",
        "description": "Sends a verification code to your registered email. Returns the same response whether or not the email exists (prevents enumeration).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Recovery code sent (if account exists)" },
          "429": { "description": "Too many recovery attempts" }
        }
      }
    },
    "/v1/recover/verify": {
      "post": {
        "tags": ["Account"],
        "summary": "Verify recovery code and get API key",
        "description": "Verify the recovery code to retrieve your API key. The key is shown only in the response — never sent via email.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "code"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "code": { "type": "string", "example": "123456" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key recovered",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "recovered" }, "apiKey": { "type": "string" }, "tier": { "type": "string" } } } } }
          },
          "400": { "description": "Invalid code" },
          "410": { "description": "Code expired" },
          "429": { "description": "Too many attempts" }
        }
      }
    },
    "/v1/email-change": {
      "post": {
        "tags": ["Account"],
        "summary": "Request email change",
        "description": "Change the email associated with your API key. Sends a verification code to the new email address.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["apiKey", "newEmail"],
                "properties": {
                  "apiKey": { "type": "string", "description": "Your current API key" },
                  "newEmail": { "type": "string", "format": "email", "description": "New email address" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Verification code sent to new email" },
          "400": { "description": "Invalid input" },
          "401": { "description": "Invalid API key" },
          "409": { "description": "Email already in use" },
          "429": { "description": "Too many attempts" }
        }
      }
    },
    "/v1/email-change/verify": {
      "post": {
        "tags": ["Account"],
        "summary": "Verify email change",
        "description": "Verify the code sent to your new email to complete the change.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["apiKey", "newEmail", "code"],
                "properties": {
                  "apiKey": { "type": "string" },
                  "newEmail": { "type": "string", "format": "email" },
                  "code": { "type": "string", "example": "123456" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Email updated", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "updated" }, "newEmail": { "type": "string" } } } } } },
          "400": { "description": "Invalid code" },
          "401": { "description": "Invalid API key" },
          "410": { "description": "Code expired" }
        }
      }
    },
    "/v1/billing/checkout": {
      "post": {
        "tags": ["Billing"],
        "summary": "Start Pro subscription checkout",
        "description": "Creates a Stripe Checkout session for the Pro plan ($9/mo). Returns a URL to redirect the user to.",
        "responses": {
          "200": { "description": "Checkout URL", "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "format": "uri" } } } } } },
          "500": { "description": "Checkout creation failed" }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "tags": ["System"],
        "summary": "Get usage statistics",
        "description": "Returns your API usage statistics for the current billing period.",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "responses": {
          "200": { "description": "Usage stats" }
        }
      }
    },
    "/health": {
      "get": {
        "tags": ["System"],
        "summary": "Health check",
        "description": "Returns service health status. No authentication required.",
        "responses": {
          "200": { "description": "Service is healthy" }
        }
      }
    }
  }
}
