{
  "openapi": "3.0.3",
  "info": {
    "title": "API Snap",
    "version": "1.0.0",
    "description": "API Snap is a developer utility API that bundles 13+ common tools into a single REST API with one API key. Generate QR codes, resize images, capture screenshots, convert HTML to PDF, hash strings, generate UUIDs, extract URL metadata, and more. Free tier includes 100 API calls/month with no credit card required. All endpoints support CORS and return JSON (or binary where appropriate). Built for developers who want to ship faster.",
    "contact": {
      "name": "API Snap Support",
      "url": "https://api-snap.com"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://api-snap.com",
      "description": "Production server"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key obtained from your API Snap dashboard. Pass as `Authorization: Bearer <key>` header or as `?api_key=<key>` query parameter."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message"
          }
        },
        "required": ["error"]
      },
      "RateLimitError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "Rate limit exceeded"
          },
          "usage": {
            "type": "integer",
            "description": "Number of API calls used this month"
          },
          "limit": {
            "type": "integer",
            "description": "Monthly call limit for your plan"
          },
          "upgrade_url": {
            "type": "string",
            "format": "uri",
            "description": "URL to upgrade your plan"
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "API key required. Pass via Authorization: Bearer <key> header or ?api_key= query param."
            }
          }
        }
      },
      "RateLimitExceeded": {
        "description": "Monthly API call limit reached",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RateLimitError"
            }
          }
        },
        "headers": {
          "X-RateLimit-Limit": {
            "schema": { "type": "integer" },
            "description": "Monthly call limit"
          },
          "X-RateLimit-Remaining": {
            "schema": { "type": "integer" },
            "description": "Remaining calls this month"
          }
        }
      }
    }
  },
  "paths": {
    "/api/qr": {
      "get": {
        "operationId": "generateQrCode",
        "summary": "Generate QR code",
        "description": "Generate a QR code image for any text or URL. Returns PNG or SVG.",
        "tags": ["Images"],
        "parameters": [
          {
            "name": "data",
            "in": "query",
            "description": "The text or URL to encode in the QR code. Also accepted as `url`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "https://example.com"
          },
          {
            "name": "size",
            "in": "query",
            "description": "Width/height of the QR code in pixels (max 1000).",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 300,
              "maximum": 1000,
              "minimum": 1
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "Output format.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["png", "svg"],
              "default": "png"
            }
          },
          {
            "name": "dark",
            "in": "query",
            "description": "Hex color for dark (foreground) modules.",
            "required": false,
            "schema": {
              "type": "string",
              "default": "#000000"
            },
            "example": "#000000"
          },
          {
            "name": "light",
            "in": "query",
            "description": "Hex color for light (background) modules.",
            "required": false,
            "schema": {
              "type": "string",
              "default": "#ffffff"
            },
            "example": "#ffffff"
          }
        ],
        "responses": {
          "200": {
            "description": "QR code image",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/resize": {
      "post": {
        "operationId": "resizeImage",
        "summary": "Resize and convert images",
        "description": "Resize and/or convert images to PNG, WebP, JPEG, or AVIF. Accepts multipart form data (with an `image` file field) or a JSON body with a base64-encoded image or image URL.",
        "tags": ["Images"],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary",
                    "description": "The image file to resize."
                  },
                  "width": {
                    "type": "integer",
                    "description": "Target width in pixels (max 4096).",
                    "maximum": 4096
                  },
                  "height": {
                    "type": "integer",
                    "description": "Target height in pixels (max 4096).",
                    "maximum": 4096
                  },
                  "format": {
                    "type": "string",
                    "enum": ["png", "jpeg", "jpg", "webp", "avif"],
                    "default": "png"
                  },
                  "quality": {
                    "type": "integer",
                    "description": "Output quality (1–100). Applies to JPEG, WebP, AVIF.",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 80
                  },
                  "fit": {
                    "type": "string",
                    "enum": ["cover", "contain", "fill", "inside", "outside"],
                    "default": "cover",
                    "description": "How to fit the image within the target dimensions."
                  }
                },
                "required": ["image"]
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "description": "Base64-encoded image data."
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL of the image to fetch and resize."
                  },
                  "width": {
                    "type": "integer",
                    "maximum": 4096
                  },
                  "height": {
                    "type": "integer",
                    "maximum": 4096
                  },
                  "format": {
                    "type": "string",
                    "enum": ["png", "jpeg", "jpg", "webp", "avif"],
                    "default": "png"
                  },
                  "quality": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 80
                  },
                  "fit": {
                    "type": "string",
                    "enum": ["cover", "contain", "fill", "inside", "outside"],
                    "default": "cover"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resized image binary",
            "content": {
              "image/png": { "schema": { "type": "string", "format": "binary" } },
              "image/jpeg": { "schema": { "type": "string", "format": "binary" } },
              "image/webp": { "schema": { "type": "string", "format": "binary" } },
              "image/avif": { "schema": { "type": "string", "format": "binary" } }
            }
          },
          "400": {
            "description": "Missing image input or invalid parameters",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/screenshot": {
      "get": {
        "operationId": "captureScreenshot",
        "summary": "Capture webpage screenshot",
        "description": "Capture a screenshot of any publicly accessible URL. Returns PNG or JPEG.",
        "tags": ["Browser"],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "description": "The URL of the webpage to screenshot.",
            "required": true,
            "schema": { "type": "string", "format": "uri" },
            "example": "https://example.com"
          },
          {
            "name": "width",
            "in": "query",
            "description": "Viewport width in pixels (max 1920).",
            "required": false,
            "schema": { "type": "integer", "default": 1280, "maximum": 1920, "minimum": 1 }
          },
          {
            "name": "height",
            "in": "query",
            "description": "Viewport height in pixels (max 1080).",
            "required": false,
            "schema": { "type": "integer", "default": 720, "maximum": 1080, "minimum": 1 }
          },
          {
            "name": "format",
            "in": "query",
            "description": "Image output format.",
            "required": false,
            "schema": { "type": "string", "enum": ["png", "jpeg"], "default": "png" }
          },
          {
            "name": "full_page",
            "in": "query",
            "description": "Capture the full scrollable page instead of only the viewport.",
            "required": false,
            "schema": { "type": "boolean", "default": false }
          }
        ],
        "responses": {
          "200": {
            "description": "Screenshot image",
            "content": {
              "image/png": { "schema": { "type": "string", "format": "binary" } },
              "image/jpeg": { "schema": { "type": "string", "format": "binary" } }
            }
          },
          "400": {
            "description": "Missing or invalid URL",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/pdf": {
      "post": {
        "operationId": "htmlToPdf",
        "summary": "Convert HTML to PDF",
        "description": "Convert an HTML string to a downloadable PDF file.",
        "tags": ["Documents"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["html"],
                "properties": {
                  "html": {
                    "type": "string",
                    "description": "HTML content to convert to PDF."
                  },
                  "title": {
                    "type": "string",
                    "description": "Document title, used as the PDF filename.",
                    "default": "Document"
                  }
                }
              },
              "example": {
                "html": "<h1>Hello World</h1><p>This is my PDF content.</p>",
                "title": "My Document"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PDF file",
            "content": {
              "application/pdf": {
                "schema": { "type": "string", "format": "binary" }
              }
            },
            "headers": {
              "Content-Disposition": {
                "schema": { "type": "string" },
                "description": "attachment; filename=\"<title>.pdf\""
              }
            }
          },
          "400": {
            "description": "Missing html field",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/hash": {
      "get": {
        "operationId": "hashStringGet",
        "summary": "Hash a string (GET)",
        "description": "Compute a cryptographic hash of a string using the specified algorithm.",
        "tags": ["Security"],
        "parameters": [
          {
            "name": "text",
            "in": "query",
            "description": "The string to hash.",
            "required": true,
            "schema": { "type": "string" },
            "example": "Hello World"
          },
          {
            "name": "algorithm",
            "in": "query",
            "description": "Hash algorithm to use.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["md5", "sha1", "sha256", "sha512", "sha384", "sha3-256", "sha3-512"],
              "default": "sha256"
            }
          },
          {
            "name": "encoding",
            "in": "query",
            "description": "Output encoding.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["hex", "base64", "base64url"],
              "default": "hex"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Hash result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hash": { "type": "string", "description": "The computed hash value." },
                    "algorithm": { "type": "string" },
                    "encoding": { "type": "string" }
                  }
                },
                "example": {
                  "hash": "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e",
                  "algorithm": "sha256",
                  "encoding": "hex"
                }
              }
            }
          },
          "400": {
            "description": "Missing text or invalid algorithm/encoding",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      },
      "post": {
        "operationId": "hashStringPost",
        "summary": "Hash a string (POST)",
        "description": "Compute a cryptographic hash of a string via JSON body. Useful for hashing large inputs.",
        "tags": ["Security"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["text"],
                "properties": {
                  "text": { "type": "string", "description": "The string to hash." },
                  "algorithm": {
                    "type": "string",
                    "enum": ["md5", "sha1", "sha256", "sha512", "sha384", "sha3-256", "sha3-512"],
                    "default": "sha256"
                  },
                  "encoding": {
                    "type": "string",
                    "enum": ["hex", "base64", "base64url"],
                    "default": "hex"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hash result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hash": { "type": "string" },
                    "algorithm": { "type": "string" },
                    "encoding": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing text or invalid algorithm",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/uuid": {
      "get": {
        "operationId": "generateId",
        "summary": "Generate UUIDs and unique IDs",
        "description": "Generate one or more unique identifiers in various formats: UUID v4, nanoid, hex token, base64, numeric, or timestamp-prefixed.",
        "tags": ["Utilities"],
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "description": "ID format to generate.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["uuid", "v4", "nanoid", "nanoid-short", "hex", "base64", "numeric", "timestamp"],
              "default": "uuid"
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "Number of IDs to generate (1–100).",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 1 }
          },
          {
            "name": "prefix",
            "in": "query",
            "description": "Optional string prefix to prepend to each generated ID.",
            "required": false,
            "schema": { "type": "string" },
            "example": "user_"
          }
        ],
        "responses": {
          "200": {
            "description": "Generated ID(s). Returns `id` (string) when count=1, or `ids` (array) when count>1.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "description": "Single generated ID." }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "ids": {
                          "type": "array",
                          "items": { "type": "string" },
                          "description": "Array of generated IDs."
                        }
                      }
                    }
                  ]
                },
                "examples": {
                  "single": { "value": { "id": "550e8400-e29b-41d4-a716-446655440000" } },
                  "multiple": { "value": { "ids": ["550e8400-e29b-41d4-a716-446655440000", "7b3d479c-12f1-4a3e-8c5b-123456789abc"] } }
                }
              }
            }
          },
          "400": {
            "description": "Invalid format parameter",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/meta": {
      "get": {
        "operationId": "extractUrlMetadata",
        "summary": "Extract URL metadata and Open Graph tags",
        "description": "Fetch a URL and extract its title, description, Open Graph image, favicon, and other metadata.",
        "tags": ["Utilities"],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "description": "The URL to extract metadata from.",
            "required": true,
            "schema": { "type": "string", "format": "uri" },
            "example": "https://example.com"
          }
        ],
        "responses": {
          "200": {
            "description": "Extracted metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": { "type": "string", "format": "uri" },
                    "title": { "type": "string", "nullable": true },
                    "description": { "type": "string", "nullable": true },
                    "image": { "type": "string", "format": "uri", "nullable": true },
                    "siteName": { "type": "string", "nullable": true },
                    "type": { "type": "string", "nullable": true },
                    "favicon": { "type": "string", "format": "uri", "nullable": true },
                    "themeColor": { "type": "string", "nullable": true },
                    "author": { "type": "string", "nullable": true },
                    "published": { "type": "string", "format": "date-time", "nullable": true }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid URL",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/base64": {
      "post": {
        "operationId": "base64EncodeDecode",
        "summary": "Base64 encode or decode",
        "description": "Encode a string to Base64 or decode a Base64 string back to plain text. Supports standard and URL-safe Base64.",
        "tags": ["Utilities"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "string",
                    "description": "The string to encode or the Base64 string to decode."
                  },
                  "action": {
                    "type": "string",
                    "enum": ["encode", "decode"],
                    "default": "encode",
                    "description": "Whether to encode or decode."
                  },
                  "urlSafe": {
                    "type": "boolean",
                    "default": false,
                    "description": "Use URL-safe Base64 alphabet (base64url) instead of standard Base64."
                  }
                }
              },
              "examples": {
                "encode": { "value": { "input": "Hello, World!", "action": "encode" } },
                "decode": { "value": { "input": "SGVsbG8sIFdvcmxkIQ==", "action": "decode" } }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Encoded or decoded result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "result": { "type": "string" },
                    "action": { "type": "string", "enum": ["encode", "decode"] }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing input or invalid base64 data",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/jwt-decode": {
      "post": {
        "operationId": "decodeJwt",
        "summary": "Decode a JWT token",
        "description": "Decode a JSON Web Token (JWT) and return its header, payload, and human-readable expiry information. Does not verify the signature.",
        "tags": ["Security"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["token"],
                "properties": {
                  "token": {
                    "type": "string",
                    "description": "The JWT string (header.payload.signature)."
                  }
                }
              },
              "example": {
                "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Decoded JWT",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "header": {
                      "type": "object",
                      "description": "Decoded JWT header.",
                      "additionalProperties": true
                    },
                    "payload": {
                      "type": "object",
                      "description": "Decoded JWT payload.",
                      "additionalProperties": true
                    },
                    "expired": {
                      "type": "boolean",
                      "description": "Whether the token has expired (only present if `exp` claim exists)."
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 expiry time (only present if `exp` claim exists)."
                    },
                    "issuedAt": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 issued-at time (only present if `iat` claim exists)."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing token or invalid JWT format",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/color": {
      "get": {
        "operationId": "convertColor",
        "summary": "Convert color formats",
        "description": "Convert a color between hex, RGB, HSL and get metadata like brightness and isDark. Accepts hex, rgb(), or hsl() input.",
        "tags": ["Utilities"],
        "parameters": [
          {
            "name": "color",
            "in": "query",
            "description": "Color value to convert. Accepts hex (e.g. `#ff0000` or `ff0000`), RGB (e.g. `rgb(255,0,0)`), or HSL (e.g. `hsl(0,100%,50%)`).",
            "required": true,
            "schema": { "type": "string" },
            "example": "#ff0000"
          }
        ],
        "responses": {
          "200": {
            "description": "Color in all supported formats",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hex": { "type": "string", "example": "#ff0000" },
                    "rgb": {
                      "type": "object",
                      "properties": {
                        "r": { "type": "integer" },
                        "g": { "type": "integer" },
                        "b": { "type": "integer" }
                      }
                    },
                    "rgbString": { "type": "string", "example": "rgb(255, 0, 0)" },
                    "hsl": {
                      "type": "object",
                      "properties": {
                        "h": { "type": "integer" },
                        "s": { "type": "integer" },
                        "l": { "type": "integer" }
                      }
                    },
                    "hslString": { "type": "string", "example": "hsl(0, 100%, 50%)" },
                    "rgba": { "type": "string", "example": "rgba(255, 0, 0, 1)" },
                    "brightness": { "type": "integer", "description": "Perceived brightness (0–255)." },
                    "isDark": { "type": "boolean", "description": "True if the color is perceived as dark." }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing color parameter or unsupported format",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/lorem": {
      "get": {
        "operationId": "generateLoremIpsum",
        "summary": "Generate lorem ipsum text",
        "description": "Generate placeholder lorem ipsum text as plain JSON or an HTML snippet.",
        "tags": ["Utilities"],
        "parameters": [
          {
            "name": "paragraphs",
            "in": "query",
            "description": "Number of paragraphs to generate (1–20).",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 20, "default": 3 }
          },
          {
            "name": "sentences",
            "in": "query",
            "description": "Number of sentences per paragraph (1–20).",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 20, "default": 5 }
          },
          {
            "name": "format",
            "in": "query",
            "description": "Output format. `text` returns JSON; `html` returns `<p>` tags as HTML.",
            "required": false,
            "schema": { "type": "string", "enum": ["text", "html"], "default": "text" }
          }
        ],
        "responses": {
          "200": {
            "description": "Generated lorem ipsum content",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "text": { "type": "string", "description": "All paragraphs joined by double newlines." },
                    "paragraphs": {
                      "type": "array",
                      "items": { "type": "string" },
                      "description": "Array of individual paragraph strings."
                    }
                  }
                }
              },
              "text/html": {
                "schema": { "type": "string" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/markdown": {
      "post": {
        "operationId": "markdownToHtml",
        "summary": "Convert Markdown to HTML",
        "description": "Convert a Markdown string to HTML. By default returns a fully styled HTML page; pass `styled: false` to get raw HTML fragment in a JSON response.",
        "tags": ["Documents"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["markdown"],
                "properties": {
                  "markdown": {
                    "type": "string",
                    "description": "Markdown content to convert."
                  },
                  "styled": {
                    "type": "boolean",
                    "default": true,
                    "description": "If true (default), returns a full HTML page with CSS styling. If false, returns a JSON object with the raw HTML fragment."
                  }
                }
              },
              "examples": {
                "styled": {
                  "value": { "markdown": "# Hello\n\nThis is **bold** text.", "styled": true }
                },
                "raw": {
                  "value": { "markdown": "# Hello\n\nThis is **bold** text.", "styled": false }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Converted HTML. Returns a full HTML page when `styled` is true, or a JSON object with `html` key when `styled` is false.",
            "content": {
              "text/html": {
                "schema": { "type": "string" }
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "html": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing markdown field",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    },
    "/api/placeholder": {
      "get": {
        "operationId": "generatePlaceholderImage",
        "summary": "Generate placeholder image",
        "description": "Generate an SVG placeholder image of any size with customizable background color, text color, and label.",
        "tags": ["Images"],
        "parameters": [
          {
            "name": "w",
            "in": "query",
            "description": "Image width in pixels (1–2000).",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 300 }
          },
          {
            "name": "h",
            "in": "query",
            "description": "Image height in pixels (1–2000).",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 200 }
          },
          {
            "name": "bg",
            "in": "query",
            "description": "Background color as a hex string without the `#` prefix.",
            "required": false,
            "schema": { "type": "string", "default": "cccccc" },
            "example": "cccccc"
          },
          {
            "name": "fg",
            "in": "query",
            "description": "Text/foreground color as a hex string without the `#` prefix.",
            "required": false,
            "schema": { "type": "string", "default": "666666" },
            "example": "666666"
          },
          {
            "name": "text",
            "in": "query",
            "description": "Label text to display on the image. Defaults to the dimensions (e.g. `300x200`).",
            "required": false,
            "schema": { "type": "string" },
            "example": "Hello"
          }
        ],
        "responses": {
          "200": {
            "description": "SVG placeholder image",
            "content": {
              "image/svg+xml": {
                "schema": { "type": "string" }
              }
            },
            "headers": {
              "Cache-Control": {
                "schema": { "type": "string" },
                "description": "public, max-age=31536000, immutable"
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimitExceeded" }
        }
      }
    }
  },
  "tags": [
    { "name": "Images", "description": "QR codes, image resizing, and placeholder image generation" },
    { "name": "Browser", "description": "Headless browser operations like screenshot capture" },
    { "name": "Documents", "description": "Document generation and conversion (PDF, Markdown)" },
    { "name": "Security", "description": "Cryptographic hashing and JWT decoding" },
    { "name": "Utilities", "description": "General-purpose developer utilities" }
  ]
}
