Documentation

RelayPDF API docs

Use this hub to pick the right RelayPDF surface: generate a PDF from HTML, Markdown, a URL, or a published template; screenshot a page; convert Office files; or run PDF tools (merge, protect, stamp, forms). REST, SDKs, and CLI share a bearer key. Hosted MCP uses Clerk login or that same key. Agents should run relaypdf setup and wait for browser approval instead of asking for a pasted key.

Everything is a POST to https://api.relaypdf.com with a bearer key. The same key covers PDFs, screenshots, converts, and the PDF tools.

Authorization: Bearer pdf_live_…

Keys are created in the dashboard and shown once — only a SHA-256 hash is stored, and query-string keys are not accepted. Coding agents should run relaypdf login and wait for approval in the browser instead of asking a human for a key.

Guides

Quickstart

1. Get a key

terminalCLI
# device flow — approve once in the browser
$ npx @relaypdf/cli setup
# writes RELAYPDF_API_KEY to your env file with mode 0600

2. Make your first PDF

curlshell
curl -X POST https://api.relaypdf.com/v1/pdf \
  -H "Authorization: Bearer pdf_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Invoice #1042</h1><p>Total: $1,200.00</p>",
    "filename": "invoice.pdf"
  }' \
  --output invoice.pdf
index.tsNode
import { RelayPDF } from "@relaypdf/sdk";

const client = new RelayPDF({ apiKey: process.env.RELAYPDF_API_KEY });

const pdf = await client.pdf.fromHtml(
  "<h1>Invoice #1042</h1><p>Total: $1,200.00</p>",
  { filename: "invoice.pdf" },
);

await pdf.save("invoice.pdf");
main.pyPython
import os
from relaypdf import RelayPDF

client = RelayPDF(api_key=os.environ["RELAYPDF_API_KEY"])

pdf = client.pdf.from_html(
    "<h1>Invoice #1042</h1><p>Total: $1,200.00</p>",
    filename="invoice.pdf",
)
pdf.save("invoice.pdf")

Official SDKs: npm i @relaypdf/sdk, pip install relaypdf, Composer, NuGet, and Maven. JSON field names match REST. Full surface: Node.js SDK and Python, PHP, C#, Java.

Endpoint reference

All write endpoints require a bearer key and a JSON body. Every generating endpoint also accepts response: "binary" | "url" | "async".

MethodPathJob
POST/v1/pdf/ocrAdd a searchable text layer to scanned PDF pages while retaining pages that already contain text.
POST/v1/pdf/pdfaConvert a PDF to PDF/A-2 archival output, with OCR for scanned pages.
POST/v1/pdf/cropSet the visible crop rectangle on selected PDF pages.
POST/v1/pdf/resizeFit selected pages into a new page size while preserving content aspect ratio.
POST/v1/pdf/repairParse and resave a recoverable PDF into a normalized output.
POST/v1/pdf/optimizeApply lossless stream and object optimization while preserving the document catalog.
POST/v1/pdf/redactRemove matched text or page areas and return an image-only PDF.
POST/v1/pdf/compress-advancedChoose lossless optimization or a lossy PDF compression preset.
POST/v1/pdf/attachmentsReturn embedded PDF attachments in a ZIP with a JSON manifest.
POST/v1/pdf/extract-imagesExport embedded images from selected pages as PNG files in a ZIP.
POST/v1/images/convertConvert image files to PNG, JPEG, WebP, TIFF, or PDF.
POST/v1/emailConvert EML or MSG email into a readable PDF, or extract its attachments.
POST/v1/filesUpload a private input file (up to 100 MiB)
GET/v1/billing/usageInspect reservations and exact job receipts
GET/v1/webhooks/deliveriesInspect signed delivery retries and replay failures
POST/v1/pdfHTML, URL, Markdown, or template → PDF (Chromium)
GET/v1/templatesList stored Handlebars templates
POST/v1/imagesHTML or URL → png / jpeg / webp
POST/v1/pdf/mergeMerge 2–20 PDFs
POST/v1/pdf/extractExtract or split page ranges
POST/v1/pdf/protectPassword-protect (AES-256)
POST/v1/pdf/unlockRemove a user password
POST/v1/pdf/bookmarksAdd outline bookmarks
POST/v1/pdf/rasterPDF pages → png/jpeg (zip if multiple)
POST/v1/pdf/from-imagesPNG/JPEG images → PDF
POST/v1/pdf/stampText or image watermark
POST/v1/pdf/rotateRotate pages (multiple of 90°)
POST/v1/pdf/delete-pagesDelete page ranges
POST/v1/pdf/compressLossless rewrite
POST/v1/pdf/infoPage count and metadata JSON
POST/v1/pdf/textExtract existing text layer (no OCR)
POST/v1/pdf/dataSchema extract or Markdown (AI; vision if empty layer)
POST/v1/pdf/form/fieldsList AcroForm fields
POST/v1/pdf/form/fillFill and flatten form fields
POST/v1/barcodesBarcode or QR image (PNG or SVG)
POST/v1/zipZip named files
POST/v1/convertLibreOffice / wkhtmltopdf conversion
GET/v1/jobs/:idPoll an async job (same API key)
GET/v1/files/:idPublic 24h download (no key)
GET/v1/accountPlan, rate tier, wallet millicents (not billed)
POST/mcpStreamable HTTP MCP — Clerk OAuth or Bearer
GET/healthLiveness — { ok: true }
binary

Default. File bytes with x-relaypdf-id, x-relaypdf-size, and content-disposition headers.

url

JSON with id, status, url, filename, sizeBytes, and expiresAt — a public download good for 24 hours.

async

202 with a pollUrl. Poll GET /v1/jobs/:id until completed or failed, or supply a callbackUrl.

CLI and MCP

Install with npx @relaypdf/cli. Credentials live in ~/.config/relaypdf/credentials.json with mode 0600 and are never printed. See CLI, MCP, and n8n.

relaypdf loginDevice-code flow; opens /cli/authorize
relaypdf setup [--env file]Log in if needed, then write env
relaypdf pdf --html|--url|--markdown|--templateChromium PDF
relaypdf templates list|create|publishStored Handlebars templates
relaypdf image --html|--url [--full-page]Screenshot
relaypdf convert <file> --to pdf|docx|xlsx|html|pngLibreOffice / wkhtml
relaypdf merge a.pdf b.pdf …Merge paths or https URLs
relaypdf extract file.pdf --pages 1-3Extract pages
relaypdf data file.pdf [--schema schema.json]Structured extract or Markdown
relaypdf protect file.pdf --password …Password-protect
relaypdf barcode --type qr --data '…'Barcode or QR
relaypdf jobs get|wait <id>Async job polling
relaypdf mcpLocal stdio MCP; hosted is POST /mcp with Clerk login

Errors are structured JSON

Every failure returns { "error": { "code", "message" } }. Failed requests are never billed. Full table: Errors.

invalid_requestBody failed validation — check field names and types.
payment_requiredWallet balance is empty. Top up or enable auto-reload.
rate_limited429 with Retry-After. Never billed.
account_suspended403 — keys cannot be created or used.
url_not_allowedPrivate, loopback, or metadata hosts are rejected. callbackUrl must be https.
convert_unavailable503 — document worker cold or unreachable. Not billed.

Can't find what you need?

We are happy to review your payload, your page templates, or your whole document pipeline.