REST · JSON in, PDF out · OpenAPI 3.1

Documentation

Send a template id and your data, get a print-ready PDF back in the same response. Nothing you send is stored. Every endpoint, field and error is also in the API reference (OpenAPI 3.1 spec).

Quickstart

  1. Get an API key

    At launch: create a free account, confirm your email, then create a key in the dashboard. (Launching soon.) Keys look like pdfk_live_…. Keep them on your server.

  2. Set two variables

    KTAVLY_API_KEY (your key) and, for local testing, KTAVLY_API_URL=http://localhost:8787. The default is https://api.ktavly.com.

  3. POST your data

    The response body is the PDF. Save it, attach it to an email, or stream it to your user.

quickstart.sh
# Render the built-in invoice template and save the PDF.
# On an error, curl exits non-zero and invoice.pdf holds the JSON error body instead (cat it to read why).
curl -sS "${KTAVLY_API_URL:-https://api.ktavly.com}/v1/render" \
  -H "Authorization: Bearer $KTAVLY_API_KEY" \
  -H "Content-Type: application/json" \
  --fail-with-body -o invoice.pdf \
  -d '{
    "template": "invoice",
    "data": {
      "number": "INV-1001", "issueDate": "2026-10-18", "currency": "USD",
      "from": { "name": "Northwind Studio" },
      "to": { "name": "Lumen Analytics" },
      "items": [{ "description": "Design sprint", "quantity": 1, "unitPrice": 6400 }],
      "taxRate": 8.5
    }
  }'

The first four tabs are raw HTTP; the SDK tabs make the same calls through the official clients. Every file lives in snippets/ and the test suite runs it against a local server, so what you copy here is what we test.

Official SDKs pre-release

Typed clients for Node.js / TypeScript (ktavly: ESM + CommonJS, zero dependencies, built on fetch) and Python (ktavly: sync Ktavly and async AsyncKtavly on httpx, fully typed). They are ready but not on npm or PyPI yet; they will be published at launch.

  • render(template, data, options) returns the PDF bytes; renderWithMeta / render_with_meta adds pages, usage and request id; renderStream / render_stream streams it to disk or to your HTTP response.
  • templates.list(), templates.sample(id) and usage().
  • One error class per status: AuthenticationError 401, QuotaExceededError 402, PermissionDeniedError 403, PayloadTooLargeError 413, UnsupportedMediaTypeError 415, ValidationError 422 (with every problem), RateLimitError 429 (with retryAfter).
  • Timeouts, automatic retries with backoff on 429 and 5xx (honouring Retry-After), and your key is never logged.
  • No key yet? new Ktavly({ demo: true }) / Ktavly(demo=True) renders built-in templates through the public demo.

More examples

# Raw HTML → PDF with page numbers and a Hebrew line
curl "$KTAVLY_API_URL/v1/render" \
  -H "Authorization: Bearer $KTAVLY_API_KEY" -H "Content-Type: application/json" \
  -d '{"html":"<h1>Hello</h1><p>שלום עולם</p>",
       "options":{"format":"A4","margin":"15mm","pageNumbers":true,"footer":"Acme Ltd · confidential"}}' \
  -o hello.pdf

# Same request, but get JSON with base64 (handy for Zapier / Make)
curl "$KTAVLY_API_URL/v1/render" -H "Accept: application/json" ...

# Any template with its own sample data
curl -s "$KTAVLY_API_URL/v1/templates/invoice-he/sample" | \
  jq '{template:"invoice-he", data:.}' | \
  curl "$KTAVLY_API_URL/v1/render" -H "Authorization: Bearer $KTAVLY_API_KEY" \
       -H "Content-Type: application/json" -d @- -o invoice-he.pdf

Request body POST /v1/render

FieldTypeDescription
templatestring | objectA built-in template id, or an inline template exported from the editor: {"base":"invoice","styles":{…},"labels":{…},"page":{…}}. Advanced: {"html":"…handlebars…","css":"…","schema":{…}}.
dataobjectYour document data. Validated against the template's JSON Schema; errors come back as 422 validation_failed with a list of problems.
htmlstringInstead of a template: a full HTML document or a fragment. Fonts and print CSS are injected for you. JavaScript does not run.
stylesobjectprimaryColor, accentColor, textColor (#RRGGBB), fontFamily, headingFont, direction (ltr/rtl/auto), locale (e.g. he-IL; drives number, currency and date formats), logoUrl (https or base64 data URL), accentStyle, density.
optionsobjectPage setup, see below.

Page options

OptionExampleNotes
format"A4"A3, A4, A5, Letter, Legal, Tabloid. Or set width + height ("100mm", "4in", "800px").
landscapetrueRotate the page.
margin"12mm" or {"top":"20mm","bottom":"18mm"}Units: mm, cm, in, px.
header / footer"Acme · {page}/{pages}"Text (escaped) or {"html":"…","align":"center"}. Placeholders: {page}, {pages}, {title}. Repeated on every page, RTL-aware.
pageNumbers{"position":"footer","align":"center","format":"{page} / {pages}"}true/false or an object. Defaults to “Page 1 of 3” (or “עמוד 1 מתוך 3” for RTL).
fonts["heebo","frank-ruhl-libre"]Extra embedded fonts for raw HTML: inter, heebo, frank-ruhl-libre, playfair-display, noto-sans-arabic, jetbrains-mono.
filename"invoice-1001.pdf"Sets Content-Disposition. Add ?download=1 to the URL for attachment.
allowRemoteAssetstrueOff by default. When on, public https images, fonts and stylesheets may load. Private and internal addresses are always blocked.

Long tables split across pages cleanly: table headers repeat on every page and rows never break in half. Add class="page-break" to force a new page, or class="keep" to keep a block together.

Templates

Each template ships with a JSON Schema and sample data (see the gallery for previews and sample PDFs). GET /v1/templates lists them; /v1/templates/{id}/schema and /v1/templates/{id}/sample?lang=he return the parts.

Invoice

Itemised invoice with tax, discount, payment details and multi-page item tables.

Hebrew tax invoice

חשבונית מס / קבלה: RTL layout, ע.מ / ח.פ, allocation number, VAT and payments.

Receipt

Payment receipt (A5) with paid amount, method, line items and VAT breakdown.

Business report

Cover summary, KPI cards, bar chart and a long data table whose header repeats on every page.

Certificate

A4 landscape certificate with ornamental border, seal and signatures.

Hebrew & Arabic

Set styles.locale to he-IL or ar (or just send Hebrew/Arabic data with direction: "auto") and the whole document flips: layout, table columns, headers and footers, page numbers. Heebo, Frank Ruhl Libre and Noto Sans Arabic are embedded in every PDF, so text never falls back to boxes. Numbers, amounts and IDs stay left-to-right inside RTL text.

{"template":"invoice-he","data":{"documentType":"tax_invoice_receipt","number":"20261042", …}}

// or any template in Hebrew:
{"template":"invoice","styles":{"locale":"he-IL"},"data":{"currency":"ILS","number":"חש-0087", …}}

Response

200 with Content-Type: application/pdf. Send Accept: application/json to get {"filename","pages","bytes","base64"} instead.

HeaderMeaning
X-PagesNumber of pages in the PDF.
X-Usage-Used / X-Usage-Limit / X-Usage-RemainingYour account's documents this month (UTC calendar month).
X-Usage-Overagetrue when this document was billed as overage.
X-RateLimit-Limit / X-RateLimit-RemainingRequests per minute for your plan.
X-Request-IdQuote this when contacting support. We can look up timing and status, never content.

Usage & limits

GET /v1/usage returns your plan, documents used and remaining this month, overage, per-key usage and a 12-month history. The usage dashboard shows the same data. Only successful renders count.

PlanPricePDFs / monthRequests / minOver the limit
Free$020010Stops with 402
Starter$195,00060$0.005 / PDF (opt-in)
Growth$4920,000120$0.004 / PDF (opt-in)
Scale$9960,000300$0.003 / PDF (opt-in)

Every feature is on every plan, including RTL, custom templates and all integrations.

Errors

Errors are JSON: {"error":{"code","message","details","requestId"}}. Branch on code; messages may change.

StatusCodeMeaning
Loading from /v1/errors…

Privacy: nothing is kept

  • Streamed, not stored. The PDF is generated in memory and written straight into the HTTP response. There is no download URL because there is no file.
  • No template data at rest. Your JSON and HTML live in memory for the duration of the request only. Inline templates are used once and discarded.
  • Isolated renders. Every document renders in a fresh, in-memory browser context with JavaScript disabled and the network closed (unless you allow public https assets).
  • No-retention logs. Logs record metadata only: request id, route, status, timing, page count, template id, key prefix. Never content, never full keys.
  • Hashed keys. API keys are stored as HMAC-SHA256 hashes and shown once.
  • Verified by tests. The test suite renders documents containing a unique marker, then scans temp folders, shared memory, the project and the browser profile, and the logs, to confirm the marker and no new files remain.

No-code integrations

These are step-by-step guides and importable files built on each platform’s generic HTTP module. They are not official listed apps on those platforms yet.

n8n Guide

Import the ready workflow: Webhook → HTTP Request (binary PDF) → respond or email.

integrations/n8n/render-invoice.workflow.json

Make Guide

HTTP “Make a request” module with your key in a header; the PDF arrives as a file for the next module.

integrations/make/README.md

Zapier Guide

Webhooks by Zapier (Custom Request) with Accept: application/json, or the included Zapier CLI app.

integrations/zapier/README.md