Integrate makesPDF into your app

Drop-in “AI builds PDF templates in my app” without rebuilding the authoring loop. Three copy-paste recipes, each under 60 seconds. Everything below couples over plain REST with your own API key — bring your own LLM key, pay us only for the pixels.

Which recipe do you need?

You want…UseLives
Production PDFs from your backend with data you already haveRecipe 1: backend renderThis page
Your existing agent (Claude Code, Cursor, Desktop) authoring templates with schema-validated tools, zero codeRecipe 2: hosted MCPThis page + MCP server
Authoring tools embedded in your own app next to your own model callsRecipe 3: Vercel AI SDK tools (REST shim)Paste today; ships as @makespdf/sdk next

A prebuilt chat widget (<MakespdfChat>) is deferred until integrators ask for it — the three recipes above cover the backend, agent, and in-app cases without one. Full backend detail (error table, retries, versioning, delivery patterns) lives in the application-integration skill.

Recipe 1: render production PDFs from your backend~60 seconds

Save the template once, render it many times with different data. Billing is 1 credit per 10 pages on success; every failure path deducts zero. Rate limit: 2,000 renders/hour per caller.

Step 1: save the template (one time)

# Write your DSL to a file, then save it and capture the templateId jq -n --rawfile dsl template.js --arg name "Invoice v1" \ '{ dsl: $dsl, name: $name }' | curl -sX POST https://makespdf.com/api/v1/templates \ -H "Authorization: Bearer $MAKESPDF_API_KEY" \ -H "Content-Type: application/json" \ --data-binary @- # -> { "templateId": "11111111-2222-...", "name": "Invoice v1", "createdAt": ... } # Store it as config, e.g. MAKESPDF_INVOICE_TEMPLATE_ID=11111111-2222-...

Step 2: render with real data (every request)

export async function renderInvoice(data: unknown): Promise<Uint8Array> { const res = await fetch("https://makespdf.com/api/v1/render", { method: "POST", headers: { Authorization: `Bearer ${process.env.MAKESPDF_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ templateId: process.env.MAKESPDF_INVOICE_TEMPLATE_ID, data, }), }); if (!res.ok) { throw new Error(`makesPDF ${res.status}: ${await res.text()}`); } return new Uint8Array(await res.arrayBuffer()); }

Only retry on 429 or 5xx (max 3 attempts, respect Retry-After); never blanket-retry 400/401/402/404. 402 means out of credits — top up at Settings → Billing. Full error table and retry helper in the integration skill.

Recipe 2: give your agent template powers via hosted MCP~60 seconds

No code. Register the hosted MCP server once and the agent gets schema-validated tools for validating, previewing, and saving DSL templates — plus the skill file as a fetchable resource. Authoring tools are free; only render_template (and render_markdown) are billed, at the same 1 credit per 10 pages as REST.

Step 1: create an API key

Create one at Settings → API Keys. The MCP endpoint uses the same Bearer auth as every other /api/v1/* endpoint.

Step 2: register the server (Claude Code)

claude mcp add --transport http makespdf \ https://makespdf.com/api/v1/mcp \ --header "Authorization: Bearer mpdf_your_api_key"

Claude Desktop and Cursor use the same URL and header in their JSON config — see MCP server for the per-client files.

Step 3: verify, then prompt

curl -X POST https://makespdf.com/api/v1/mcp \ -H "Authorization: Bearer mpdf_your_api_key" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # -> JSON listing all ten tools (validate_dsl, render_dsl_preview, ...)
Create an invoice template for Acme Corp with 3 line items, save it, and show me the preview PDF.

The agent reads the skill resource, drafts DSL, calls validate_dsl, fixes issues, calls render_dsl_preview (free, watermarked), then save_template. Discovery methods answer without a key; tools/call needs the Bearer token.

Recipe 3: embed authoring tools in your app (Vercel AI SDK)~60 seconds

For custom apps that already call an LLM: wrap the same REST endpoints as tools your model can call, and fetch the skill live with a vendored fallback. REST-only coupling — no shared imports, no proxy LLM, no billing passthrough. BYOK only: the integrator supplies their own model key; MAKESPDF_API_KEY pays for renders alone. This shim is the inline precursor to @makespdf/sdk (MakespdfClient + tools() + getSkill(), OIDC-published) — same shape, pasteable today.

Step 1: live skill fetch with offline fallback

// skill.ts — fetch the canonical skill live; fall back to the vendored copy. const SKILL_URL = "https://makespdf.com/skills/pdf-template-author.md"; let cached: string | null = null; export async function getSkill(fallback?: string): Promise<string> { if (cached) return cached; try { const res = await fetch(SKILL_URL); if (!res.ok) throw new Error(`skill fetch ${res.status}`); cached = await res.text(); return cached; } catch (err) { // Offline / deploy-frozen fallback: vendor once with // curl -o pdf-template-author.md https://makespdf.com/skills/pdf-template-author.md // and pass its contents as `fallback`. if (fallback) { cached = fallback; return cached; } throw err; } }

Step 2: REST-backed tools for your model

// makespdf-tools.ts — REST-only tools() shim (BYOK; no proxy, no billing passthrough). import { tool } from "ai"; import { z } from "zod"; const dataSchema = z.record(z.string(), z.unknown()).optional(); export function makespdfTools(opts: { apiKey: string; baseUrl?: string }) { const base = (opts.baseUrl ?? "https://makespdf.com").replace(/\/$/, ""); const headers = { Authorization: `Bearer ${opts.apiKey}`, "Content-Type": "application/json", }; const post = async (path: string, body: unknown) => { const res = await fetch(`${base}${path}`, { method: "POST", headers, body: JSON.stringify(body), }); if (!res.ok) throw new Error(`makesPDF ${res.status}: ${await res.text()}`); return res; }; return { validate_dsl: tool({ description: "Catalog + accessibility check for a DSL script. Cheap, no render.", inputSchema: z.object({ dsl: z.string(), data: dataSchema }), execute: async ({ dsl, data }) => post("/api/v1/preview/validate", { dsl, data }).then((r) => r.json()), }), render_dsl_preview: tool({ description: "Free watermarked preview PDF. Returns { pageCount, pdfBase64 }.", inputSchema: z.object({ dsl: z.string(), data: dataSchema }), execute: async ({ dsl, data }) => { const res = await post("/api/v1/preview", { dsl, data }); const buf = Buffer.from(await res.arrayBuffer()); return { pageCount: Number(res.headers.get("x-pages") ?? 0), pdfBase64: buf.toString("base64"), }; }, }), render_template: tool({ description: "BILLED (1 credit / 10 pages). Render a saved templateId to a real PDF.", inputSchema: z.object({ templateId: z.string(), data: dataSchema }), execute: async ({ templateId, data }) => { const res = await post("/api/v1/render", { templateId, data }); const buf = Buffer.from(await res.arrayBuffer()); return { pageCount: Number(res.headers.get("x-pages") ?? 0), creditsDeducted: Number(res.headers.get("x-credits-deducted") ?? 0), pdfBase64: buf.toString("base64"), }; }, }), }; }

Step 3: wire it next to your model call

import { generateText } from "ai"; import { getSkill } from "./skill"; import { makespdfTools } from "./makespdf-tools"; const skill = await getSkill(); // or getSkill(vendoredFallbackText) const { text } = await generateText({ model: YOUR_MODEL, // your key, your account — makesPDF never proxies LLM calls system: skill + "\n\n" + "Use validate_dsl before every preview; only call render_template when the layout is confirmed.", tools: makespdfTools({ apiKey: process.env.MAKESPDF_API_KEY! }), prompt: "Create an invoice template for Acme Corp with 3 line items.", });
Deliberately deferred: proxy-LLM / billing passthrough, Vue/Svelte adapters, and a prebuilt <MakespdfChat> widget. If you need one of these, tell us — demand decides what ships next.

What’s next

  • Application-integration skill — the full backend reference this page compresses: error table, retries, versioning, delivery patterns, per-language snippets.
  • MCP server — the ten hosted tools, per-client registration files, and verify steps.
  • Bring your own AI — skill-only flows and CLI-based authoring when MCP isn’t available.
  • API Reference — the REST endpoints every recipe above wraps.