{
  "openapi": "3.1.0",
  "info": {
    "title": "tsurette.com QR API",
    "version": "1.0.0",
    "description": "Anonymous, stateless generation of static QR code images. Request payloads and generated images are not stored."
  },
  "servers": [
    {
      "url": "https://tsurette.com"
    }
  ],
  "paths": {
    "/api/v1/qr": {
      "post": {
        "summary": "Generate a QR code",
        "operationId": "generateQrCode",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QrRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated QR code image",
            "headers": {
              "X-QR-Version": { "schema": { "type": "integer" } },
              "X-QR-Grid-Size": { "schema": { "type": "integer" } },
              "X-QR-Image-Size": { "schema": { "type": "integer" } },
              "X-QR-Error-Correction": { "schema": { "type": "string", "enum": ["L", "M", "Q", "H"] } }
            },
            "content": {
              "image/svg+xml": { "schema": { "type": "string", "format": "binary" } },
              "image/png": { "schema": { "type": "string", "format": "binary" } }
            }
          },
          "400": { "$ref": "#/components/responses/ClientError" },
          "413": { "$ref": "#/components/responses/ClientError" },
          "415": { "$ref": "#/components/responses/ClientError" },
          "422": { "$ref": "#/components/responses/ClientError" },
          "429": { "description": "Rate limit exceeded" },
          "500": { "$ref": "#/components/responses/ClientError" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "QrRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["data"],
        "properties": {
          "data": { "type": "string", "minLength": 1, "description": "Text to encode." },
          "format": { "type": "string", "enum": ["svg", "png"], "default": "svg" },
          "errorCorrection": { "type": "string", "enum": ["L", "M", "Q", "H"], "default": "L" },
          "size": { "type": "integer", "minimum": 128, "maximum": 2048, "default": 1024 },
          "style": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "foreground": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#17152b" },
              "background": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#ffffff" },
              "margin": { "type": "integer", "enum": [4, 6, 8, 12, 16], "default": 4 },
              "moduleShape": { "type": "string", "enum": ["square", "rounded", "dots"], "default": "square" },
              "finderStyle": { "type": "string", "enum": ["square", "rounded", "circle"], "default": "square" }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" }
            }
          }
        }
      }
    },
    "responses": {
      "ClientError": {
        "description": "The request could not be processed",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    }
  }
}
