Skip to content

Quickstart: your first PDF

From zero to a rendered PDF in three steps.

1. Get an API key

  1. Sign up at app.kikidoc.dev (free — 250 PDFs/month, no card).
  2. Go to API keys → Create.
  3. Copy the key — it's shown once. Keep it secret; it's like a password.

Every request authenticates with that key in the X-API-Key header.

2. Render a PDF

export KIKIDOC_API_KEY="kd_your_key_here"

curl -X POST https://api.kikidoc.dev/pdf/v1/html \
  -H "X-API-Key: $KIKIDOC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html": "<h1>Invoice #1024</h1><p>Thanks for your business.</p>"}' \
  --output invoice.pdf
import requests

resp = requests.post(
    "https://api.kikidoc.dev/pdf/v1/html",
    headers={"X-API-Key": "kd_your_key_here"},
    json={"html": "<h1>Invoice #1024</h1><p>Thanks for your business.</p>"},
)
resp.raise_for_status()
open("invoice.pdf", "wb").write(resp.content)
const resp = await fetch("https://api.kikidoc.dev/pdf/v1/html", {
  method: "POST",
  headers: {
    "X-API-Key": "kd_your_key_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ html: "<h1>Invoice #1024</h1><p>Thanks!</p>" }),
});
const blob = await resp.blob(); // the PDF bytes

By default the response is the PDF bytes (Content-Type: application/pdf). Open invoice.pdf — that's it.

3. Add data (optional)

Your HTML can contain {{ variables }} filled from a data object — handy when the HTML comes from a template string:

curl -X POST https://api.kikidoc.dev/pdf/v1/html \
  -H "X-API-Key: $KIKIDOC_API_KEY" -H "Content-Type: application/json" \
  -d '{
        "html": "<h1>Invoice {{ number }}</h1><p>Total: {{ total }}</p>",
        "data": { "number": "1024", "total": "$49.00" }
      }' \
  --output invoice.pdf

The templating is sandboxed Jinja2 — {{ var }}, {% if %}, {% for %}. See Templates + data to store templates and call them by name.

Next steps

Errors at a glance

401 = missing/invalid API key · 403 = your tier can't use that endpoint (e.g. stored templates are Pro) · 429 = monthly quota or per-minute rate limit reached. See Pricing & limits.