spoolpdf

API

HTML or URL to PDF. Sign in, create a key on API keys, then call production https://spoolpdf-api.nandra.dev.

Getting started

  1. Sign in with Google, GitHub, or a magic link.
  2. Create a key on /keys. Copy spool_live_… once.
  3. Send it as Bearer on POST /v1/render.
curl -sS -D - -o out.pdf \
  -X POST https://spoolpdf-api.nandra.dev/v1/render \
  -H "Authorization: Bearer spool_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Hello spoolpdf</h1>"}'

Recipes

HTML → PDF

curl -sS -D - -o out.pdf \
  -X POST https://spoolpdf-api.nandra.dev/v1/render \
  -H "Authorization: Bearer spool_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Hello spoolpdf</h1>"}'

URL → PDF

Public http(s) only. Loopback and private hosts return ssrf_blocked.

curl -sS -D - -o page.pdf \
  -X POST https://spoolpdf-api.nandra.dev/v1/render \
  -H "Authorization: Bearer spool_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/"}'

Margins, header, footer

Header/footer placeholders: {{page}} and {{total}} only.

curl -sS -D - -o letter.pdf \
  -X POST https://spoolpdf-api.nandra.dev/v1/render \
  -H "Authorization: Bearer spool_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Letter</h1>","margin":{"top":"24mm","right":"16mm","bottom":"24mm","left":"16mm"},"header":{"html":"<div>Acme</div>","height":"12mm"},"footer":{"html":"<div>Page {{page}} / {{total}}</div>","height":"12mm"}}'

Trial (no API key)

IP rate-limited (default 5/min). No X-Usage-Count.

curl -sS -D - -o trial.pdf \
  -X POST https://spoolpdf-api.nandra.dev/v1/trial/render \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Trial</h1>"}'

Chat → PDF (MCP)

Connect ChatGPT or Claude without pasting an API key. Open MCP for the URL and steps. Renders use your plan.

Node

npm install @spoolpdf/sdk-node

import { SpoolPdfClient } from "@spoolpdf/sdk-node";
const client = new SpoolPdfClient({ apiKey: process.env.SPOOLPDF_API_KEY });
const pdf = await client.render({ html: "<h1>Hello</h1>" });

PHP

composer require spoolpdf/sdk-php

$pdf = (new Spoolpdf\Sdk\Client(getenv('SPOOLPDF_API_KEY')))
    ->render(['html' => '<h1>Hello</h1>']);

Endpoints

MethodPathAuthSuccess
GET/healthznone{ "ok": true }
POST/v1/renderBearer API keyapplication/pdf
POST/v1/trial/rendernone (IP rate-limited)application/pdf

Render body: exactly one of html or url. Optional format, landscape, print_background, scale/zoom, margin, header, footer. Success headers: X-Request-Id; X-Usage-Count on authenticated render when the usage write succeeds.

Error codes: unauthorized, validation_error, ssrf_blocked, rate_limited, payload_too_large, render_failed, subscription_inactive.

OpenAPI source of truth: repo docs/openapi.yaml.