Leafwright API

API documentation

API keys belong to an organization project. Use test keys for development and live keys for production traffic.

Authentication

Bearer API keys

Authorization: Bearer lw_test_...

Render

HTML to PDF

curl -X POST https://YOUR_APP_HOST/api/v1/pdfs \
  -H "Authorization: Bearer lw_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "type": "html",
      "html": "<h1>Hello from Leafwright</h1>"
    },
    "options": {
      "format": "A4",
      "print_background": true
    },
    "delivery": {
      "mode": "sync",
      "return": "url"
    },
    "filename": "hello.pdf"
  }'
Use delivery.return to choose the response route:

"url"      store the PDF and return a signed download_url
"metadata" store the PDF and return job/document metadata
"bytes"    return application/pdf bytes directly; requires mode "sync"
HTML rules — validated before rendering (applies to raw HTML and templates):

Supported   full documents (doctype, html, head, meta, title, body, style),
            text, heading, list, table, and layout tags, and <img> with
            base64 data URIs (png, jpeg, gif, webp, svg+xml), relative
            paths, or cid: references. aria-* and data-* attributes pass.

Rejected    <script>, <iframe>, <object>, <embed>, <form>, <link>, inline
            event handlers, external http(s) URLs in src or CSS url(),
            and CSS @import. The renderer never fetches remote assets for
            HTML sources — embed images as data URIs. To capture a public
            web page with its assets, use source type "url" instead.

SVG         Inline <svg> markup is not supported (nor SVG in CSS url()).
            Base64-encode the SVG and embed it via <img>:
            <img src="data:image/svg+xml;base64,..."> — the data URI must
            be base64; URL-encoded SVG data URIs are rejected.

Limits      HTML 250 KB, CSS 120 KB, 200 pages per PDF.

Validation errors are returned in the 400 response body and name the
offending tag, attribute, or URL.

Templates

Create, preview, publish, render

POST /api/v1/templates
PATCH /api/v1/templates/{template_id}
POST /api/v1/templates/{template_id}/preview
POST /api/v1/templates/{template_id}/publish
POST /api/v1/templates/{template_id}/render
POST /api/v1/templates/{template_id}/duplicate
POST /api/v1/templates/{template_id}/archive
POST /api/v1/templates/{template_id}/versions/{version_id}/restore
POST /api/v1/templates/ai/generate
POST /api/v1/templates/{template_id}/validate

Template renders automatically receive project brand data under:
brand.logo_url
brand.primary_color
brand.accent_color
brand.footer_text
brand.disclaimer
brand.support_email
brand.website_url

AI template endpoints enforce prompt safety, per-request token estimates,
daily request limits, and monthly AI token limits by billing plan before
calling AI Gateway.

Archived templates cannot be previewed, published, or rendered. Restore copies
a published version back into the draft, where it can be reviewed and published
as a new immutable version.

Brand

Project document defaults

PATCH /api/v1/dashboard/brand
Authorization: Bearer <supabase_access_token>

{
  "project_id": "proj_...",
  "logo_url": "https://cdn.example.com/logo.png",
  "primary_color": "#14211b",
  "accent_color": "#c87845",
  "footer_text": "Generated by Acme",
  "disclaimer": "Confidential document.",
  "support_email": "support@example.com",
  "website_url": "https://example.com"
}

POST /api/v1/dashboard/brand/upload-url
POST /api/v1/dashboard/brand/references
GET /api/v1/dashboard/brand/references?project_id=proj_...

Webhooks

Render events

POST /api/v1/dashboard/webhooks
Authorization: Bearer <supabase_access_token>

{
  "project_id": "proj_...",
  "url": "https://example.com/leafwright/webhook",
  "events": ["render.succeeded", "render.failed"]
}

Webhook deliveries include x-leafwright-event, x-leafwright-timestamp,
and x-leafwright-signature headers.

POST /api/v1/dashboard/webhooks/deliveries/{delivery_id}/retry
Authorization: Bearer <supabase_access_token>

GET or POST /api/v1/cron/webhooks/retry
Authorization: Bearer <cron_secret>

Key rotation

Rotate without sharing secrets twice

POST /api/v1/api-keys/{key_id}/rotate
Authorization: Bearer <supabase_access_token>

Response includes a one-time replacement key and revokes the previous key.

Billing

Plans and overages

POST /api/v1/billing/checkout
Authorization: Bearer <supabase_access_token>

{
  "org_id": "org_...",
  "plan_slug": "starter"
}

Paid plans can include metered overages. Free plans remain hard-capped.