{
  "openapi": "3.1.0",
  "info": {
    "title": "Bytario API",
    "version": "0.1.0",
    "summary": "Privacy-first file utility API — same WASM engine as bytario.com",
    "description": "Paid B2B file utility API. Every endpoint is a stateless conversion\nover byte arrays — the same `@bytario/core` pure functions that power\nthe consumer site at `bytario.com`, hosted in a Cloudflare Worker.\n\n## Authentication\nAll `/v1/*` endpoints require an API key supplied as a bearer token:\n`Authorization: Bearer sk_live_...`. Keys are issued after successful\nStripe checkout and emailed to the billing contact.\n\n## Rate limits\nEvery plan has a sustained-throughput budget (`RateLimit-Limit` header)\nand a burst allowance enforced via a per-key token bucket. Responses\ncarry `RateLimit-Limit` / `RateLimit-Remaining`; a rejected request\ngets HTTP 429 plus `Retry-After`.\n\n## Quota\nMonthly request caps reset on the 1st of each month at 00:00 UTC.\n`X-Quota-Remaining` on every success response reflects the post-call\nremaining budget. Quota exhaustion returns HTTP 429 `quota_exceeded`.\n",
    "contact": {
      "name": "Bytario Support",
      "email": "support@bytario.com"
    },
    "license": {
      "name": "Proprietary — Copyright (c) 2026 DMG L&D, LLC. All rights reserved.",
      "url": "https://bytario.com/terms"
    }
  },
  "servers": [
    {
      "url": "https://api.bytario.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "image",
      "description": "Image conversion, resize, compress, metadata, favicon"
    },
    {
      "name": "pdf",
      "description": "PDF merge / split / rotate / watermark / info / text / render / forms"
    },
    {
      "name": "qr",
      "description": "QR code generation and decoding"
    },
    {
      "name": "barcode",
      "description": "1D and 2D barcode generation and decoding (non-QR)"
    },
    {
      "name": "render",
      "description": "Vector → raster rendering"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "summary": "Liveness probe",
        "security": [],
        "tags": [
          "image"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "ok"
                }
              }
            }
          }
        }
      }
    },
    "/v1/image/convert": {
      "post": {
        "tags": [
          "image"
        ],
        "summary": "Convert an image between formats",
        "parameters": [
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "jpeg",
                "png",
                "webp",
                "avif"
              ]
            }
          },
          {
            "name": "quality",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryImage"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryImage"
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/image/resize": {
      "post": {
        "tags": [
          "image"
        ],
        "summary": "Resize with fit modes (cover/contain/fill/inside/outside)",
        "parameters": [
          {
            "name": "width",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "height",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "fit",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "cover",
                "contain",
                "fill",
                "inside",
                "outside"
              ]
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "jpeg",
                "png",
                "webp",
                "avif"
              ]
            }
          },
          {
            "name": "quality",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryImage"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryImage"
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/image/compress": {
      "post": {
        "tags": [
          "image"
        ],
        "summary": "Recompress at target quality (optionally re-encode format)",
        "parameters": [
          {
            "name": "quality",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "jpeg",
                "png",
                "webp",
                "avif"
              ]
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryImage"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryImage"
          }
        }
      }
    },
    "/v1/image/strip-metadata": {
      "post": {
        "tags": [
          "image"
        ],
        "summary": "Remove EXIF / IPTC / XMP / GPS without re-encoding pixels",
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryImage"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryImage"
          }
        }
      }
    },
    "/v1/image/read-metadata": {
      "post": {
        "tags": [
          "image"
        ],
        "summary": "Extract EXIF / GPS / camera info as structured JSON",
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryImage"
        },
        "responses": {
          "200": {
            "description": "ImageMetadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageMetadata"
                }
              }
            }
          }
        }
      }
    },
    "/v1/image/favicon-set": {
      "post": {
        "tags": [
          "image"
        ],
        "summary": "Generate a full favicon bundle (ICO + PNGs + manifest.json)",
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryImage"
        },
        "responses": {
          "200": {
            "description": "Favicon bundle JSON (base64 encoded ICO + PNGs + manifest)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FaviconSetResult"
                }
              }
            }
          }
        }
      }
    },
    "/v1/pdf/merge": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Merge multiple PDFs into one",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "files"
                ],
                "properties": {
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "byte",
                      "description": "base64-encoded PDF"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryPdf"
          }
        }
      }
    },
    "/v1/pdf/split": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Extract one or more page ranges into separate PDFs",
        "parameters": [
          {
            "name": "ranges",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1-3,7-9"
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryPdf"
        },
        "responses": {
          "200": {
            "description": "Array of base64-encoded PDFs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pdfs": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "format": "byte"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/pdf/rotate": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Rotate specified pages by 90, 180, or 270 degrees",
        "parameters": [
          {
            "name": "pages",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1,3,5",
              "default": "all"
            }
          },
          {
            "name": "degrees",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                90,
                180,
                270
              ]
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryPdf"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryPdf"
          }
        }
      }
    },
    "/v1/pdf/watermark": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Stamp text watermark on one or more pages",
        "parameters": [
          {
            "name": "text",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "opacity",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            }
          },
          {
            "name": "rotation",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "fontSize",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 1
            }
          },
          {
            "name": "pages",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "all"
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryPdf"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryPdf"
          }
        }
      }
    },
    "/v1/pdf/info": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Page count, page sizes, and document metadata",
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryPdf"
        },
        "responses": {
          "200": {
            "description": "PdfInfo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PdfInfo"
                }
              }
            }
          }
        }
      }
    },
    "/v1/pdf/extract-text": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Pure-JS vector text extraction (no OCR)",
        "parameters": [
          {
            "name": "pages",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1-3 or 1,3,5"
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryPdf"
        },
        "responses": {
          "200": {
            "description": "PdfTextResult",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PdfTextResult"
                }
              }
            }
          }
        }
      }
    },
    "/v1/pdf/render-page": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Rasterize one or more pages to PNG / JPEG / WebP",
        "parameters": [
          {
            "name": "pages",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1,3"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "png",
                "jpeg",
                "webp"
              ],
              "default": "png"
            }
          },
          {
            "name": "dpi",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 72,
              "maximum": 300
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryPdf"
        },
        "responses": {
          "200": {
            "description": "Array of rendered pages",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PdfRenderPageResult"
                }
              }
            }
          }
        }
      }
    },
    "/v1/pdf/fill-form": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Fill AcroForm fields (optionally flatten afterwards)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "pdf",
                  "fields"
                ],
                "properties": {
                  "pdf": {
                    "type": "string",
                    "format": "byte"
                  },
                  "fields": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "flatten": {
                    "type": "boolean"
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file",
                  "fields"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "fields": {
                    "type": "string",
                    "description": "JSON string of field map"
                  },
                  "flatten": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryPdf"
          }
        }
      }
    },
    "/v1/pdf/flatten": {
      "post": {
        "tags": [
          "pdf"
        ],
        "summary": "Flatten form fields (bake values in, remove editability)",
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryPdf"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryPdf"
          }
        }
      }
    },
    "/v1/qr/generate": {
      "post": {
        "tags": [
          "qr"
        ],
        "summary": "Generate a QR code as PNG or SVG",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QrGenerateOptions"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PNG or SVG bytes",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/v1/qr/read": {
      "post": {
        "tags": [
          "qr"
        ],
        "summary": "Decode a QR code from an image",
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryImage"
        },
        "responses": {
          "200": {
            "description": "QrReadResult",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "format": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/barcode/generate": {
      "post": {
        "tags": [
          "barcode"
        ],
        "summary": "Generate a 1D or 2D barcode (EAN, UPC, Code 128, DataMatrix, PDF417, Aztec)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BarcodeGenerateOptions"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SVG bytes",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/v1/barcode/read": {
      "post": {
        "tags": [
          "barcode"
        ],
        "summary": "Decode 1D/2D barcodes from an image",
        "requestBody": {
          "$ref": "#/components/requestBodies/BinaryImage"
        },
        "responses": {
          "200": {
            "description": "BarcodeReadResult",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "codes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "text": {
                            "type": "string"
                          },
                          "format": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/render/svg-to-png": {
      "post": {
        "tags": [
          "render"
        ],
        "summary": "Render an SVG to a PNG via resvg-wasm",
        "parameters": [
          {
            "name": "scale",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0.1,
              "maximum": 10
            }
          },
          {
            "name": "width",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "height",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "image/svg+xml": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PNG bytes",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sk_live_..."
      }
    },
    "requestBodies": {
      "BinaryImage": {
        "required": true,
        "content": {
          "image/jpeg": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/png": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/webp": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/avif": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/heic": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "application/octet-stream": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      },
      "BinaryPdf": {
        "required": true,
        "content": {
          "application/pdf": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "application/octet-stream": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      }
    },
    "responses": {
      "BinaryImage": {
        "description": "Converted image bytes",
        "headers": {
          "X-Quota-Remaining": {
            "schema": {
              "type": "integer"
            }
          },
          "RateLimit-Limit": {
            "schema": {
              "type": "integer"
            }
          },
          "RateLimit-Remaining": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "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"
            }
          }
        }
      },
      "BinaryPdf": {
        "description": "PDF bytes",
        "headers": {
          "X-Quota-Remaining": {
            "schema": {
              "type": "integer"
            }
          },
          "RateLimit-Limit": {
            "schema": {
              "type": "integer"
            }
          },
          "RateLimit-Remaining": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/pdf": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      },
      "Error": {
        "description": "Standardized error envelope",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      }
    },
    "schemas": {
      "ApiError": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "unauthorized",
              "subscription_inactive",
              "quota_exceeded",
              "rate_limited",
              "invalid_input",
              "unsupported_format",
              "too_large",
              "conversion_failed",
              "internal_error"
            ]
          },
          "message": {
            "type": "string"
          },
          "upgrade_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "ImageMetadata": {
        "type": "object",
        "properties": {
          "width": {
            "type": "integer"
          },
          "height": {
            "type": "integer"
          },
          "takenAt": {
            "type": "string",
            "format": "date-time"
          },
          "camera": {
            "type": "object",
            "properties": {
              "make": {
                "type": "string"
              },
              "model": {
                "type": "string"
              },
              "lens": {
                "type": "string"
              }
            }
          },
          "gps": {
            "type": "object",
            "properties": {
              "latitude": {
                "type": "number"
              },
              "longitude": {
                "type": "number"
              },
              "altitude": {
                "type": "number"
              }
            }
          },
          "exif": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "FaviconSetResult": {
        "type": "object",
        "properties": {
          "ico": {
            "type": "string",
            "format": "byte"
          },
          "pngs": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "byte"
            }
          },
          "manifest": {
            "type": "string"
          }
        }
      },
      "PdfInfo": {
        "type": "object",
        "required": [
          "pageCount",
          "pageSizes",
          "metadata",
          "encrypted"
        ],
        "properties": {
          "pageCount": {
            "type": "integer"
          },
          "pageSizes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "width": {
                  "type": "number"
                },
                "height": {
                  "type": "number"
                }
              }
            }
          },
          "metadata": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string"
              },
              "author": {
                "type": "string"
              },
              "subject": {
                "type": "string"
              },
              "keywords": {
                "type": "string"
              },
              "producer": {
                "type": "string"
              },
              "creator": {
                "type": "string"
              }
            }
          },
          "encrypted": {
            "type": "boolean"
          }
        }
      },
      "PdfTextResult": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string"
          },
          "pages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "PdfRenderPageResult": {
        "type": "object",
        "properties": {
          "pages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "page": {
                  "type": "integer"
                },
                "bytes": {
                  "type": "string",
                  "format": "byte"
                },
                "width": {
                  "type": "integer"
                },
                "height": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "QrGenerateOptions": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string"
          },
          "format": {
            "type": "string",
            "enum": [
              "png",
              "svg"
            ],
            "default": "png"
          },
          "size": {
            "type": "integer",
            "minimum": 1
          },
          "margin": {
            "type": "integer",
            "minimum": 0
          },
          "errorCorrection": {
            "type": "string",
            "enum": [
              "L",
              "M",
              "Q",
              "H"
            ],
            "default": "M"
          },
          "foreground": {
            "type": "string",
            "example": "#000000"
          },
          "background": {
            "type": "string",
            "example": "#ffffff"
          }
        }
      },
      "BarcodeGenerateOptions": {
        "type": "object",
        "required": [
          "text",
          "format"
        ],
        "properties": {
          "text": {
            "type": "string"
          },
          "format": {
            "type": "string",
            "enum": [
              "ean13",
              "ean8",
              "upca",
              "upce",
              "code128",
              "code39",
              "itf14",
              "itf",
              "datamatrix",
              "pdf417",
              "aztec"
            ]
          },
          "output": {
            "type": "string",
            "enum": [
              "svg"
            ],
            "default": "svg"
          },
          "scale": {
            "type": "integer"
          },
          "height": {
            "type": "integer"
          },
          "includeText": {
            "type": "boolean"
          },
          "foreground": {
            "type": "string"
          },
          "background": {
            "type": "string"
          }
        }
      }
    }
  }
}
