{
  "openapi": "3.1.0",
  "info": {
    "title": "SnapAPI - Screenshot & Web Data API",
    "version": "2.0.0",
    "description": "Professional screenshot, PDF, video, scraping, content extraction, and AI analysis API. Convert any URL into structured data or visual captures with a single API call. Powered by headless Chromium.\n\n## Authentication\n\nAll API endpoints (except Auth and Health) require one of:\n- `X-Api-Key: sk_live_xxx` header (recommended for server-side)\n- `Authorization: Bearer sk_live_xxx` header\n- `?access_key=sk_live_xxx` query parameter (for GET endpoints)\n\nDashboard endpoints use JWT Bearer tokens obtained from `/auth/login`.\n\n## Rate Limits\n\n| Plan | Requests/month | Rate |\n|------|---------------|------|\n| Free | 100 | 10/min |\n| Starter | 5,000 | 60/min |\n| Pro | 50,000 | 300/min |\n\nRate limit headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`",
    "contact": {
      "email": "support@snapapi.pics",
      "url": "https://snapapi.pics"
    }
  },
  "servers": [
    {
      "url": "https://api.snapapi.pics",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your SnapAPI API key"
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT access token obtained from /auth/login or /auth/refresh"
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "schema": {
          "type": "integer"
        },
        "description": "Max requests per window"
      },
      "X-RateLimit-Remaining": {
        "schema": {
          "type": "integer"
        },
        "description": "Remaining requests"
      },
      "X-RateLimit-Reset": {
        "schema": {
          "type": "integer"
        },
        "description": "Window reset time (unix ms)"
      },
      "X-Request-Id": {
        "schema": {
          "type": "string"
        },
        "description": "Unique request identifier for debugging"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "integer"
          },
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ScreenshotRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://example.com"
          },
          "html": {
            "type": "string",
            "maxLength": 5000000,
            "description": "Raw HTML to render"
          },
          "markdown": {
            "type": "string",
            "maxLength": 1000000,
            "description": "Markdown to render"
          },
          "format": {
            "type": "string",
            "enum": [
              "png",
              "jpeg",
              "webp",
              "avif",
              "pdf"
            ],
            "default": "png"
          },
          "quality": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 80
          },
          "device": {
            "type": "string",
            "enum": [
              "desktop-1080p",
              "desktop-1440p",
              "desktop-4k",
              "macbook-pro-13",
              "macbook-pro-16",
              "imac-24",
              "iphone-12",
              "iphone-13",
              "iphone-14",
              "iphone-14-pro",
              "iphone-15",
              "iphone-15-pro",
              "iphone-15-pro-max",
              "iphone-se",
              "ipad",
              "ipad-mini",
              "ipad-air",
              "ipad-pro-11",
              "ipad-pro-12.9",
              "pixel-7",
              "pixel-8",
              "pixel-8-pro",
              "samsung-galaxy-s23",
              "samsung-galaxy-s24",
              "samsung-galaxy-tab-s9"
            ]
          },
          "width": {
            "type": "integer",
            "minimum": 100,
            "maximum": 3840,
            "default": 1280
          },
          "height": {
            "type": "integer",
            "minimum": 100,
            "maximum": 2160,
            "default": 800
          },
          "deviceScaleFactor": {
            "type": "number",
            "minimum": 1,
            "maximum": 3,
            "default": 1
          },
          "isMobile": {
            "type": "boolean",
            "default": false
          },
          "hasTouch": {
            "type": "boolean",
            "default": false
          },
          "isLandscape": {
            "type": "boolean",
            "default": false
          },
          "fullPage": {
            "type": "boolean",
            "default": false
          },
          "fullPageScrollDelay": {
            "type": "integer",
            "default": 400
          },
          "fullPageMaxHeight": {
            "type": "integer",
            "maximum": 50000
          },
          "selector": {
            "type": "string",
            "description": "CSS selector to capture specific element"
          },
          "clipX": {
            "type": "integer"
          },
          "clipY": {
            "type": "integer"
          },
          "clipWidth": {
            "type": "integer"
          },
          "clipHeight": {
            "type": "integer"
          },
          "delay": {
            "type": "integer",
            "minimum": 0,
            "maximum": 30000,
            "default": 0
          },
          "timeout": {
            "type": "integer",
            "minimum": 1000,
            "maximum": 60000,
            "default": 30000
          },
          "waitUntil": {
            "type": "string",
            "enum": [
              "load",
              "domcontentloaded",
              "networkidle"
            ],
            "default": "load"
          },
          "waitForSelector": {
            "type": "string"
          },
          "darkMode": {
            "type": "boolean",
            "default": false
          },
          "reducedMotion": {
            "type": "boolean",
            "default": false
          },
          "css": {
            "type": "string",
            "maxLength": 100000,
            "description": "Custom CSS (Starter+)"
          },
          "javascript": {
            "type": "string",
            "maxLength": 100000,
            "description": "Custom JS (Pro+)"
          },
          "hideSelectors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 50
          },
          "clickSelector": {
            "type": "string"
          },
          "clickDelay": {
            "type": "integer"
          },
          "blockAds": {
            "type": "boolean",
            "default": false,
            "description": "Block ads (Starter+)"
          },
          "blockTrackers": {
            "type": "boolean",
            "default": false,
            "description": "Block trackers (Pro+)"
          },
          "blockCookieBanners": {
            "type": "boolean",
            "default": false
          },
          "blockChatWidgets": {
            "type": "boolean",
            "default": false
          },
          "blockResources": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "document",
                "stylesheet",
                "image",
                "media",
                "font",
                "script",
                "xhr",
                "fetch",
                "websocket"
              ]
            }
          },
          "userAgent": {
            "type": "string"
          },
          "extraHeaders": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "cookies": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                },
                "domain": {
                  "type": "string"
                },
                "path": {
                  "type": "string"
                }
              }
            }
          },
          "httpAuth": {
            "type": "object",
            "properties": {
              "username": {
                "type": "string"
              },
              "password": {
                "type": "string"
              }
            }
          },
          "proxy": {
            "type": "object",
            "properties": {
              "server": {
                "type": "string",
                "format": "uri"
              },
              "username": {
                "type": "string"
              },
              "password": {
                "type": "string"
              }
            }
          },
          "geolocation": {
            "type": "object",
            "properties": {
              "latitude": {
                "type": "number"
              },
              "longitude": {
                "type": "number"
              },
              "accuracy": {
                "type": "number"
              }
            }
          },
          "timezone": {
            "type": "string",
            "example": "America/New_York"
          },
          "locale": {
            "type": "string",
            "example": "en-US"
          },
          "pdfOptions": {
            "type": "object",
            "properties": {
              "pageSize": {
                "type": "string",
                "enum": [
                  "a4",
                  "a3",
                  "a5",
                  "letter",
                  "legal",
                  "tabloid",
                  "custom"
                ]
              },
              "landscape": {
                "type": "boolean"
              },
              "printBackground": {
                "type": "boolean"
              },
              "scale": {
                "type": "number",
                "minimum": 0.1,
                "maximum": 2
              },
              "marginTop": {
                "type": "string"
              },
              "marginBottom": {
                "type": "string"
              },
              "marginLeft": {
                "type": "string"
              },
              "marginRight": {
                "type": "string"
              },
              "headerTemplate": {
                "type": "string"
              },
              "footerTemplate": {
                "type": "string"
              },
              "displayHeaderFooter": {
                "type": "boolean"
              },
              "pageRanges": {
                "type": "string"
              }
            }
          },
          "thumbnail": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "width": {
                "type": "integer"
              },
              "height": {
                "type": "integer"
              },
              "fit": {
                "type": "string",
                "enum": [
                  "cover",
                  "contain",
                  "fill"
                ]
              }
            }
          },
          "failOnHttpError": {
            "type": "boolean",
            "default": false
          },
          "failIfContentMissing": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "failIfContentContains": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "cache": {
            "type": "boolean",
            "default": false,
            "description": "Enable caching (Pro+)"
          },
          "cacheTtl": {
            "type": "integer",
            "minimum": 60,
            "maximum": 2592000,
            "default": 86400
          },
          "responseType": {
            "type": "string",
            "enum": [
              "binary",
              "base64",
              "json"
            ],
            "default": "binary"
          },
          "includeMetadata": {
            "type": "boolean",
            "default": false
          },
          "extractMetadata": {
            "type": "object",
            "properties": {
              "fonts": {
                "type": "boolean"
              },
              "colors": {
                "type": "boolean"
              },
              "links": {
                "type": "boolean"
              },
              "httpStatusCode": {
                "type": "boolean"
              }
            }
          },
          "storage": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "destination": {
                "type": "string",
                "enum": [
                  "snapapi",
                  "user_s3"
                ]
              }
            }
          },
          "async": {
            "type": "boolean",
            "default": false
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri"
          },
          "webhookHeaders": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "ScreenshotJsonResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "cached": {
            "type": "boolean"
          },
          "data": {
            "type": "string",
            "description": "Base64-encoded image data"
          },
          "format": {
            "type": "string",
            "example": "png"
          },
          "width": {
            "type": "integer",
            "example": 1280
          },
          "height": {
            "type": "integer",
            "example": 800
          },
          "fileSize": {
            "type": "integer"
          },
          "took": {
            "type": "integer",
            "description": "Response time in ms"
          },
          "metadata": {
            "type": "object"
          },
          "storage": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "url": {
                "type": "string"
              }
            }
          }
        }
      },
      "AsyncJobResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "async": {
            "type": "boolean"
          },
          "jobId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing",
              "completed",
              "failed"
            ]
          },
          "statusUrl": {
            "type": "string"
          }
        }
      },
      "BatchRequest": {
        "type": "object",
        "required": [
          "urls"
        ],
        "properties": {
          "urls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            },
            "minItems": 1,
            "maxItems": 100
          },
          "format": {
            "type": "string",
            "enum": [
              "png",
              "jpeg",
              "webp",
              "avif",
              "pdf"
            ],
            "default": "png"
          },
          "quality": {
            "type": "integer",
            "default": 80
          },
          "width": {
            "type": "integer",
            "default": 1280
          },
          "height": {
            "type": "integer",
            "default": 800
          },
          "fullPage": {
            "type": "boolean",
            "default": false
          },
          "darkMode": {
            "type": "boolean",
            "default": false
          },
          "blockAds": {
            "type": "boolean",
            "default": false
          },
          "blockCookieBanners": {
            "type": "boolean",
            "default": false
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "VideoRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "format": {
            "type": "string",
            "enum": [
              "webm",
              "mp4",
              "gif"
            ],
            "default": "webm"
          },
          "width": {
            "type": "integer",
            "minimum": 320,
            "maximum": 1920,
            "default": 1280
          },
          "height": {
            "type": "integer",
            "minimum": 240,
            "maximum": 1080,
            "default": 720
          },
          "duration": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "default": 5,
            "description": "Duration in seconds"
          },
          "fps": {
            "type": "integer",
            "minimum": 10,
            "maximum": 30,
            "default": 25
          },
          "scrolling": {
            "type": "boolean",
            "default": false
          },
          "scrollSpeed": {
            "type": "integer",
            "default": 100
          },
          "darkMode": {
            "type": "boolean",
            "default": false
          },
          "blockAds": {
            "type": "boolean",
            "default": false
          },
          "blockCookieBanners": {
            "type": "boolean",
            "default": false
          },
          "delay": {
            "type": "integer",
            "default": 0
          },
          "responseType": {
            "type": "string",
            "enum": [
              "binary",
              "base64",
              "json"
            ],
            "default": "binary"
          }
        }
      },
      "ExtractRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "type": {
            "type": "string",
            "enum": [
              "html",
              "text",
              "markdown",
              "article",
              "links",
              "images",
              "metadata",
              "structured"
            ],
            "default": "markdown"
          },
          "selector": {
            "type": "string",
            "description": "CSS selector to target"
          },
          "waitFor": {
            "type": "string",
            "description": "Wait for selector before extracting"
          },
          "timeout": {
            "type": "integer",
            "minimum": 1000,
            "maximum": 60000,
            "default": 30000
          },
          "darkMode": {
            "type": "boolean",
            "default": false
          },
          "blockAds": {
            "type": "boolean",
            "default": false
          },
          "blockCookieBanners": {
            "type": "boolean",
            "default": false
          },
          "includeImages": {
            "type": "boolean",
            "default": true
          },
          "maxLength": {
            "type": "integer",
            "minimum": 100,
            "maximum": 500000
          },
          "cleanOutput": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "ExtractResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "type": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "data": {
            "description": "Extracted content (format depends on type param)"
          },
          "responseTime": {
            "type": "integer"
          }
        }
      },
      "AnalyzeRequest": {
        "type": "object",
        "required": [
          "url",
          "prompt",
          "apiKey"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "prompt": {
            "type": "string",
            "minLength": 1,
            "maxLength": 5000,
            "description": "Analysis prompt for the LLM"
          },
          "provider": {
            "type": "string",
            "enum": [
              "openai",
              "anthropic"
            ],
            "default": "openai"
          },
          "apiKey": {
            "type": "string",
            "description": "Your own LLM provider API key (BYOK)"
          },
          "model": {
            "type": "string",
            "description": "Model override (e.g. gpt-4o, claude-sonnet-4-20250514)"
          },
          "jsonSchema": {
            "type": "object",
            "description": "JSON schema for structured LLM output"
          },
          "timeout": {
            "type": "integer",
            "default": 30000
          },
          "waitFor": {
            "type": "string"
          },
          "blockAds": {
            "type": "boolean",
            "default": true
          },
          "blockCookieBanners": {
            "type": "boolean",
            "default": true
          },
          "includeScreenshot": {
            "type": "boolean",
            "default": false
          },
          "includeMetadata": {
            "type": "boolean",
            "default": true
          },
          "maxContentLength": {
            "type": "integer",
            "default": 50000
          }
        }
      },
      "AnalyzeResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "url": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "description": {
                "type": "string"
              }
            }
          },
          "analysis": {
            "description": "LLM analysis (string or structured object)"
          },
          "provider": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "responseTime": {
            "type": "integer"
          }
        }
      },
      "UsageResponse": {
        "type": "object",
        "properties": {
          "used": {
            "type": "integer",
            "example": 150
          },
          "limit": {
            "type": "integer",
            "example": 1000
          },
          "remaining": {
            "type": "integer",
            "example": 850
          },
          "resetAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UserObject": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string"
          },
          "plan": {
            "type": "string",
            "enum": [
              "free",
              "starter",
              "pro"
            ]
          },
          "avatarUrl": {
            "type": "string",
            "nullable": true
          },
          "emailVerified": {
            "type": "boolean"
          },
          "isAdmin": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AuthResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "user": {
            "$ref": "#/components/schemas/UserObject"
          },
          "accessToken": {
            "type": "string",
            "description": "JWT access token (15 min expiry). Store in memory only."
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ScrapeRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "URL to scrape"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "html",
              "links",
              "markdown",
              "metadata"
            ],
            "default": "text",
            "description": "Output format"
          },
          "pages": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10,
            "default": 1,
            "description": "Number of paginated pages to scrape"
          },
          "waitMs": {
            "type": "integer",
            "minimum": 0,
            "maximum": 30000,
            "default": 0,
            "description": "Wait time in ms after page load"
          },
          "proxy": {
            "type": "string",
            "description": "Custom proxy URL (http://user:pass@host:port)"
          },
          "premiumProxy": {
            "type": "boolean",
            "description": "Use managed residential proxy pool"
          },
          "blockResources": {
            "type": "boolean",
            "default": false,
            "description": "Block images, media, and fonts"
          },
          "locale": {
            "type": "string",
            "maxLength": 20,
            "description": "Browser locale (e.g. en-US)"
          }
        }
      },
      "ScrapeResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "page": {
                  "type": "integer"
                },
                "url": {
                  "type": "string"
                },
                "data": {
                  "type": "string",
                  "description": "Scraped content (string or JSON string for links/metadata)"
                }
              }
            }
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "description": "Full key value (only returned on create/regenerate)",
            "example": "sk_live_abc123..."
          },
          "name": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "isActive": {
            "type": "boolean"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "screenshot",
                "pdf",
                "metadata",
                "batch"
              ]
            }
          }
        }
      },
      "StoredFile": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "storageType": {
            "type": "string",
            "enum": [
              "local",
              "user_s3"
            ]
          },
          "originalUrl": {
            "type": "string"
          },
          "format": {
            "type": "string"
          },
          "fileSize": {
            "type": "integer"
          },
          "width": {
            "type": "integer",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "nullable": true
          },
          "url": {
            "type": "string",
            "nullable": true,
            "description": "Signed URL to access the file"
          },
          "thumbnailUrl": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  },
  "paths": {
    "/v1/ping": {
      "get": {
        "operationId": "ping",
        "summary": "Ping",
        "description": "Simple health check. Returns OK status and timestamp.",
        "tags": [
          "Health"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    },
                    "timestamp": {
                      "type": "integer",
                      "example": 1708372800000
                    }
                  }
                },
                "example": {
                  "status": "ok",
                  "timestamp": 1708372800000
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Health Check",
        "tags": [
          "Health"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/health/detailed": {
      "get": {
        "operationId": "healthDetailed",
        "summary": "Detailed Health Check",
        "description": "Returns status of database, Redis, and job queue.",
        "tags": [
          "Health"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "All systems healthy"
          },
          "503": {
            "description": "One or more systems degraded"
          }
        }
      }
    },
    "/v1/screenshot": {
      "post": {
        "operationId": "takeScreenshot",
        "summary": "Take Screenshot",
        "description": "Capture a screenshot of any URL, HTML, or Markdown. Supports full-page, device emulation, dark mode, ad blocking, custom CSS/JS, caching, async processing, webhooks, and cloud storage.",
        "tags": [
          "Screenshot"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScreenshotRequest"
              },
              "examples": {
                "simple": {
                  "summary": "Basic screenshot",
                  "value": {
                    "url": "https://example.com",
                    "format": "png"
                  }
                },
                "fullPage": {
                  "summary": "Full page + dark mode",
                  "value": {
                    "url": "https://example.com",
                    "fullPage": true,
                    "darkMode": true,
                    "blockAds": true
                  }
                },
                "mobile": {
                  "summary": "iPhone 15 Pro",
                  "value": {
                    "url": "https://example.com",
                    "device": "iphone-15-pro"
                  }
                },
                "html": {
                  "summary": "Render HTML",
                  "value": {
                    "html": "<h1>Hello World</h1><p>Rendered by SnapAPI</p>",
                    "format": "png",
                    "width": 800,
                    "height": 600
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Screenshot captured successfully",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "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": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScreenshotJsonResponse"
                }
              }
            }
          },
          "202": {
            "description": "Async job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AsyncJobResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Feature not available on your plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or quota exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "takeScreenshotGet",
        "summary": "Take Screenshot (GET)",
        "description": "Simple GET endpoint for screenshots via query parameters.",
        "tags": [
          "Screenshot"
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "png",
                "jpeg",
                "webp",
                "avif",
                "pdf"
              ],
              "default": "png"
            }
          },
          {
            "name": "quality",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "width",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1280
            }
          },
          {
            "name": "height",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 800
            }
          },
          {
            "name": "full_page",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "dark_mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "block_ads",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "block_cookie_banners",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "cache",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "response_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "binary",
                "base64",
                "json"
              ],
              "default": "binary"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Screenshot captured"
          },
          "400": {
            "description": "Validation error"
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      }
    },
    "/v1/pdf": {
      "post": {
        "operationId": "generatePdf",
        "summary": "Generate PDF",
        "description": "Generate a PDF from any URL or HTML. Supports page sizes, margins, headers/footers, and scaling.",
        "tags": [
          "PDF"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScreenshotRequest"
              },
              "example": {
                "url": "https://example.com",
                "pdfOptions": {
                  "pageSize": "a4",
                  "landscape": false,
                  "printBackground": true
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PDF generated",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Validation error"
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      }
    },
    "/v1/screenshot/batch": {
      "post": {
        "operationId": "batchScreenshots",
        "summary": "Batch Screenshots",
        "description": "Submit up to 100 URLs for batch processing. Returns a job ID to poll for results.",
        "tags": [
          "Screenshot"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRequest"
              },
              "example": {
                "urls": [
                  "https://example.com",
                  "https://google.com"
                ],
                "format": "png",
                "width": 1280
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "jobId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Quota exceeded"
          }
        }
      }
    },
    "/v1/screenshot/batch/{jobId}": {
      "get": {
        "operationId": "getBatchStatus",
        "summary": "Get Batch Job Status",
        "tags": [
          "Screenshot"
        ],
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Batch job status with results"
          },
          "404": {
            "description": "Job not found or expired"
          }
        }
      }
    },
    "/v1/screenshot/async/{jobId}": {
      "get": {
        "operationId": "getAsyncStatus",
        "summary": "Get Async Screenshot Status",
        "tags": [
          "Screenshot"
        ],
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeData",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "description": "Include base64 data in response"
          }
        ],
        "responses": {
          "200": {
            "description": "Async job status"
          },
          "404": {
            "description": "Job not found or expired"
          }
        }
      }
    },
    "/v1/video": {
      "post": {
        "operationId": "recordVideo",
        "summary": "Record Video",
        "description": "Record a video of a webpage with optional scrolling. Supports WebM, MP4, and GIF output. Costs 5 credits per recording.",
        "tags": [
          "Video"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VideoRequest"
              },
              "examples": {
                "basic": {
                  "summary": "5-second recording",
                  "value": {
                    "url": "https://example.com",
                    "duration": 5,
                    "format": "mp4"
                  }
                },
                "scrolling": {
                  "summary": "Scrolling video",
                  "value": {
                    "url": "https://example.com",
                    "duration": 10,
                    "scrolling": true,
                    "scrollSpeed": 150,
                    "format": "webm"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Video recorded",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "video/webm": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/gif": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "string"
                    },
                    "format": {
                      "type": "string"
                    },
                    "width": {
                      "type": "integer"
                    },
                    "height": {
                      "type": "integer"
                    },
                    "duration": {
                      "type": "integer"
                    },
                    "fileSize": {
                      "type": "integer"
                    },
                    "took": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error"
          },
          "429": {
            "description": "Quota exceeded"
          },
          "503": {
            "description": "Server busy (max concurrent videos reached)"
          }
        }
      }
    },
    "/v1/extract": {
      "post": {
        "operationId": "extractContent",
        "summary": "Extract Web Content",
        "description": "Extract content from any webpage as HTML, text, markdown, article, links, images, metadata, or structured data. Optimized for LLM consumption.",
        "tags": [
          "Extract"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExtractRequest"
              },
              "examples": {
                "markdown": {
                  "summary": "Extract as markdown",
                  "value": {
                    "url": "https://example.com",
                    "type": "markdown"
                  }
                },
                "article": {
                  "summary": "Extract article (Readability)",
                  "value": {
                    "url": "https://blog.example.com/post",
                    "type": "article"
                  }
                },
                "structured": {
                  "summary": "Structured extraction",
                  "value": {
                    "url": "https://example.com",
                    "type": "structured",
                    "maxLength": 10000
                  }
                },
                "links": {
                  "summary": "Extract all links",
                  "value": {
                    "url": "https://example.com",
                    "type": "links"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Content extracted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error"
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      },
      "get": {
        "operationId": "extractContentGet",
        "summary": "Extract Web Content (GET)",
        "tags": [
          "Extract"
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "html",
                "text",
                "markdown",
                "article",
                "links",
                "images",
                "metadata",
                "structured"
              ],
              "default": "markdown"
            }
          },
          {
            "name": "selector",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "max_length",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "clean",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "true"
            }
          },
          {
            "name": "block_ads",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "block_cookies",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Content extracted"
          },
          "400": {
            "description": "Validation error"
          }
        }
      }
    },
    "/v1/analyze": {
      "post": {
        "operationId": "analyzeWebpage",
        "summary": "AI-Powered Web Analysis",
        "description": "Analyze any webpage using your own LLM API key (BYOK). Supports OpenAI and Anthropic. Optionally get structured JSON output via jsonSchema. Perfect for competitive intelligence, compliance audits, and data extraction.",
        "tags": [
          "Analyze"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnalyzeRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic analysis",
                  "value": {
                    "url": "https://example.com",
                    "prompt": "Summarize the main content",
                    "provider": "openai",
                    "apiKey": "sk-..."
                  }
                },
                "structured": {
                  "summary": "Structured output",
                  "value": {
                    "url": "https://example.com/pricing",
                    "prompt": "Extract all pricing plans",
                    "provider": "openai",
                    "apiKey": "sk-...",
                    "jsonSchema": {
                      "type": "object",
                      "properties": {
                        "plans": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "price": {
                                "type": "string"
                              },
                              "features": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "required": [
                        "plans"
                      ],
                      "additionalProperties": false
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Analysis complete",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyzeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error"
          },
          "401": {
            "description": "Invalid SnapAPI key"
          },
          "502": {
            "description": "LLM provider error"
          }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Get API Usage",
        "description": "Check your current API usage and remaining quota.",
        "tags": [
          "Usage"
        ],
        "responses": {
          "200": {
            "description": "Usage data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageResponse"
                },
                "example": {
                  "used": 150,
                  "limit": 1000,
                  "remaining": 850,
                  "resetAt": "2026-03-01T00:00:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      }
    },
    "/v1/devices": {
      "get": {
        "operationId": "listDevices",
        "summary": "List Device Presets",
        "description": "Get all available device presets (desktop, mobile, tablet) for screenshot emulation.",
        "tags": [
          "Utilities"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Device presets grouped by category"
          }
        }
      }
    },
    "/v1/capabilities": {
      "get": {
        "operationId": "getCapabilities",
        "summary": "API Capabilities",
        "description": "Get supported formats, features, and limits.",
        "tags": [
          "Utilities"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "API capabilities"
          }
        }
      }
    },
    "/v1/scrape": {
      "post": {
        "operationId": "scrapeWebpage",
        "summary": "Scrape Webpage",
        "description": "Scrape content from any URL. Returns text, HTML, markdown, links, or metadata. Supports pagination for multi-page crawls, custom proxies, and resource blocking.",
        "tags": [
          "Scrape"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScrapeRequest"
              },
              "examples": {
                "text": {
                  "summary": "Scrape as plain text",
                  "value": {
                    "url": "https://example.com",
                    "type": "text"
                  }
                },
                "markdown": {
                  "summary": "Scrape as markdown (LLM-ready)",
                  "value": {
                    "url": "https://example.com",
                    "type": "markdown"
                  }
                },
                "links": {
                  "summary": "Extract all links",
                  "value": {
                    "url": "https://example.com",
                    "type": "links"
                  }
                },
                "metadata": {
                  "summary": "Extract page metadata",
                  "value": {
                    "url": "https://example.com",
                    "type": "metadata"
                  }
                },
                "multipage": {
                  "summary": "3-page scrape",
                  "value": {
                    "url": "https://example.com/blog",
                    "type": "text",
                    "pages": 3,
                    "waitMs": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Content scraped successfully",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScrapeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error or invalid URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or quota exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Scrape failed (site unreachable or timeout)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "scrapeWebpageGet",
        "summary": "Scrape Webpage (GET)",
        "description": "Simple GET version of the scrape endpoint using query parameters.",
        "tags": [
          "Scrape"
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uri"
            },
            "description": "URL to scrape"
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "text",
                "html",
                "links"
              ],
              "default": "text"
            }
          },
          {
            "name": "pages",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "wait_ms",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "block_resources",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "locale",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Content scraped",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScrapeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error"
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      }
    },
    "/auth/register": {
      "post": {
        "operationId": "register",
        "summary": "Register",
        "description": "Create a new account with email and password. A verification email is sent automatically. Rate limited to 3 requests/minute per IP.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8,
                    "description": "Minimum 8 characters"
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Optional display name"
                  }
                }
              },
              "example": {
                "email": "user@example.com",
                "password": "securepass123",
                "name": "Jane Developer"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registration successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Email already registered or invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited (3/min per IP)"
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "operationId": "login",
        "summary": "Login",
        "description": "Authenticate with email and password. Returns a JWT access token and sets a HttpOnly refresh token cookie. Rate limited to 5 requests/minute per IP.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "email": "user@example.com",
                "password": "securepass123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Login successful. `refresh_token` set as HttpOnly cookie.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account disabled"
          },
          "429": {
            "description": "Rate limited (5/min per IP)"
          }
        }
      }
    },
    "/auth/google": {
      "post": {
        "operationId": "googleAuth",
        "summary": "Google OAuth",
        "description": "Sign in or register using a Google ID token obtained from Google Sign-In.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "credential"
                ],
                "properties": {
                  "credential": {
                    "type": "string",
                    "description": "Google ID token from Google Sign-In"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Authentication successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid Google token"
          },
          "501": {
            "description": "Google OAuth not configured"
          }
        }
      }
    },
    "/auth/github": {
      "post": {
        "operationId": "githubAuth",
        "summary": "GitHub OAuth",
        "description": "Sign in or register using a GitHub OAuth authorization code.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "GitHub OAuth authorization code"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Authentication successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or expired authorization code"
          },
          "501": {
            "description": "GitHub OAuth not configured"
          }
        }
      }
    },
    "/auth/apple": {
      "post": {
        "operationId": "appleAuth",
        "summary": "Apple Sign-In",
        "description": "Sign in or register using an Apple ID token.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "idToken"
                ],
                "properties": {
                  "idToken": {
                    "type": "string",
                    "description": "Apple ID token"
                  },
                  "user": {
                    "type": "object",
                    "description": "User info (only sent on first sign-in)",
                    "properties": {
                      "email": {
                        "type": "string",
                        "format": "email"
                      },
                      "name": {
                        "type": "object",
                        "properties": {
                          "firstName": {
                            "type": "string"
                          },
                          "lastName": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Authentication successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid Apple token"
          }
        }
      }
    },
    "/auth/refresh": {
      "post": {
        "operationId": "refreshToken",
        "summary": "Refresh Token",
        "description": "Exchange the `refresh_token` HttpOnly cookie for a new access token. Rotates the refresh token on each use.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "New access token issued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "No refresh token cookie or token expired/invalid"
          }
        }
      }
    },
    "/auth/logout": {
      "post": {
        "operationId": "logout",
        "summary": "Logout",
        "description": "Invalidate the current session and clear the refresh token cookie.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Logged out successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/me": {
      "get": {
        "operationId": "getCurrentUser",
        "summary": "Get Current User",
        "description": "Get the authenticated user's profile. Requires `Authorization: Bearer <token>` header.",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "User profile",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/UserObject"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing token"
          }
        }
      }
    },
    "/auth/forgot-password": {
      "post": {
        "operationId": "forgotPassword",
        "summary": "Forgot Password",
        "description": "Send a password reset email. Always returns success to prevent email enumeration. Rate limited to 3 requests/hour per IP.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "If account exists, reset email sent"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/auth/reset-password": {
      "post": {
        "operationId": "resetPassword",
        "summary": "Reset Password",
        "description": "Set a new password using a valid reset token (obtained from the password reset email).",
        "tags": [
          "Auth"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "password"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password reset successful"
          },
          "400": {
            "description": "Invalid or expired token"
          }
        }
      }
    },
    "/auth/verify-email": {
      "get": {
        "operationId": "verifyEmail",
        "summary": "Verify Email",
        "description": "Verify email address using the token sent by registration email. Redirects to the dashboard on success.",
        "tags": [
          "Auth"
        ],
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Email verification token"
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to dashboard with `?verified=true` or `?verified=false`"
          },
          "400": {
            "description": "Missing token"
          }
        }
      }
    },
    "/dashboard/overview": {
      "get": {
        "operationId": "getDashboardOverview",
        "summary": "Dashboard Overview",
        "description": "Returns user profile, quota usage, monthly stats, daily usage chart data, and active subscription.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Dashboard data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/UserObject"
                    },
                    "quota": {
                      "type": "object",
                      "properties": {
                        "used": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "remaining": {
                          "type": "integer"
                        },
                        "percentUsed": {
                          "type": "integer"
                        },
                        "resetsAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "stats": {
                      "type": "object",
                      "properties": {
                        "totalRequests": {
                          "type": "integer"
                        },
                        "successful": {
                          "type": "integer"
                        },
                        "failed": {
                          "type": "integer"
                        },
                        "avgResponseTime": {
                          "type": "integer",
                          "description": "ms"
                        },
                        "totalBytes": {
                          "type": "integer"
                        },
                        "apiKeysCount": {
                          "type": "integer"
                        }
                      }
                    },
                    "dailyUsage": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": {
                            "type": "string"
                          },
                          "count": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "subscription": {
                      "type": "object",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Email not verified"
          }
        }
      }
    },
    "/dashboard/api-keys": {
      "get": {
        "operationId": "listApiKeys",
        "summary": "List API Keys",
        "description": "Returns all API keys for the authenticated user including full key values.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "API keys list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiKey"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createApiKey",
        "summary": "Create API Key",
        "description": "Create a new API key. Maximum 10 keys per user. Full key value is only returned once on creation.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 100,
                    "default": "New Key"
                  },
                  "permissions": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "screenshot",
                        "pdf",
                        "metadata",
                        "batch"
                      ]
                    }
                  },
                  "expiresAt": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key created \u2014 save it now, won't be shown again"
          },
          "400": {
            "description": "Maximum 10 keys limit reached"
          }
        }
      }
    },
    "/dashboard/api-keys/{id}": {
      "patch": {
        "operationId": "updateApiKey",
        "summary": "Update API Key",
        "description": "Update an API key's name, active status, or permissions.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "isActive": {
                    "type": "boolean"
                  },
                  "permissions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          },
          "404": {
            "description": "Key not found"
          }
        }
      },
      "delete": {
        "operationId": "deleteApiKey",
        "summary": "Delete API Key",
        "description": "Delete an API key. Cannot delete the last remaining key.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "400": {
            "description": "Cannot delete last API key"
          },
          "404": {
            "description": "Key not found"
          }
        }
      }
    },
    "/dashboard/api-keys/{id}/regenerate": {
      "post": {
        "operationId": "regenerateApiKey",
        "summary": "Regenerate API Key",
        "description": "Generate a new key value for an existing key entry. Old key is immediately invalidated.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "New key value returned \u2014 save it now"
          },
          "404": {
            "description": "Key not found"
          }
        }
      }
    },
    "/dashboard/usage": {
      "get": {
        "operationId": "getUsageHistory",
        "summary": "Usage History",
        "description": "Paginated list of API calls with endpoint, options, response time, status code, and error details.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "apiKeyId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by specific API key"
          }
        ],
        "responses": {
          "200": {
            "description": "Usage records",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "records": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "limit": {
                          "type": "integer"
                        },
                        "offset": {
                          "type": "integer"
                        },
                        "hasMore": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/dashboard/billing": {
      "get": {
        "operationId": "getBilling",
        "summary": "Billing Info",
        "description": "Returns the current subscription and payment history.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Billing info",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "subscription": {
                      "type": "object",
                      "nullable": true
                    },
                    "payments": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/dashboard/plans": {
      "get": {
        "operationId": "getPlans",
        "summary": "Available Plans",
        "description": "Returns all available subscription plans with pricing, quotas, and features.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Plan list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "plans": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/dashboard/create-checkout": {
      "post": {
        "operationId": "createCheckout",
        "summary": "Create Checkout",
        "description": "Returns a Paddle price ID and customer email for the frontend to open a Paddle.js checkout overlay.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "planId",
                  "interval"
                ],
                "properties": {
                  "planId": {
                    "type": "string"
                  },
                  "interval": {
                    "type": "string",
                    "enum": [
                      "monthly",
                      "yearly"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Paddle checkout params"
          },
          "404": {
            "description": "Plan not found"
          }
        }
      }
    },
    "/dashboard/cancel-subscription": {
      "post": {
        "operationId": "cancelSubscription",
        "summary": "Cancel Subscription",
        "description": "Cancel the active subscription at period end. Access remains until current billing period expires.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Cancellation scheduled"
          },
          "400": {
            "description": "No active subscription"
          },
          "502": {
            "description": "Paddle API error"
          }
        }
      }
    },
    "/dashboard/profile": {
      "patch": {
        "operationId": "updateProfile",
        "summary": "Update Profile",
        "description": "Update the authenticated user's display name.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 100
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Profile updated"
          },
          "400": {
            "description": "No fields to update"
          }
        }
      }
    },
    "/dashboard/change-password": {
      "post": {
        "operationId": "changePassword",
        "summary": "Change Password",
        "description": "Change password for email/password accounts. Not available for OAuth-only accounts.",
        "tags": [
          "Dashboard"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "currentPassword",
                  "newPassword"
                ],
                "properties": {
                  "currentPassword": {
                    "type": "string"
                  },
                  "newPassword": {
                    "type": "string",
                    "minLength": 8
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password updated"
          },
          "400": {
            "description": "Current password incorrect or OAuth account"
          }
        }
      }
    },
    "/storage/overview": {
      "get": {
        "operationId": "getStorageOverview",
        "summary": "Storage Overview",
        "description": "Returns vault usage, S3 configuration status, and plan-based storage limits.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Storage overview",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "vault": {
                      "type": "object",
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "active": {
                          "type": "boolean"
                        },
                        "used": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    },
                    "userS3": {
                      "type": "object",
                      "properties": {
                        "configured": {
                          "type": "boolean"
                        },
                        "bucket": {
                          "type": "string",
                          "nullable": true
                        },
                        "region": {
                          "type": "string",
                          "nullable": true
                        }
                      }
                    },
                    "plan": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/storage/vault-preference": {
      "post": {
        "operationId": "setVaultPreference",
        "summary": "Set Vault Preference",
        "description": "Enable or disable SnapAPI cloud storage (Vault). Requires a paid plan.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "enabled"
                ],
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preference saved"
          },
          "403": {
            "description": "Premium Vault requires a paid plan"
          }
        }
      }
    },
    "/storage/files": {
      "get": {
        "operationId": "listStoredFiles",
        "summary": "List Stored Files",
        "description": "Paginated list of stored screenshots with signed download URLs.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "local",
                "user_s3"
              ]
            },
            "description": "Filter by storage type"
          }
        ],
        "responses": {
          "200": {
            "description": "Files list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "files": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/StoredFile"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "hasMore": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/storage/files/{id}": {
      "get": {
        "operationId": "getStoredFile",
        "summary": "Get Stored File",
        "description": "Serve a stored file directly (local storage) or redirect to a signed S3 URL. Supports JWT auth via `token` query parameter for use in `<img>` tags.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "thumb",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ]
            },
            "description": "Return thumbnail instead of full file"
          },
          {
            "name": "token",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "JWT token as alternative to Authorization header (for <img> tags)"
          }
        ],
        "responses": {
          "200": {
            "description": "File content"
          },
          "302": {
            "description": "Redirect to S3 signed URL"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "File not found"
          }
        }
      },
      "delete": {
        "operationId": "deleteStoredFile",
        "summary": "Delete Stored File",
        "description": "Permanently delete a stored file.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "File deleted"
          },
          "404": {
            "description": "File not found"
          }
        }
      }
    },
    "/storage/user-s3": {
      "get": {
        "operationId": "getUserS3Config",
        "summary": "Get S3 Configuration",
        "description": "Returns the user's custom S3 configuration (access key ID masked).",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "S3 config (access key masked)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "configured": {
                      "type": "boolean"
                    },
                    "bucket": {
                      "type": "string",
                      "nullable": true
                    },
                    "region": {
                      "type": "string",
                      "nullable": true
                    },
                    "accessKeyId": {
                      "type": "string",
                      "nullable": true,
                      "description": "Partially masked"
                    },
                    "endpoint": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "saveUserS3Config",
        "summary": "Save S3 Configuration",
        "description": "Save custom S3 credentials for storing screenshots in your own bucket.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "bucket",
                  "region",
                  "accessKeyId"
                ],
                "properties": {
                  "bucket": {
                    "type": "string"
                  },
                  "region": {
                    "type": "string"
                  },
                  "accessKeyId": {
                    "type": "string"
                  },
                  "secretAccessKey": {
                    "type": "string",
                    "description": "Required for new configs; optional to preserve existing value"
                  },
                  "endpoint": {
                    "type": "string",
                    "description": "Custom S3 endpoint for non-AWS providers (e.g., Cloudflare R2)"
                  }
                }
              },
              "examples": {
                "aws": {
                  "summary": "AWS S3",
                  "value": {
                    "bucket": "my-screenshots",
                    "region": "us-east-1",
                    "accessKeyId": "AKIA...",
                    "secretAccessKey": "..."
                  }
                },
                "r2": {
                  "summary": "Cloudflare R2",
                  "value": {
                    "bucket": "my-screenshots",
                    "region": "auto",
                    "accessKeyId": "...",
                    "secretAccessKey": "...",
                    "endpoint": "https://<accountid>.r2.cloudflarestorage.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "S3 settings saved"
          },
          "400": {
            "description": "Validation error"
          }
        }
      },
      "delete": {
        "operationId": "deleteUserS3Config",
        "summary": "Delete S3 Configuration",
        "description": "Remove the custom S3 configuration.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "S3 settings removed"
          }
        }
      }
    },
    "/storage/user-s3/test": {
      "post": {
        "operationId": "testUserS3Connection",
        "summary": "Test S3 Connection",
        "description": "Test connectivity to the configured S3 bucket by attempting a put/get/delete operation.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "bucket",
                  "region",
                  "accessKeyId"
                ],
                "properties": {
                  "bucket": {
                    "type": "string"
                  },
                  "region": {
                    "type": "string"
                  },
                  "accessKeyId": {
                    "type": "string"
                  },
                  "secretAccessKey": {
                    "type": "string"
                  },
                  "endpoint": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Connection test passed"
          },
          "400": {
            "description": "Connection test failed \u2014 check credentials and bucket name"
          }
        }
      }
    },
    "/webhooks/paddle": {
      "post": {
        "operationId": "paddleWebhook",
        "summary": "Paddle Webhook",
        "description": "Receives Paddle billing events (subscription created/updated/canceled, payment completed/failed). Validates the `Paddle-Signature` header using HMAC-SHA256. This endpoint is for Paddle servers only \u2014 not for direct API consumers.",
        "tags": [
          "Webhooks"
        ],
        "security": [],
        "parameters": [
          {
            "name": "Paddle-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "HMAC-SHA256 signature: `ts=<timestamp>;h1=<hash>`"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event_id": {
                    "type": "string"
                  },
                  "event_type": {
                    "type": "string",
                    "enum": [
                      "subscription.created",
                      "subscription.activated",
                      "subscription.updated",
                      "subscription.canceled",
                      "subscription.paused",
                      "subscription.resumed",
                      "subscription.past_due",
                      "transaction.completed",
                      "transaction.payment_failed"
                    ]
                  },
                  "occurred_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "notification_id": {
                    "type": "string"
                  },
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received"
          },
          "401": {
            "description": "Invalid signature"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Screenshot",
      "description": "Screenshot, PDF, and batch capture"
    },
    {
      "name": "PDF",
      "description": "PDF generation from URLs and HTML"
    },
    {
      "name": "Video",
      "description": "Video recording of webpages"
    },
    {
      "name": "Extract",
      "description": "Web content extraction (HTML, text, markdown, article, structured)"
    },
    {
      "name": "Analyze",
      "description": "AI-powered web analysis with your own LLM key (BYOK)"
    },
    {
      "name": "Usage",
      "description": "API usage and quota management"
    },
    {
      "name": "Health",
      "description": "Health check and monitoring"
    },
    {
      "name": "Utilities",
      "description": "Device presets and API capabilities"
    },
    {
      "name": "Auth",
      "description": "Authentication \u2014 register, login, OAuth, password reset, email verification"
    },
    {
      "name": "Dashboard",
      "description": "User dashboard \u2014 quota overview, API key management, billing, usage history"
    },
    {
      "name": "Storage",
      "description": "File storage \u2014 list, retrieve, delete stored files; configure custom S3"
    },
    {
      "name": "Scrape",
      "description": "Web scraping \u2014 extract text, HTML, links, markdown, or metadata from any URL"
    },
    {
      "name": "Webhooks",
      "description": "Paddle billing webhooks (server-to-server)"
    }
  ]
}
