{
  "components": {
    "schemas": {
      "BatchFailure": {
        "description": "One failed batch item.",
        "properties": {
          "data": {
            "description": "Requested content.",
            "type": "string"
          },
          "error": {
            "description": "Why it failed.",
            "type": "string"
          },
          "item": {
            "description": "1-based position in the submitted list.",
            "type": "integer"
          },
          "type": {
            "description": "Requested symbology.",
            "type": "string"
          }
        },
        "required": [
          "item",
          "type",
          "data",
          "error"
        ],
        "type": "object"
      },
      "BatchFailureResponse": {
        "description": "Returned instead of a partial ZIP when any item fails.",
        "properties": {
          "error": {
            "description": "Summary line, e.g. \"2 of 5 items couldn't be generated.\"",
            "type": "string"
          },
          "failures": {
            "description": "Every failed item.",
            "items": {
              "$ref": "#/components/schemas/BatchFailure"
            },
            "type": "array"
          },
          "success": {
            "const": false,
            "type": "boolean"
          }
        },
        "required": [
          "success",
          "error",
          "failures"
        ],
        "type": "object"
      },
      "BatchItem": {
        "description": "One item in a batch. type and data are required; the rest are optional per-item overrides. CSV/XLSX columns use the same names (except logo/logo_scale, which are JSON-only).",
        "properties": {
          "bar_height": {
            "description": "Bar height in pixels (linear).",
            "type": "integer"
          },
          "bar_width": {
            "description": "Bar width in pixels (linear).",
            "type": "integer"
          },
          "bearer_bars": {
            "description": "ITF-14 bearer bars.",
            "type": "boolean"
          },
          "bg_color": {
            "description": "Background color (hex).",
            "type": "string"
          },
          "data": {
            "description": "Content to encode.",
            "type": "string"
          },
          "error_correction": {
            "description": "QR error-correction level.",
            "enum": [
              "L",
              "M",
              "Q",
              "H"
            ],
            "type": "string"
          },
          "fg_color": {
            "description": "Foreground color (hex).",
            "type": "string"
          },
          "filename": {
            "description": "Output file name inside the ZIP. Auto-derived when omitted.",
            "type": "string"
          },
          "format": {
            "description": "Output format for this item.",
            "enum": [
              "png",
              "svg",
              "pdf"
            ],
            "type": "string"
          },
          "logo": {
            "description": "Base64-encoded logo overlaid on the QR code (JSON input only).",
            "type": "string"
          },
          "logo_scale": {
            "description": "Logo size relative to the code (0–1). Default: 0.2.",
            "type": "number"
          },
          "show_text": {
            "description": "Text band under linear codes.",
            "type": "boolean"
          },
          "size": {
            "description": "Module size in pixels (2D codes).",
            "type": "string"
          },
          "type": {
            "description": "Barcode symbology (aliases accepted).",
            "enum": [
              "qr",
              "ean-13",
              "ean-8",
              "upc-a",
              "itf-14",
              "code-128",
              "code-39",
              "code-93",
              "codabar",
              "2of5",
              "datamatrix",
              "aztec",
              "pdf-417"
            ],
            "type": "string"
          }
        },
        "required": [
          "type",
          "data"
        ],
        "type": "object"
      },
      "DecodeJSONBody": {
        "description": "JSON form of a decode request.",
        "properties": {
          "format": {
            "description": "Symbology hint; auto-detects when omitted.",
            "enum": [
              "qr",
              "ean-13",
              "ean-8",
              "upc-a",
              "upc-e",
              "itf-14",
              "code-128",
              "code-39",
              "code-93",
              "codabar",
              "datamatrix",
              "aztec"
            ],
            "type": "string"
          },
          "image": {
            "description": "Base64-encoded image bytes; a data: URL prefix is tolerated.",
            "type": "string"
          }
        },
        "required": [
          "image"
        ],
        "type": "object"
      },
      "DecodeResult": {
        "description": "Successful decode.",
        "properties": {
          "format": {
            "description": "Recognized symbology (canonical name, e.g. \"ean-13\").",
            "type": "string"
          },
          "success": {
            "const": true,
            "type": "boolean"
          },
          "text": {
            "description": "Decoded content.",
            "type": "string"
          }
        },
        "required": [
          "success",
          "format",
          "text"
        ],
        "type": "object"
      },
      "Error": {
        "description": "The API's uniform error body (every non-2xx JSON response).",
        "properties": {
          "error": {
            "description": "Human-readable message; safe to show to a user.",
            "type": "string"
          },
          "success": {
            "const": false,
            "type": "boolean"
          }
        },
        "required": [
          "success",
          "error"
        ],
        "type": "object"
      },
      "GenerateRequest": {
        "description": "Parameters for one barcode. Mirrors the GET query parameters; only type and data are required.",
        "properties": {
          "bearer_bars": {
            "description": "ITF-14 bearer bars. Default: on for itf-14.",
            "type": "boolean"
          },
          "bg": {
            "description": "Background color, same forms as fg.",
            "type": "string"
          },
          "data": {
            "description": "Content to encode.",
            "type": "string"
          },
          "ec": {
            "description": "QR error-correction level. QR only.",
            "enum": [
              "L",
              "M",
              "Q",
              "H"
            ],
            "type": "string"
          },
          "fg": {
            "description": "Foreground color (#RGB/#RGBA/#RRGGBB/#RRGGBBAA).",
            "type": "string"
          },
          "format": {
            "description": "Output format. Default: png.",
            "enum": [
              "png",
              "svg",
              "pdf"
            ],
            "type": "string"
          },
          "height": {
            "description": "Bar height in pixels. Linear only.",
            "type": "integer"
          },
          "show_text": {
            "description": "Text band under linear codes. Default: on.",
            "type": "boolean"
          },
          "size": {
            "description": "Module size in pixels (positive integer, sent as a string). 2D codes only.",
            "pattern": "^[1-9][0-9]*$",
            "type": "string"
          },
          "type": {
            "description": "Barcode symbology (aliases accepted).",
            "enum": [
              "qr",
              "ean-13",
              "ean-8",
              "upc-a",
              "itf-14",
              "code-128",
              "code-39",
              "code-93",
              "codabar",
              "2of5",
              "datamatrix",
              "aztec",
              "pdf-417"
            ],
            "type": "string"
          },
          "width": {
            "description": "Bar width in pixels. Linear only.",
            "type": "integer"
          }
        },
        "required": [
          "type",
          "data"
        ],
        "type": "object"
      },
      "SpecResponse": {
        "description": "Capability list.",
        "properties": {
          "error_levels": {
            "items": {
              "description": "",
              "type": "string"
            },
            "type": "array"
          },
          "formats": {
            "items": {
              "description": "",
              "type": "string"
            },
            "type": "array"
          },
          "types": {
            "items": {
              "$ref": "#/components/schemas/TypeSpec"
            },
            "type": "array"
          }
        },
        "required": [
          "types",
          "formats",
          "error_levels"
        ],
        "type": "object"
      },
      "TypeSpec": {
        "description": "One symbology's spec entry.",
        "properties": {
          "hint": {
            "description": "Content rules in one line.",
            "type": "string"
          },
          "is_linear": {
            "description": "True for 1D symbologies.",
            "type": "boolean"
          },
          "label": {
            "description": "Human-readable name.",
            "type": "string"
          },
          "sample": {
            "description": "A known-valid sample value (the site URL for qr).",
            "type": "string"
          },
          "type": {
            "description": "Canonical symbology name.",
            "type": "string"
          }
        },
        "required": [
          "type",
          "label",
          "is_linear",
          "hint",
          "sample"
        ],
        "type": "object"
      },
      "ValidationResult": {
        "description": "Validation outcome; 200 regardless of validity.",
        "properties": {
          "check_digit": {
            "description": "The appended check digit, when auto-completed.",
            "type": "string"
          },
          "corrected": {
            "description": "Full code after check-digit auto-complete (GS1 types, N-1 digit input).",
            "type": "string"
          },
          "country_code": {
            "description": "Issuing country/region (ean-13 only).",
            "type": "string"
          },
          "data": {
            "description": "The data checked — the corrected full code when auto-complete applied.",
            "type": "string"
          },
          "message": {
            "description": "\"valid\", \"auto-completed check digit\", or why the data failed.",
            "type": "string"
          },
          "type": {
            "description": "Canonical symbology that was checked.",
            "type": "string"
          },
          "valid": {
            "description": "Whether the data satisfies the type's rules.",
            "type": "boolean"
          }
        },
        "required": [
          "valid",
          "type",
          "data"
        ],
        "type": "object"
      }
    }
  },
  "externalDocs": {
    "description": "Human-readable API reference",
    "url": "https://barcode.donaldmurillo.com/docs"
  },
  "info": {
    "description": "Free anonymous barcode \u0026 QR API: 13 symbologies, PNG/SVG/PDF output, GS1 validation with check-digit auto-complete, image decoding, and batch ZIPs from CSV/Excel/JSON. No key needed for the anonymous tier (per-IP rate limits apply). Registered API keys raise the limits and work on the same operations under /api/v1/generate, /api/v1/validate, and /api/v1/decode — send the key as X-API-Key or Authorization: Bearer. Versioning policy: keyed endpoints carry the version in the URL path (/v1/); a breaking change ships as /api/v2 with /api/v1 kept working through a deprecation window, and the anonymous /api surface only changes additively. Account, dashboard, and MCP surfaces are out of scope for this document. Human-readable reference: /docs.",
    "summary": "Generate, validate, decode, and batch barcodes and QR codes over HTTP.",
    "title": "Barcode Generator API",
    "version": "1.0.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/api/batch": {
      "post": {
        "description": "Accepts a JSON array, CSV, or Excel list of items (raw body or multipart \"file\" field), generates every item, and streams a ZIP of the codes. If ANY item fails, no ZIP is written: a 422 carries every failure (1-based item position, type, data, error) so the list can be fixed and re-run. Per-item overrides follow the same names as the single generate call.",
        "operationId": "generateBatchZip",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "items": {
                  "$ref": "#/components/schemas/BatchItem"
                },
                "maxItems": 10000,
                "type": "array"
              }
            },
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            },
            "multipart/form-data": {
              "schema": {
                "description": "Upload form.",
                "properties": {
                  "file": {
                    "description": "The batch file (JSON/CSV/XLSX).",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            },
            "text/csv": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            }
          },
          "description": "A batch of items to generate. Auto-detected: a JSON array, a CSV document, an .xlsx workbook, or a multipart form upload whose \"file\" field holds any of those. CSV/XLSX column names equal the JSON field names (type, data, filename, format, fg_color, bg_color, size, error_correction, bar_height, bar_width, show_text, bearer_bars). Max 10,000 items; max 64 MB body."
        },
        "responses": {
          "200": {
            "content": {
              "application/zip": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "All items generated — the ZIP of barcode files streams as attachment \"barcodes.zip\"."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unparseable input (bad JSON/CSV/XLSX, or a header row with no valid columns)."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Cross-origin browser request without an API key. Programmatic clients (curl, SDKs) and same-origin studio calls are unaffected."
          },
          "413": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "More than 10,000 items or a body over 64 MB."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchFailureResponse"
                }
              }
            },
            "description": "At least one item could not be generated; the ZIP is withheld."
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rate limit exceeded (per-IP anonymous budget, or per-key quota on /api/v1). Retry after the window in X-RateLimit-Reset. Defaults: 30/min and 300/day per IP."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Batch capacity is busy; retry shortly."
          }
        },
        "summary": "Batch-generate a ZIP of barcodes"
      }
    },
    "/api/decode": {
      "get": {
        "description": "Same decode as the POST, with the image passed URL-encoded in the query string — handy for quick tests, limited by URL length for real images.",
        "operationId": "decodeImageFromQuery",
        "parameters": [
          {
            "description": "Base64-encoded image bytes. A data: URL prefix is tolerated.",
            "in": "query",
            "name": "image",
            "required": true,
            "schema": {
              "description": "Base64-encoded image bytes. A data: URL prefix is tolerated.",
              "type": "string"
            }
          },
          {
            "description": "Symbology hint that narrows the reader (auto-detects when omitted).",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "description": "Symbology hint that narrows the reader (auto-detects when omitted).",
              "enum": [
                "qr",
                "ean-13",
                "ean-8",
                "upc-a",
                "upc-e",
                "itf-14",
                "code-128",
                "code-39",
                "code-93",
                "codabar",
                "datamatrix",
                "aztec"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecodeResult"
                }
              }
            },
            "description": "Decoded barcode."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "No image supplied or invalid base64."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Cross-origin browser request without an API key. Programmatic clients (curl, SDKs) and same-origin studio calls are unaffected."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "The image could not be read or no barcode was recognized."
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rate limit exceeded (per-IP anonymous budget, or per-key quota on /api/v1). Retry after the window in X-RateLimit-Reset. Defaults: 30/min and 300/day per IP."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Decode capacity is busy; retry shortly."
          }
        },
        "summary": "Read a barcode out of a base64 image"
      },
      "post": {
        "description": "Decodes an image and returns the recognized symbology and text. POST the raw image bytes (Content-Type image/png, image/jpeg, …), or a JSON body with a base64 image. Supported: qr, ean-13, ean-8, upc-a, upc-e, itf-14, code-128, code-39, code-93, codabar, datamatrix, and aztec. 2of5 and pdf-417 are encode-only.",
        "operationId": "decodeImage",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecodeJSONBody"
              }
            },
            "image/*": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            }
          },
          "description": "The image to read. Either the raw image bytes (Content-Type image/*) or a JSON object with a base64 image."
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecodeResult"
                }
              }
            },
            "description": "Decoded barcode."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "No image supplied, invalid base64, or a malformed body."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Cross-origin browser request without an API key. Programmatic clients (curl, SDKs) and same-origin studio calls are unaffected."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "The image could not be read or no barcode was recognized (optionally narrow it with a format hint)."
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rate limit exceeded (per-IP anonymous budget, or per-key quota on /api/v1). Retry after the window in X-RateLimit-Reset. Defaults: 30/min and 300/day per IP."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Decode capacity is busy; retry shortly."
          }
        },
        "summary": "Read a barcode out of an image"
      }
    },
    "/api/generate": {
      "get": {
        "description": "Renders one barcode and returns the raw image bytes. GET with query parameters — the form the studio's live \u003cimg\u003e preview uses. Only type and data are required; everything else falls back to the symbology's defaults.",
        "operationId": "generateBarcode",
        "parameters": [
          {
            "description": "Barcode symbology. Common aliases (ean13, upca, code128, dm, …) are accepted case-insensitively; '-' and '_' are equivalent.",
            "in": "query",
            "name": "type",
            "required": true,
            "schema": {
              "description": "Barcode symbology. Common aliases (ean13, upca, code128, dm, …) are accepted case-insensitively; '-' and '_' are equivalent.",
              "enum": [
                "qr",
                "ean-13",
                "ean-8",
                "upc-a",
                "itf-14",
                "code-128",
                "code-39",
                "code-93",
                "codabar",
                "2of5",
                "datamatrix",
                "aztec",
                "pdf-417"
              ],
              "type": "string"
            }
          },
          {
            "description": "Content to encode. Required; per-type rules apply (e.g. EAN-13 needs 12–13 digits).",
            "in": "query",
            "name": "data",
            "required": true,
            "schema": {
              "description": "Content to encode. Required; per-type rules apply (e.g. EAN-13 needs 12–13 digits).",
              "type": "string"
            }
          },
          {
            "description": "Output format. Default: png.",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "description": "Output format. Default: png.",
              "enum": [
                "png",
                "svg",
                "pdf"
              ],
              "type": "string"
            }
          },
          {
            "description": "Foreground (bar) color as #RGB, #RGBA, #RRGGBB or #RRGGBBAA, with or without '#'. Default: #000000.",
            "in": "query",
            "name": "fg",
            "required": false,
            "schema": {
              "description": "Foreground (bar) color as #RGB, #RGBA, #RRGGBB or #RRGGBBAA, with or without '#'. Default: #000000.",
              "type": "string"
            }
          },
          {
            "description": "Background color, same hex forms as fg. Default: #ffffff.",
            "in": "query",
            "name": "bg",
            "required": false,
            "schema": {
              "description": "Background color, same hex forms as fg. Default: #ffffff.",
              "type": "string"
            }
          },
          {
            "description": "Module size in pixels (positive integer, sent as a string). 2D codes only. Default: 300.",
            "in": "query",
            "name": "size",
            "required": false,
            "schema": {
              "description": "Module size in pixels (positive integer, sent as a string). 2D codes only. Default: 300.",
              "pattern": "^[1-9][0-9]*$",
              "type": "string"
            }
          },
          {
            "description": "QR error-correction level. QR only. Default: M.",
            "in": "query",
            "name": "ec",
            "required": false,
            "schema": {
              "description": "QR error-correction level. QR only. Default: M.",
              "enum": [
                "L",
                "M",
                "Q",
                "H"
              ],
              "type": "string"
            }
          },
          {
            "description": "Bar height in pixels. Linear symbologies only. Default: 60 (50 for code-39 and codabar).",
            "in": "query",
            "name": "height",
            "required": false,
            "schema": {
              "description": "Bar height in pixels. Linear symbologies only. Default: 60 (50 for code-39 and codabar).",
              "type": "integer"
            }
          },
          {
            "description": "Bar width in pixels (narrow-module width). Linear symbologies only. Default: 2.",
            "in": "query",
            "name": "width",
            "required": false,
            "schema": {
              "description": "Bar width in pixels (narrow-module width). Linear symbologies only. Default: 2.",
              "type": "integer"
            }
          },
          {
            "description": "Text band under linear codes. Truthy values: \"1\", \"true\", \"yes\"; any other non-empty value is false; omit for the default (on).",
            "in": "query",
            "name": "show_text",
            "required": false,
            "schema": {
              "description": "Text band under linear codes. Truthy values: \"1\", \"true\", \"yes\"; any other non-empty value is false; omit for the default (on).",
              "type": "string"
            }
          },
          {
            "description": "ITF-14 bearer bars. Same truthy rules as show_text. Default: on for itf-14.",
            "in": "query",
            "name": "bearer_bars",
            "required": false,
            "schema": {
              "description": "ITF-14 bearer bars. Same truthy rules as show_text. Default: on for itf-14.",
              "type": "string"
            }
          },
          {
            "description": "Any non-empty value sets Content-Disposition: attachment (filename \"barcode.\u003cformat\u003e\").",
            "in": "query",
            "name": "download",
            "required": false,
            "schema": {
              "description": "Any non-empty value sets Content-Disposition: attachment (filename \"barcode.\u003cformat\u003e\").",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/pdf": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/png": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The rendered barcode.",
            "headers": {
              "Content-Disposition": {
                "description": "attachment; filename=\"barcode.\u003cformat\u003e\" — only when download is set.",
                "schema": {
                  "description": "",
                  "type": "string"
                }
              },
              "X-Barcode-Type": {
                "description": "Canonical symbology that was generated (useful when the request used an alias).",
                "schema": {
                  "description": "",
                  "enum": [
                    "qr",
                    "ean-13",
                    "ean-8",
                    "upc-a",
                    "itf-14",
                    "code-128",
                    "code-39",
                    "code-93",
                    "codabar",
                    "2of5",
                    "datamatrix",
                    "aztec",
                    "pdf-417"
                  ],
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing/unknown parameter: unknown type, empty data, bad hex color, non-positive size, bad format or ec value."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "The data does not satisfy the type's rules (e.g. wrong digit count or failed check digit)."
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rate limit exceeded (per-IP anonymous budget, or per-key quota on /api/v1). Retry after the window in X-RateLimit-Reset. Defaults: 30/min and 300/day per IP."
          }
        },
        "summary": "Generate a barcode (query string)"
      },
      "post": {
        "description": "Same operation as the GET, with the parameters in a JSON body — better for large content (QR codes hold up to ~4296 chars) and for non-ASCII data. The download flag stays in the query string.",
        "operationId": "generateBarcodeFromBody",
        "parameters": [
          {
            "description": "Any non-empty value sets Content-Disposition: attachment (filename \"barcode.\u003cformat\u003e\").",
            "in": "query",
            "name": "download",
            "required": false,
            "schema": {
              "description": "Any non-empty value sets Content-Disposition: attachment (filename \"barcode.\u003cformat\u003e\").",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/pdf": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/png": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The rendered barcode.",
            "headers": {
              "Content-Disposition": {
                "description": "attachment; filename=\"barcode.\u003cformat\u003e\" — only when download is set.",
                "schema": {
                  "description": "",
                  "type": "string"
                }
              },
              "X-Barcode-Type": {
                "description": "Canonical symbology that was generated (useful when the request used an alias).",
                "schema": {
                  "description": "",
                  "enum": [
                    "qr",
                    "ean-13",
                    "ean-8",
                    "upc-a",
                    "itf-14",
                    "code-128",
                    "code-39",
                    "code-93",
                    "codabar",
                    "2of5",
                    "datamatrix",
                    "aztec",
                    "pdf-417"
                  ],
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Malformed JSON, or a missing/unknown parameter (same rules as the GET form)."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "The data does not satisfy the type's rules."
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rate limit exceeded (per-IP anonymous budget, or per-key quota on /api/v1). Retry after the window in X-RateLimit-Reset. Defaults: 30/min and 300/day per IP."
          }
        },
        "summary": "Generate a barcode (JSON body)"
      }
    },
    "/api/spec": {
      "get": {
        "description": "The static list the studio UI populates its dropdowns from: every symbology with a human label, linearity flag, content hint, and a known-valid sample value; plus output formats and QR error-correction levels. Not rate-limited.",
        "operationId": "getApiSpec",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpecResponse"
                }
              }
            },
            "description": "Capability list."
          }
        },
        "summary": "Capability list: symbologies, formats, error levels"
      }
    },
    "/api/validate": {
      "get": {
        "description": "Checks data against a type's rules before you print anything. GS1 types (ean-13, ean-8, upc-a, itf-14) given one digit fewer than their full length come back auto-completed: the response carries the corrected full code, its check digit, and — for ean-13 — the issuing country. Invalid data still returns 200 with valid=false; only an unknown type is a 400.",
        "operationId": "validateData",
        "parameters": [
          {
            "description": "Barcode symbology to validate against. Validation exists for qr, ean-13, ean-8, upc-a, itf-14, code-128, code-39, and codabar.",
            "in": "query",
            "name": "type",
            "required": true,
            "schema": {
              "description": "Barcode symbology to validate against. Validation exists for qr, ean-13, ean-8, upc-a, itf-14, code-128, code-39, and codabar.",
              "enum": [
                "qr",
                "ean-13",
                "ean-8",
                "upc-a",
                "itf-14",
                "code-128",
                "code-39",
                "codabar"
              ],
              "type": "string"
            }
          },
          {
            "description": "Content to validate (or N-1 digits for GS1 auto-complete).",
            "in": "query",
            "name": "data",
            "required": true,
            "schema": {
              "description": "Content to validate (or N-1 digits for GS1 auto-complete).",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationResult"
                }
              }
            },
            "description": "Validation result. invalid data also returns 200 with valid=false — only an unknown type is a 400."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unknown type."
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rate limit exceeded (per-IP anonymous budget, or per-key quota on /api/v1). Retry after the window in X-RateLimit-Reset. Defaults: 30/min and 300/day per IP."
          }
        },
        "summary": "Validate content for a symbology"
      },
      "post": {
        "description": "Same validation as the GET, with type and data in a JSON body.",
        "operationId": "validateDataFromBody",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Data to validate.",
                "properties": {
                  "data": {
                    "description": "Content to validate.",
                    "type": "string"
                  },
                  "type": {
                    "description": "Barcode symbology.",
                    "enum": [
                      "qr",
                      "ean-13",
                      "ean-8",
                      "upc-a",
                      "itf-14",
                      "code-128",
                      "code-39",
                      "code-93",
                      "codabar",
                      "2of5",
                      "datamatrix",
                      "aztec",
                      "pdf-417"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "type",
                  "data"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationResult"
                }
              }
            },
            "description": "Validation result. invalid data also returns 200 with valid=false — only an unknown type is a 400."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Malformed JSON or unknown type."
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rate limit exceeded (per-IP anonymous budget, or per-key quota on /api/v1). Retry after the window in X-RateLimit-Reset. Defaults: 30/min and 300/day per IP."
          }
        },
        "summary": "Validate content for a symbology (JSON body)"
      }
    }
  },
  "servers": [
    {
      "url": "https://barcode.donaldmurillo.com"
    }
  ],
  "tags": [
    {
      "description": "Render a single barcode or QR code.",
      "name": "generate"
    },
    {
      "description": "Check content against a symbology's rules; auto-complete GS1 check digits.",
      "name": "validate"
    },
    {
      "description": "Read symbology and content back out of an image.",
      "name": "decode"
    },
    {
      "description": "Generate many codes at once into a ZIP.",
      "name": "batch"
    },
    {
      "description": "Capability discovery.",
      "name": "spec"
    }
  ]
}
