{
  "openapi": "3.1.0",
  "info": {
    "title": "MostlyPDF API",
    "version": "1.0.0",
    "summary": "35 PDF operations behind one endpoint, priced per operation.",
    "description": "Run any MostlyPDF tool programmatically. One flat, metered per-operation rate — no credit currency, no hidden calculator.\n\n### Quickstart\nCreate a key in your [dashboard](https://mostlypdf.com/#/keys), then call the API with it as a Bearer token. Files go in and out base64-encoded:\n\n```bash\ncurl https://mostly-pdf.web.app/v1/process \\\n  -H \"Authorization: Bearer sk_live_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"tool\": \"rotate-pdf\",\n    \"options\": { \"degrees\": 90 },\n    \"files\": [\"JVBERi0xLjQK...\"]\n  }'\n```\n\nThe response is `{ \"outputs\": [\"<base64-pdf>\"], \"filenames\": [...], \"contentType\": \"application/pdf\" }` (render tools return a hosted `pdfUrl` instead). `GET /v1/process` with your key checks it without running or billing anything.\n\n### Authentication\nAn `sk_` API key as `Authorization: Bearer …` (or the `x-api-key` header). Keys are created in the dashboard and need the `pdf:run` scope; API keys come with the Pro plan.\n\n### Pricing\nEvery successful call is one operation, whichever tool you run: $1 per 100 operations, charged from your Mostly Tiny wallet (https://id.mostlytiny.io/billing). An empty wallet or missing card returns `402` with a `billing_url`.\n\n### Rate limits\nKeys billed from a funded wallet have no per-key request cap; throughput is bounded by concurrency (requests over ~20 in flight queue briefly). Callers on the free trial allowance (a Mostly Tiny identity with no card on file, e.g. via the MCP) get 60 requests/minute plus a small daily cap per conversion tool (5–20/day). Over a limit you get `429` with `code: \"quota\"`, a `resetAt` timestamp and a `Retry-After` header.\n\n### Errors\nEvery error is JSON `{ \"error\": \"<human message>\", \"code\": \"<machine code>\" }`, sometimes with extra fields (`resetAt`, `billing_url`, `hint`). Branch on `code`, not on `error`.\n\n### Idempotency and side effects\nOperations are pure transforms: nothing is stored, nothing is changed on your account, and the same input gives the same output, so a failed call is always safe to retry. Send an `Idempotency-Key` header to make the retry free as well — the wallet charges a given key once.\n\n### Use from an AI agent\nThe unified Mostly Tiny MCP server at https://mcp.mostlytiny.io exposes this API as tools (OAuth sign-in, no key needed): `claude mcp add --transport http mostly-tiny https://mcp.mostlytiny.io`.\n\n### Tools\n- `merge-pdf` — Merge PDF (two or more files)\n- `split-pdf` — Split PDF (one file)\n- `remove-pages` — Remove Pages (one file)\n- `extract-pages` — Extract Pages (one file)\n- `organize-pdf` — Organize PDF (one file)\n- `rotate-pdf` — Rotate PDF (one file)\n- `page-numbers` — Add Page Numbers (one file)\n- `watermark-pdf` — Watermark PDF (one file)\n- `crop-pdf` — Crop PDF (one file)\n- `fill-pdf-form` — Fill PDF Form (one file)\n- `jpg-to-pdf` — JPG to PDF (two or more files)\n- `compress-pdf` — Compress PDF (one file)\n- `pdf-to-word` — PDF to Word (one file; Pro)\n- `pdf-to-jpg` — PDF to JPG (one file)\n- `word-to-pdf` — Word to PDF (one file)\n- `ocr-pdf` — OCR PDF (one file; Pro)\n- `excel-to-pdf` — Excel to PDF (one file)\n- `powerpoint-to-pdf` — PowerPoint to PDF (one file)\n- `pdf-to-excel` — PDF to Excel (one file; Pro)\n- `pdf-to-powerpoint` — PDF to PowerPoint (one file; Pro)\n- `pdf-to-pdfa` — PDF to PDF/A (one file)\n- `repair-pdf` — Repair PDF (one file)\n- `compare-pdf` — Compare PDF (two or more files)\n- `redact-pdf` — Redact PDF (one file; Pro)\n- `txt-to-pdf` — TXT to PDF (one file)\n- `rtf-to-pdf` — RTF to PDF (one file)\n- `odt-to-pdf` — ODT to PDF (one file)\n- `html-to-pdf` — HTML to PDF (no files — content goes in `options`)\n- `url-to-pdf` — Webpage to PDF (no files — content goes in `options`)\n- `markdown-to-pdf` — Markdown to PDF (no files — content goes in `options`)\n- `email-to-pdf` — Email to PDF (no files — content goes in `options`)\n- `protect-pdf` — Protect PDF (one file)\n- `unlock-pdf` — Unlock PDF (one file)\n- `sign-pdf` — Sign PDF (one file; Pro)\n- `sign-pdf-certified` — Certify PDF (digital signature) (one file; Pro)",
    "termsOfService": "https://mostlypdf.com/terms",
    "license": {
      "name": "Proprietary — use governed by the Terms of Service",
      "url": "https://mostlypdf.com/terms"
    },
    "contact": {
      "name": "MostlyPDF support",
      "url": "https://mostlypdf.com/support"
    },
    "x-logo": {
      "url": "https://mostlypdf.com/apple-touch-icon.png",
      "altText": "MostlyPDF"
    }
  },
  "externalDocs": {
    "description": "API reference and guides",
    "url": "https://mostlypdf.com/docs"
  },
  "servers": [
    {
      "url": "https://mostly-pdf.web.app",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "apiKeyHeader": []
    }
  ],
  "tags": [
    {
      "name": "PDF",
      "description": "Run a PDF operation."
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your `sk_` API key."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your `sk_` API key, as an alternative to the Bearer header."
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 128
        },
        "description": "Any unique string per logical request (a UUID is fine). A retry carrying the same key is not charged twice."
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Seconds until the limit resets.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "schemas": {
      "ProcessRequest-merge-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "merge-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-merge-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-split-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "split-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-split-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-remove-pages": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "remove-pages"
          },
          "options": {
            "$ref": "#/components/schemas/Options-remove-pages"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-extract-pages": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "extract-pages"
          },
          "options": {
            "$ref": "#/components/schemas/Options-extract-pages"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-organize-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "organize-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-organize-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-rotate-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "rotate-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-rotate-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-page-numbers": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "page-numbers"
          },
          "options": {
            "$ref": "#/components/schemas/Options-page-numbers"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-watermark-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "watermark-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-watermark-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-crop-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "crop-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-crop-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-fill-pdf-form": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "fill-pdf-form"
          },
          "options": {
            "$ref": "#/components/schemas/Options-fill-pdf-form"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-jpg-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "jpg-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-jpg-to-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-compress-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "compress-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-compress-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-pdf-to-word": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "pdf-to-word"
          },
          "options": {
            "$ref": "#/components/schemas/Options-pdf-to-word"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-pdf-to-jpg": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "pdf-to-jpg"
          },
          "options": {
            "$ref": "#/components/schemas/Options-pdf-to-jpg"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-word-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "word-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-word-to-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-ocr-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "ocr-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-ocr-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-excel-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "excel-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-excel-to-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-powerpoint-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "powerpoint-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-powerpoint-to-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-pdf-to-excel": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "pdf-to-excel"
          },
          "options": {
            "$ref": "#/components/schemas/Options-pdf-to-excel"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-pdf-to-powerpoint": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "pdf-to-powerpoint"
          },
          "options": {
            "$ref": "#/components/schemas/Options-pdf-to-powerpoint"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-pdf-to-pdfa": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "pdf-to-pdfa"
          },
          "options": {
            "$ref": "#/components/schemas/Options-pdf-to-pdfa"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-repair-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "repair-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-repair-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-compare-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "compare-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-compare-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-redact-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "redact-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-redact-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-txt-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "txt-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-txt-to-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-rtf-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "rtf-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-rtf-to-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-odt-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "odt-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-odt-to-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-html-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "options"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "html-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-html-to-pdf"
          }
        }
      },
      "ProcessRequest-url-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "options"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "url-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-url-to-pdf"
          }
        }
      },
      "ProcessRequest-markdown-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "options"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "markdown-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-markdown-to-pdf"
          }
        }
      },
      "ProcessRequest-email-to-pdf": {
        "type": "object",
        "required": [
          "tool",
          "options"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "email-to-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-email-to-pdf"
          }
        }
      },
      "ProcessRequest-protect-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "protect-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-protect-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-unlock-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "unlock-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-unlock-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-sign-pdf": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "sign-pdf"
          },
          "options": {
            "$ref": "#/components/schemas/Options-sign-pdf"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "ProcessRequest-sign-pdf-certified": {
        "type": "object",
        "required": [
          "tool",
          "files"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "const": "sign-pdf-certified"
          },
          "options": {
            "$ref": "#/components/schemas/Options-sign-pdf-certified"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
          }
        }
      },
      "Options-merge-pdf": {
        "title": "Merge PDF options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-split-pdf": {
        "title": "Split PDF options",
        "type": "object",
        "properties": {
          "ranges": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "One output per range, e.g. [\"1-3\", \"4-10\"]. Takes precedence over everyN."
          },
          "everyN": {
            "type": "integer",
            "minimum": 1,
            "description": "Split into chunks of N pages."
          }
        },
        "additionalProperties": false
      },
      "Options-remove-pages": {
        "title": "Remove Pages options",
        "type": "object",
        "properties": {
          "pages": {
            "oneOf": [
              {
                "type": "string",
                "pattern": "^\\s*\\d+(\\s*-\\s*\\d+)?(\\s*,\\s*\\d+(\\s*-\\s*\\d+)?)*\\s*$"
              },
              {
                "type": "array",
                "items": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            ],
            "description": "1-based page selection: a range string like \"1-3,5\" or an array of page numbers.",
            "examples": [
              "2,5-7"
            ]
          }
        },
        "required": [
          "pages"
        ],
        "additionalProperties": false
      },
      "Options-extract-pages": {
        "title": "Extract Pages options",
        "type": "object",
        "properties": {
          "pages": {
            "oneOf": [
              {
                "type": "string",
                "pattern": "^\\s*\\d+(\\s*-\\s*\\d+)?(\\s*,\\s*\\d+(\\s*-\\s*\\d+)?)*\\s*$"
              },
              {
                "type": "array",
                "items": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            ],
            "description": "1-based page selection: a range string like \"1-3,5\" or an array of page numbers.",
            "examples": [
              "2,5-7"
            ]
          }
        },
        "required": [
          "pages"
        ],
        "additionalProperties": false
      },
      "Options-organize-pdf": {
        "title": "Organize PDF options",
        "type": "object",
        "properties": {
          "order": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            },
            "description": "A permutation of every page number, e.g. [3,1,2] for a 3-page file."
          }
        },
        "required": [
          "order"
        ],
        "additionalProperties": false
      },
      "Options-rotate-pdf": {
        "title": "Rotate PDF options",
        "type": "object",
        "properties": {
          "degrees": {
            "type": "integer",
            "enum": [
              90,
              180,
              270
            ],
            "default": 90,
            "description": "Clockwise rotation."
          },
          "pages": {
            "oneOf": [
              {
                "type": "string",
                "pattern": "^\\s*\\d+(\\s*-\\s*\\d+)?(\\s*,\\s*\\d+(\\s*-\\s*\\d+)?)*\\s*$"
              },
              {
                "type": "array",
                "items": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            ],
            "description": "1-based page selection: a range string like \"1-3,5\" or an array of page numbers.",
            "examples": [
              "2,5-7"
            ]
          }
        },
        "additionalProperties": false
      },
      "Options-page-numbers": {
        "title": "Add Page Numbers options",
        "type": "object",
        "properties": {
          "position": {
            "type": "string",
            "enum": [
              "bottom-center",
              "bottom-left",
              "bottom-right",
              "top-center",
              "top-left",
              "top-right"
            ],
            "default": "bottom-center"
          },
          "start": {
            "type": "integer",
            "default": 1,
            "description": "Number printed on the first page."
          },
          "fontSize": {
            "type": "number",
            "default": 10
          },
          "margin": {
            "type": "number",
            "default": 24,
            "description": "Distance from the page edge, in points."
          }
        },
        "additionalProperties": false
      },
      "Options-watermark-pdf": {
        "title": "Watermark PDF options",
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Watermark text, drawn diagonally across every page."
          },
          "opacity": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "default": 0.25
          },
          "fontSize": {
            "type": "number",
            "default": 48
          },
          "color": {
            "type": "array",
            "items": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            },
            "minItems": 3,
            "maxItems": 3,
            "default": [
              0.6,
              0.6,
              0.6
            ],
            "description": "RGB, each 0–1."
          }
        },
        "required": [
          "text"
        ],
        "additionalProperties": false
      },
      "Options-crop-pdf": {
        "title": "Crop PDF options",
        "type": "object",
        "properties": {
          "top": {
            "type": "number",
            "minimum": 0,
            "default": 0,
            "description": "Points to trim from the top."
          },
          "bottom": {
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "left": {
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "right": {
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "pages": {
            "oneOf": [
              {
                "type": "string",
                "pattern": "^\\s*\\d+(\\s*-\\s*\\d+)?(\\s*,\\s*\\d+(\\s*-\\s*\\d+)?)*\\s*$"
              },
              {
                "type": "array",
                "items": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            ],
            "description": "1-based page selection: a range string like \"1-3,5\" or an array of page numbers.",
            "examples": [
              "2,5-7"
            ]
          }
        },
        "additionalProperties": false
      },
      "Options-fill-pdf-form": {
        "title": "Fill PDF Form options",
        "type": "object",
        "properties": {
          "fields": {
            "type": "object",
            "additionalProperties": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "boolean"
                }
              ]
            },
            "description": "Field name → value. Text fields take a string, checkboxes a boolean, radio/dropdown the option name."
          },
          "flatten": {
            "type": "boolean",
            "default": true,
            "description": "Bake the values in and remove the interactive fields."
          }
        },
        "required": [
          "fields"
        ],
        "additionalProperties": false
      },
      "Options-jpg-to-pdf": {
        "title": "JPG to PDF options",
        "type": "object",
        "properties": {
          "margin": {
            "type": "number",
            "minimum": 0,
            "default": 0,
            "description": "Page margin around each image, in points."
          },
          "pageSize": {
            "type": "string",
            "enum": [
              "fit",
              "a4"
            ],
            "default": "fit",
            "description": "\"fit\" sizes each page to its image; \"a4\" centres it on an A4 page."
          }
        },
        "additionalProperties": false
      },
      "Options-compress-pdf": {
        "title": "Compress PDF options",
        "type": "object",
        "properties": {
          "quality": {
            "type": "string",
            "enum": [
              "screen",
              "ebook",
              "printer",
              "prepress"
            ],
            "default": "ebook",
            "description": "Ghostscript preset — screen is smallest, prepress keeps the most detail."
          }
        },
        "additionalProperties": false
      },
      "Options-pdf-to-word": {
        "title": "PDF to Word options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-pdf-to-jpg": {
        "title": "PDF to JPG options",
        "type": "object",
        "properties": {
          "dpi": {
            "type": "integer",
            "minimum": 36,
            "maximum": 300,
            "default": 150
          },
          "quality": {
            "type": "integer",
            "minimum": 50,
            "maximum": 100,
            "default": 90,
            "description": "JPEG quality."
          }
        },
        "additionalProperties": false
      },
      "Options-word-to-pdf": {
        "title": "Word to PDF options",
        "type": "object",
        "properties": {
          "ext": {
            "type": "string",
            "default": "docx",
            "description": "Source file extension LibreOffice should read the input as (e.g. docx, doc, odt, rtf, txt)."
          }
        },
        "additionalProperties": false
      },
      "Options-ocr-pdf": {
        "title": "OCR PDF options",
        "type": "object",
        "properties": {
          "lang": {
            "type": "string",
            "default": "eng",
            "description": "Tesseract language code(s), \"+\"-joined, e.g. \"eng+deu\"."
          },
          "force": {
            "type": "boolean",
            "default": false,
            "description": "Re-OCR pages that already have a text layer."
          }
        },
        "additionalProperties": false
      },
      "Options-excel-to-pdf": {
        "title": "Excel to PDF options",
        "type": "object",
        "properties": {
          "ext": {
            "type": "string",
            "default": "xlsx",
            "description": "Source file extension LibreOffice should read the input as (e.g. docx, doc, odt, rtf, txt)."
          }
        },
        "additionalProperties": false
      },
      "Options-powerpoint-to-pdf": {
        "title": "PowerPoint to PDF options",
        "type": "object",
        "properties": {
          "ext": {
            "type": "string",
            "default": "pptx",
            "description": "Source file extension LibreOffice should read the input as (e.g. docx, doc, odt, rtf, txt)."
          }
        },
        "additionalProperties": false
      },
      "Options-pdf-to-excel": {
        "title": "PDF to Excel options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-pdf-to-powerpoint": {
        "title": "PDF to PowerPoint options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-pdf-to-pdfa": {
        "title": "PDF to PDF/A options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-repair-pdf": {
        "title": "Repair PDF options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-compare-pdf": {
        "title": "Compare PDF options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-redact-pdf": {
        "title": "Redact PDF options",
        "type": "object",
        "properties": {
          "boxes": {
            "type": "array",
            "description": "Areas to black out. x/y/w/h are fractions (0–1) of the page width/height from the top-left. Every page is then rasterized, so the hidden text is unrecoverable.",
            "items": {
              "type": "object",
              "properties": {
                "page": {
                  "type": "integer",
                  "minimum": 1
                },
                "x": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                },
                "y": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                },
                "w": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                },
                "h": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                }
              },
              "required": [
                "page",
                "x",
                "y",
                "w",
                "h"
              ],
              "additionalProperties": false
            }
          },
          "dpi": {
            "type": "integer",
            "minimum": 72,
            "maximum": 300,
            "default": 200,
            "description": "Rasterization resolution."
          }
        },
        "required": [
          "boxes"
        ],
        "additionalProperties": false
      },
      "Options-txt-to-pdf": {
        "title": "TXT to PDF options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-rtf-to-pdf": {
        "title": "RTF to PDF options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-odt-to-pdf": {
        "title": "ODT to PDF options",
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "Options-html-to-pdf": {
        "title": "HTML to PDF options",
        "type": "object",
        "properties": {
          "html": {
            "type": "string",
            "description": "The HTML document to render."
          },
          "paper": {
            "type": "string",
            "enum": [
              "A4",
              "Letter",
              "Legal",
              "A3",
              "A5"
            ],
            "default": "A4",
            "description": "Paper size."
          }
        },
        "required": [
          "html"
        ],
        "additionalProperties": false
      },
      "Options-url-to-pdf": {
        "title": "Webpage to PDF options",
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "A public http(s) URL."
          },
          "paper": {
            "type": "string",
            "enum": [
              "A4",
              "Letter",
              "Legal",
              "A3",
              "A5"
            ],
            "default": "A4",
            "description": "Paper size."
          }
        },
        "required": [
          "url"
        ],
        "additionalProperties": false
      },
      "Options-markdown-to-pdf": {
        "title": "Markdown to PDF options",
        "type": "object",
        "properties": {
          "html": {
            "type": "string",
            "description": "The Markdown, already rendered to HTML."
          },
          "paper": {
            "type": "string",
            "enum": [
              "A4",
              "Letter",
              "Legal",
              "A3",
              "A5"
            ],
            "default": "A4",
            "description": "Paper size."
          }
        },
        "required": [
          "html"
        ],
        "additionalProperties": false
      },
      "Options-email-to-pdf": {
        "title": "Email to PDF options",
        "type": "object",
        "properties": {
          "html": {
            "type": "string",
            "description": "The email body, as HTML."
          },
          "paper": {
            "type": "string",
            "enum": [
              "A4",
              "Letter",
              "Legal",
              "A3",
              "A5"
            ],
            "default": "A4",
            "description": "Paper size."
          }
        },
        "required": [
          "html"
        ],
        "additionalProperties": false
      },
      "Options-protect-pdf": {
        "title": "Protect PDF options",
        "type": "object",
        "properties": {
          "password": {
            "type": "string",
            "minLength": 1,
            "description": "Password to open the file (256-bit AES)."
          },
          "ownerPassword": {
            "type": "string",
            "description": "Permissions password; defaults to `password`."
          }
        },
        "required": [
          "password"
        ],
        "additionalProperties": false
      },
      "Options-unlock-pdf": {
        "title": "Unlock PDF options",
        "type": "object",
        "properties": {
          "password": {
            "type": "string",
            "minLength": 1,
            "description": "The current password."
          }
        },
        "required": [
          "password"
        ],
        "additionalProperties": false
      },
      "Options-sign-pdf": {
        "title": "Sign PDF options",
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "text",
              "image"
            ],
            "default": "text"
          },
          "text": {
            "type": "string",
            "description": "Typed signature (type \"text\")."
          },
          "image": {
            "type": "object",
            "properties": {
              "base64": {
                "type": "string",
                "format": "byte"
              },
              "type": {
                "type": "string",
                "enum": [
                  "png",
                  "jpg"
                ]
              }
            },
            "required": [
              "base64"
            ],
            "additionalProperties": false
          },
          "page": {
            "type": "integer",
            "minimum": 1,
            "description": "Page to sign; defaults to the last page."
          },
          "x": {
            "type": "number",
            "default": 56,
            "description": "Points from the left edge."
          },
          "y": {
            "type": "number",
            "default": 64,
            "description": "Points from the bottom edge."
          },
          "width": {
            "type": "number",
            "description": "Image width in points (image mode)."
          },
          "height": {
            "type": "number",
            "description": "Image height in points (image mode); defaults to width × the image aspect ratio."
          },
          "fontSize": {
            "type": "number",
            "default": 18
          },
          "dated": {
            "type": "boolean",
            "default": false,
            "description": "Print a small \"Signed <date>\" caption under the signature."
          },
          "flatten": {
            "type": "boolean",
            "default": true,
            "description": "Flatten form fields into the page so filled-in values cannot be edited after signing."
          }
        },
        "additionalProperties": false
      },
      "Options-sign-pdf-certified": {
        "title": "Certify PDF (digital signature) options",
        "type": "object",
        "properties": {
          "p12": {
            "type": "string",
            "format": "byte",
            "description": "Your PKCS#12 (.p12/.pfx) certificate, base64. Used for this request only and never stored."
          },
          "passphrase": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "location": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "contactInfo": {
            "type": "string"
          }
        },
        "required": [
          "p12"
        ],
        "additionalProperties": false
      },
      "FileResult": {
        "type": "object",
        "required": [
          "outputs",
          "filenames",
          "contentType"
        ],
        "properties": {
          "outputs": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "byte"
            },
            "description": "Result file(s), base64-encoded. split-pdf and pdf-to-jpg return several."
          },
          "filenames": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "A suggested filename per output, same order."
          },
          "contentType": {
            "type": "string",
            "description": "MIME type of the outputs.",
            "examples": [
              "application/pdf",
              "image/jpeg"
            ]
          }
        }
      },
      "HostedPdfResult": {
        "type": "object",
        "required": [
          "tool",
          "pdfUrl",
          "contentType"
        ],
        "description": "Returned by the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf).",
        "properties": {
          "tool": {
            "type": "string"
          },
          "pdfUrl": {
            "type": "string",
            "format": "uri",
            "description": "Signed download URL for the rendered PDF; valid for about a day."
          },
          "contentType": {
            "type": "string",
            "const": "application/pdf"
          }
        }
      },
      "KeyCheck": {
        "type": "object",
        "required": [
          "ok",
          "scopes"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable message."
          },
          "code": {
            "type": "string",
            "description": "Machine-readable code — branch on this.",
            "examples": [
              "invalid-argument",
              "unauthorized",
              "forbidden",
              "needs_card",
              "insufficient_balance",
              "quota",
              "over-crop",
              "no-fields-matched",
              "not-implemented",
              "unavailable",
              "error"
            ]
          },
          "resetAt": {
            "type": "integer",
            "description": "On `quota`: when the limit resets (epoch ms)."
          },
          "billing_url": {
            "type": "string",
            "format": "uri",
            "description": "On 402 and trial-allowance 429s: where to add a card or top up."
          },
          "hint": {
            "type": "string"
          }
        }
      }
    }
  },
  "paths": {
    "/v1/process": {
      "get": {
        "operationId": "verifyKey",
        "tags": [
          "PDF"
        ],
        "summary": "Check an API key",
        "description": "Validate the key and list its scopes. Runs nothing and is never billed — use it as a connection test.",
        "responses": {
          "200": {
            "description": "The key is valid and has `pdf:run`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeyCheck"
                },
                "example": {
                  "ok": true,
                  "scopes": [
                    "pdf:run"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "missing or invalid API key",
                  "code": "unauthorized"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the `pdf:run` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "key lacks pdf:run scope",
                  "code": "forbidden"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "process",
        "tags": [
          "PDF"
        ],
        "summary": "Run a PDF tool",
        "description": "Run one tool over the supplied file(s) and return the result(s). Metered: one billable operation per successful call. Stateless and safe to retry.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "x-mcp-annotations": {
          "idempotentHint": true,
          "destructiveHint": false
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tool"
                ],
                "properties": {
                  "tool": {
                    "type": "string",
                    "enum": [
                      "merge-pdf",
                      "split-pdf",
                      "remove-pages",
                      "extract-pages",
                      "organize-pdf",
                      "rotate-pdf",
                      "page-numbers",
                      "watermark-pdf",
                      "crop-pdf",
                      "fill-pdf-form",
                      "jpg-to-pdf",
                      "compress-pdf",
                      "pdf-to-word",
                      "pdf-to-jpg",
                      "word-to-pdf",
                      "ocr-pdf",
                      "excel-to-pdf",
                      "powerpoint-to-pdf",
                      "pdf-to-excel",
                      "pdf-to-powerpoint",
                      "pdf-to-pdfa",
                      "repair-pdf",
                      "compare-pdf",
                      "redact-pdf",
                      "txt-to-pdf",
                      "rtf-to-pdf",
                      "odt-to-pdf",
                      "html-to-pdf",
                      "url-to-pdf",
                      "markdown-to-pdf",
                      "email-to-pdf",
                      "protect-pdf",
                      "unlock-pdf",
                      "sign-pdf",
                      "sign-pdf-certified"
                    ],
                    "description": "The tool to run."
                  },
                  "options": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Tool-specific options; `*` marks a required key. Typed per-tool schemas are under `components.schemas.Options-<tool>`.\n\n- `merge-pdf`: none\n- `split-pdf`: ranges, everyN\n- `remove-pages`: pages*\n- `extract-pages`: pages*\n- `organize-pdf`: order*\n- `rotate-pdf`: degrees, pages\n- `page-numbers`: position, start, fontSize, margin\n- `watermark-pdf`: text*, opacity, fontSize, color\n- `crop-pdf`: top, bottom, left, right, pages\n- `fill-pdf-form`: fields*, flatten\n- `jpg-to-pdf`: margin, pageSize\n- `compress-pdf`: quality\n- `pdf-to-word`: none\n- `pdf-to-jpg`: dpi, quality\n- `word-to-pdf`: ext\n- `ocr-pdf`: lang, force\n- `excel-to-pdf`: ext\n- `powerpoint-to-pdf`: ext\n- `pdf-to-excel`: none\n- `pdf-to-powerpoint`: none\n- `pdf-to-pdfa`: none\n- `repair-pdf`: none\n- `compare-pdf`: none\n- `redact-pdf`: boxes*, dpi\n- `txt-to-pdf`: none\n- `rtf-to-pdf`: none\n- `odt-to-pdf`: none\n- `html-to-pdf`: html*, paper\n- `url-to-pdf`: url*, paper\n- `markdown-to-pdf`: html*, paper\n- `email-to-pdf`: html*, paper\n- `protect-pdf`: password*, ownerPassword\n- `unlock-pdf`: password*\n- `sign-pdf`: type, text, image, page, x, y, width, height, fontSize, dated, flatten\n- `sign-pdf-certified`: p12*, passphrase, reason, location, name, contactInfo"
                  },
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "byte"
                    },
                    "description": "Input file(s), base64-encoded. Required for every tool except the render tools (html-to-pdf, url-to-pdf, markdown-to-pdf, email-to-pdf). Multi-file tools (merge-pdf, jpg-to-pdf, compare-pdf) take several, in order."
                  }
                },
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ProcessRequest-merge-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-split-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-remove-pages"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-extract-pages"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-organize-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-rotate-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-page-numbers"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-watermark-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-crop-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-fill-pdf-form"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-jpg-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-compress-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-pdf-to-word"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-pdf-to-jpg"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-word-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-ocr-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-excel-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-powerpoint-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-pdf-to-excel"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-pdf-to-powerpoint"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-pdf-to-pdfa"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-repair-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-compare-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-redact-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-txt-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-rtf-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-odt-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-html-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-url-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-markdown-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-email-to-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-protect-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-unlock-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-sign-pdf"
                  },
                  {
                    "$ref": "#/components/schemas/ProcessRequest-sign-pdf-certified"
                  }
                ],
                "discriminator": {
                  "propertyName": "tool",
                  "mapping": {
                    "merge-pdf": "#/components/schemas/ProcessRequest-merge-pdf",
                    "split-pdf": "#/components/schemas/ProcessRequest-split-pdf",
                    "remove-pages": "#/components/schemas/ProcessRequest-remove-pages",
                    "extract-pages": "#/components/schemas/ProcessRequest-extract-pages",
                    "organize-pdf": "#/components/schemas/ProcessRequest-organize-pdf",
                    "rotate-pdf": "#/components/schemas/ProcessRequest-rotate-pdf",
                    "page-numbers": "#/components/schemas/ProcessRequest-page-numbers",
                    "watermark-pdf": "#/components/schemas/ProcessRequest-watermark-pdf",
                    "crop-pdf": "#/components/schemas/ProcessRequest-crop-pdf",
                    "fill-pdf-form": "#/components/schemas/ProcessRequest-fill-pdf-form",
                    "jpg-to-pdf": "#/components/schemas/ProcessRequest-jpg-to-pdf",
                    "compress-pdf": "#/components/schemas/ProcessRequest-compress-pdf",
                    "pdf-to-word": "#/components/schemas/ProcessRequest-pdf-to-word",
                    "pdf-to-jpg": "#/components/schemas/ProcessRequest-pdf-to-jpg",
                    "word-to-pdf": "#/components/schemas/ProcessRequest-word-to-pdf",
                    "ocr-pdf": "#/components/schemas/ProcessRequest-ocr-pdf",
                    "excel-to-pdf": "#/components/schemas/ProcessRequest-excel-to-pdf",
                    "powerpoint-to-pdf": "#/components/schemas/ProcessRequest-powerpoint-to-pdf",
                    "pdf-to-excel": "#/components/schemas/ProcessRequest-pdf-to-excel",
                    "pdf-to-powerpoint": "#/components/schemas/ProcessRequest-pdf-to-powerpoint",
                    "pdf-to-pdfa": "#/components/schemas/ProcessRequest-pdf-to-pdfa",
                    "repair-pdf": "#/components/schemas/ProcessRequest-repair-pdf",
                    "compare-pdf": "#/components/schemas/ProcessRequest-compare-pdf",
                    "redact-pdf": "#/components/schemas/ProcessRequest-redact-pdf",
                    "txt-to-pdf": "#/components/schemas/ProcessRequest-txt-to-pdf",
                    "rtf-to-pdf": "#/components/schemas/ProcessRequest-rtf-to-pdf",
                    "odt-to-pdf": "#/components/schemas/ProcessRequest-odt-to-pdf",
                    "html-to-pdf": "#/components/schemas/ProcessRequest-html-to-pdf",
                    "url-to-pdf": "#/components/schemas/ProcessRequest-url-to-pdf",
                    "markdown-to-pdf": "#/components/schemas/ProcessRequest-markdown-to-pdf",
                    "email-to-pdf": "#/components/schemas/ProcessRequest-email-to-pdf",
                    "protect-pdf": "#/components/schemas/ProcessRequest-protect-pdf",
                    "unlock-pdf": "#/components/schemas/ProcessRequest-unlock-pdf",
                    "sign-pdf": "#/components/schemas/ProcessRequest-sign-pdf",
                    "sign-pdf-certified": "#/components/schemas/ProcessRequest-sign-pdf-certified"
                  }
                }
              },
              "examples": {
                "rotate": {
                  "summary": "Rotate every page 90°",
                  "value": {
                    "tool": "rotate-pdf",
                    "options": {
                      "degrees": 90
                    },
                    "files": [
                      "JVBERi0xLjQK"
                    ]
                  }
                },
                "merge": {
                  "summary": "Merge two PDFs",
                  "value": {
                    "tool": "merge-pdf",
                    "files": [
                      "JVBERi0xLjQK",
                      "JVBERi0xLjcK"
                    ]
                  }
                },
                "extract": {
                  "summary": "Keep pages 1–3 and 5",
                  "value": {
                    "tool": "extract-pages",
                    "options": {
                      "pages": "1-3,5"
                    },
                    "files": [
                      "JVBERi0xLjQK"
                    ]
                  }
                },
                "watermark": {
                  "summary": "Stamp DRAFT across every page",
                  "value": {
                    "tool": "watermark-pdf",
                    "options": {
                      "text": "DRAFT",
                      "opacity": 0.2
                    },
                    "files": [
                      "JVBERi0xLjQK"
                    ]
                  }
                },
                "compress": {
                  "summary": "Compress for screen",
                  "value": {
                    "tool": "compress-pdf",
                    "options": {
                      "quality": "screen"
                    },
                    "files": [
                      "JVBERi0xLjQK"
                    ]
                  }
                },
                "htmlToPdf": {
                  "summary": "Render HTML (no files)",
                  "value": {
                    "tool": "html-to-pdf",
                    "options": {
                      "html": "<h1>Invoice #42</h1>",
                      "paper": "A4"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Processed. File tools return `FileResult`; render tools return `HostedPdfResult`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/FileResult"
                    },
                    {
                      "$ref": "#/components/schemas/HostedPdfResult"
                    }
                  ]
                },
                "examples": {
                  "file": {
                    "summary": "A file tool",
                    "value": {
                      "outputs": [
                        "JVBERi0xLjcK"
                      ],
                      "filenames": [
                        "rotate-pdf.pdf"
                      ],
                      "contentType": "application/pdf"
                    }
                  },
                  "hosted": {
                    "summary": "A render tool",
                    "value": {
                      "tool": "html-to-pdf",
                      "pdfUrl": "https://storage.googleapis.com/mostly-pdf-files/render/outputs/3f2a9c.pdf?X-Goog-Signature=abc123",
                      "contentType": "application/pdf"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid argument — unknown tool, no files, or options the tool rejects.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unknown tool",
                  "code": "invalid-argument"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "missing or invalid API key",
                  "code": "unauthorized"
                }
              }
            }
          },
          "402": {
            "description": "Payment required — no card on file (`needs_card`) or the wallet is too low (`insufficient_balance`). Follow `billing_url`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Your Mostly Tiny wallet balance is too low for this operation.",
                  "code": "insufficient_balance",
                  "billing_url": "https://id.mostlytiny.io/billing"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the `pdf:run` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "key lacks pdf:run scope",
                  "code": "forbidden"
                }
              }
            }
          },
          "413": {
            "description": "Input too large for the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "files too large",
                  "code": "too-large"
                }
              }
            }
          },
          "422": {
            "description": "The input is valid JSON but the operation cannot apply to this file — e.g. crop margins larger than the page (`over-crop`) or no matching form fields (`no-fields-matched`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "crop margins consume the whole of page 1",
                  "code": "over-crop"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or trial allowance reached. Keys billed from a funded wallet have no per-key request cap; throughput is bounded by concurrency (requests over ~20 in flight queue briefly). Callers on the free trial allowance (a Mostly Tiny identity with no card on file, e.g. via the MCP) get 60 requests/minute plus a small daily cap per conversion tool (5–20/day). Over a limit you get `429` with `code: \"quota\"`, a `resetAt` timestamp and a `Retry-After` header.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "daily limit reached for this tool",
                  "code": "quota",
                  "resetAt": 1767225600000,
                  "billing_url": "https://id.mostlytiny.io/billing"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected failure. Safe to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "internal error",
                  "code": "error"
                }
              }
            }
          },
          "501": {
            "description": "The tool needs the conversion service, which is not enabled on this deployment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conversion service not configured",
                  "code": "not-implemented"
                }
              }
            }
          },
          "502": {
            "description": "The wallet could not be charged (billing service error). Retry with the same Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "wallet charge failed",
                  "code": "wallet_error"
                }
              }
            }
          },
          "503": {
            "description": "A downstream engine is temporarily unavailable. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "PDF rendering is not available",
                  "code": "unavailable"
                }
              }
            }
          }
        }
      }
    }
  }
}
