# makesPDF > Beautiful PDFs from your data. Send JSON or Markdown, get a compliant PDF > back. Designed to be driven by AI agents — there is a dedicated skill file > that teaches any LLM how to author PDF templates. > **URLs in this document are HTTP URLs, not filesystem paths.** If you need > to re-fetch the skill file later, use a web fetch / HTTP tool — do not > call your filesystem `Read` tool with `/skills/pdf-template-author.md`. > The full URL is always `https://makespdf.com/skills/pdf-template-author.md`. ## Quick links for AI agents - AI & Agent landing (production): https://ai.makespdf.com/ - Documentation index: https://makespdf.com/docs - Skill file (single source of truth for the template DSL): https://makespdf.com/skills/pdf-template-author.md - Companion skills (fetch on demand from the same origin): - Authentication / OAuth device flow: https://makespdf.com/skills/pdf-auth.md - API endpoints (preview / render / validate): https://makespdf.com/skills/pdf-api.md - Per-doc-type recipes: https://makespdf.com/skills/pdf-recipes.md - Custom font uploads: https://makespdf.com/skills/pdf-fonts.md - Server-side application integration (API key, error handling, per-language snippets): https://makespdf.com/skills/pdf-integration.md - API reference: https://makespdf.com/docs/api - Agent setup walkthrough: https://makespdf.com/docs/ai-setup - Model benchmark digest (which LLMs author makesPDF templates well, with failing-DSL snippets for diagnosis): https://makespdf.com/ai/benchmark.md Structured companion (same data, JSON shape, no DSL snippets): https://makespdf.com/ai/benchmark.json - CLI (`@makespdf/cli` on npm): https://github.com/makesPDF/makespdf-cli ## Authentication (read this first) All /api/v1/* endpoints need a Bearer token by default. Two carve-outs exist (full policy at https://makespdf.com/docs/api): the public veraPDF utility at `POST /api/v1/pdf/validate` and — when the operator enables the `promo:md_anonymous_enabled` flag — `POST /api/v1/md` itself. The `/md` carve-out is rate-limited per IP (60/hour, 200/day, 20 pages per render) and intended for low-volume callers (IDE plugins, quick scripts, demos). Authenticate anyway for higher limits, artifact capture, and the rest of the API. Stale / invalid Bearer tokens always 401 — the server never silently downgrades a failed auth attempt to anonymous. There are two paths to get a Bearer token; **AI agents should use the device flow — never ask the user for a password or API key directly, and never register an account or sign in on the user's behalf.** If the device approval page (https://makespdf.com/device?code=…) shows a login screen when you open it in a browser MCP, you are done with the browser. Hand control back to the user so they can sign in themselves — the account owner is the human whose credits get charged, and the approval must be their decision, not yours. Do not fill the registration form, do not auto-submit credentials you scraped from earlier messages. Just poll /api/v1/device/token and wait. ### Device authorization flow (preferred for AI agents and CLIs) OAuth 2.0 RFC 8628. The user authenticates in their browser; you receive a token without ever touching their credentials. 1. `POST https://makespdf.com/api/v1/device/code` (no auth required, optional body `{ "client_name": "My Agent" }`). Response: ```json { "device_code": "", "user_code": "ABCD-1234", "verification_uri": "https://makespdf.com/device", "verification_uri_complete": "https://makespdf.com/device?code=ABCD-1234", "expires_in": 600, "interval": 5 } ``` 2. **Tell the user:** "Open https://makespdf.com/device?code=ABCD-1234 in your browser and approve this device." Show both the URL and the user_code so they can verify it matches what's shown in the browser. 3. **Wait for the user to approve**, then make **one** request: `POST https://makespdf.com/api/v1/device/token` with `{ "device_code": "..." }`. On success you get HTTP 200 `{ "access_token": "mpdf_...", "token_type": "Bearer" }`. Save the access_token; that's the user's API key. *Automated harnesses* with no interactive user (CI, scripted demos) may fall back to polling every `interval` seconds — HTTP 400 `{ "error": "authorization_pending" }` means keep waiting. But when a human is present, ask them to confirm before calling. 4. Use `Authorization: Bearer ` on every subsequent request. ### API key (for humans setting up CI or scripting their own account) Generate at https://makespdf.com/settings/api-keys. Same Bearer token format. ## Quickstart: I have JSON data, I want a PDF Three paths, cheapest first. All require a Bearer token (see Authentication above). 1. **Markdown → PDF** (simplest, sub-second, no AI call). Format your data as GitHub Flavored Markdown, POST to `/api/v1/md`: ``` curl -X POST https://makespdf.com/api/v1/md \ -H "Authorization: Bearer $MAKESPDF_API_KEY" \ -H "Content-Type: application/json" \ -d '{"markdown": "# Invoice #123\n\n| Item | Price |\n|---|---|\n| Widget | $10 |"}' \ -o invoice.pdf ``` 2. **DSL → PDF** (custom layouts, sub-second, no AI call). Read the skill file, write a short JavaScript DSL snippet, POST to `/api/v1/preview`: ``` curl -X POST https://makespdf.com/api/v1/preview \ -H "Authorization: Bearer $MAKESPDF_API_KEY" \ -H "Content-Type: application/json" \ -d '{"dsl": "const template = doc(...); const sampleData = {...};", "data": {...}}' \ -o invoice.pdf ``` 3. **AI-generated template** (one-shot, ~20s). If the agent can't author a template itself, POST to `/api/v1/render` with a document type and data and the server will generate + render in one call. Details at https://makespdf.com/docs/api. **Always read the skill file first for path 2.** It is ~25KB and teaches the full DSL, document recipes (invoice, receipt, quote, report, CV, etc.), style properties, and worked examples. ## Endpoints - POST /api/v1/device/code — Start OAuth device flow (no auth required) - POST /api/v1/device/token — Poll for access_token (no auth required) - POST /api/v1/md — Markdown to PDF (no AI call, sub-second; anonymous-callable when promo:md_anonymous_enabled is set) - POST /api/v1/preview — Render a DSL template with data - POST /api/v1/render — One-shot AI generation + render (~20s) - POST /api/v1/md/validate — Pre-flight accessibility check for markdown - POST /api/v1/preview/validate — Pre-flight structure + a11y check for templates All /api/v1/* endpoints except the device-flow pair require Bearer token (API key) or a session cookie. Unauthenticated calls return a 401 whose body includes a `device_authorization` block with the exact steps above, plus `agent_guide` and `skill` URLs so agents can self-recover. ## Pay-per-call (x402) — for agents without an account Agents and wallets that don't have a Bearer token can pay per request in USDC on Base mainnet. No signup, no API key, no session — just a signed EIP-3009 authorization on each call. This implements the [x402 spec](https://www.x402.org/) v2 wire format. **Pricing (production, Base mainnet `eip155:8453`):** - POST /api/v1/md — $0.01 per render (USDC, 6 decimals → atomic `10000`) - POST /api/v1/render — $0.02 per render (inline `{ dsl, data }` body only; `{ templateId }` is not available to wallet callers in v1) `/api/v1/preview`, validation, and the template / font / library endpoints are not paid-callable — use a Bearer token for those. **Flow:** 1. Send the request with no auth. Server replies HTTP **402 Payment Required** with a JSON body that advertises what to pay: ```json { "x402Version": 2, "error": "Payment required", "resource": { "url": "https://makespdf.com/api/v1/md", "description": "Convert GitHub-flavoured Markdown to a tagged, accessible PDF.", "mimeType": "application/pdf", "serviceName": "makesPDF", "tags": ["pdf", "markdown", "accessibility", "pdf-ua", "pdf-a"] }, "accepts": [ { "scheme": "exact", "network": "eip155:8453", "amount": "10000", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "payTo": "0x9bB96Acb3fD11D8949D862736B96e7e12D319DC4", "maxTimeoutSeconds": 60, "extra": { "name": "USD Coin", "version": "2" } } ], "extensions": { "bazaar": { "info": {}, "schema": {} } }, "docs": "https://makespdf.com/docs/api", "agent_guide": "https://makespdf.com/llms.txt", "skill": "https://makespdf.com/skills/pdf-template-author.md" } ``` This is the x402 **v2** body shape: a top-level `resource` object, an `accepts` array of payment requirements, and an `extensions.bazaar` discovery object (abbreviated above — it carries the endpoint's input `info` + JSON `schema`). 2. Build an EIP-3009 `transferWithAuthorization` payload paying `payTo` the advertised `amount` of the advertised `asset`, sign it, base64-encode the JSON `PaymentPayload`, and resend the original request with header `PAYMENT-SIGNATURE: `. Echo the 402's `resource` and `extensions` back in the payload so the settlement is cataloged for discovery. 3. Server verifies + settles via the Coinbase CDP facilitator (`https://api.cdp.coinbase.com/platform/v2/x402`), then renders. Response is the PDF bytes plus header `X-PAYMENT-RESPONSE` carrying the settlement receipt. 4. **Idempotency.** Resending the same `PAYMENT-SIGNATURE` within 5 minutes returns the cached PDF bytes verbatim with header `X-Idempotent-Replay: 1`. No double settlement, safe to retry on network failure. 5. **Refunds.** If verification succeeds but rendering fails, the payment is marked `failed` and processed off-band as a refund to the payer wallet. No automatic retry. **Rate limits.** Wallet callers are rate-limited by payer address (`wallet:0x…`) at the same per-endpoint thresholds as authed callers. **Watermark.** Paid renders are watermark-free by construction. **Discovery (for indexes and crawlers).** This endpoint set is also auto-discoverable via Coinbase Bazaar; no submission step is required. For the full spec, scheme negotiation, and SDK pointers see [x402.org](https://www.x402.org/).