D DataPDFEngine
Start free

API reference

Complete API reference.

Every endpoint, every payload, every error code. The same reference that powers the in-product playground.

Base URL https://api.datapdfengine.com/api/v1

Authentication

All requests authenticate with a Bearer API key. Keys are scoped to a single organisation, never shown in plaintext after creation, and can be rotated or revoked without code changes — the next request with the old key returns 401.

Tokens start with `pdf_live_…` (production) or `pdf_test_…` (sandbox).

Authorization: Bearer pdf_live_X8s3...e2Qa
  • Server-only — never embed an API key in a browser bundle or mobile binary.
  • Last-used timestamp is updated on every request, visible in your dashboard.
  • Revoke a key from `Settings → API keys`; effective on the next request.
Templates

Templates — the PDF the engine fills

A template is your source PDF plus the labels (named rectangles with coordinates) that mark where values are drawn. Labels are created manually via the visual editor or the `/labels/` bulk-upsert endpoint — they're not auto-detected.

GET /templates/

List all templates in your organisation.

Paginated, sorted by recency. Supports `?search=` for fuzzy name matching.

POST /templates/ multipart/form-data

Upload a new PDF as a template.

Fields

  • name string · required Display name.
  • description string · optional Internal note for your team.
  • file file · required PDF file, up to 25 MB.

Page previews run in the background. `previews_ready` flips to `true` when it's safe to render.

GET /templates/{id}/

Retrieve a template with its labels and page previews.

DELETE /templates/{id}/

Delete the template and its S3 artefacts.

Compilations

Compilations — one rendered PDF

Submit a values map for a template, get a `compilation` resource. Rendering is async: the response is immediate, the rendered PDF arrives in S3 and is exposed via a short-lived `download_url` once status transitions to `done`.

POST /compilations/ application/json

Create a single compilation.

Fields

  • template uuid · required Template to render.
  • name string · optional Human-readable name.
  • values object · required Map of `label_name → value`. Accepts strings, numbers, booleans and null — coerced server-side per field type.

Request body

{
  "template": "3f0e4b2a-21c2-4d34-9c8d-9b0a5d6b3f11",
  "values": {
    "full_name": "Jordan Rivera",
    "effective_date": "2026-06-01",
    "agrees_to_terms": true
  }
}

Response

HTTP/1.1 201 Created
{
  "id": "c2a1...e9",
  "status": "pending",
  "download_url": null,
  "created_at": "2026-05-27T10:13:51Z"
}

Status lifecycle: `pending → running → done | failed`. `download_url` is a pre-signed S3 URL valid for 5 minutes.

GET /compilations/{id}/

Poll a compilation, or fetch its `download_url` once `status == done`.

PATCH /compilations/{id}/

Re-render with new values, or rename the compilation.

Sending `values` triggers a re-render and consumes one quota unit. Sending only `name` is a free metadata edit.

DELETE /compilations/{id}/

Permanently delete the compilation and its rendered PDF from S3.

Batches

Batches — thousands of PDFs in one call

Two entry points: `/batches/json/` for programmatic use, `/batches/upload/` for CSV/XLSX. Both stream rows through a parallel worker pool and produce a single `result.zip` on completion.

POST /batches/json/ application/json

Submit up to 5 000 rows of values inline.

Fields

  • template uuid · required Template to render.
  • rows array · required 1–5000 row objects.
  • completion_webhook_endpoint uuid · optional Saved endpoint to notify on completion.
  • completion_webhook_url url · optional Inline one-shot webhook URL.

Response

HTTP/1.1 202 Accepted
{
  "id": "b1f2...77",
  "source": "json",
  "status": "pending",
  "total": 0,
  "expected_total": 2,
  "succeeded": 0,
  "failed": 0
}

Webhook precedence: saved endpoint → inline URL → org default endpoint. If none is configured, the batch runs without notification.

POST /batches/upload/ multipart/form-data

Submit a CSV or XLSX file (up to 20 MB).

Fields

  • template uuid · required Template to render.
  • file file · required .csv or .xlsx, ≤ 20 MB.
  • column_mapping object · optional JSON map of CSV column → label name.
GET /batches/{id}/

Poll batch progress. `succeeded + failed` reach `expected_total` when finished; `download_url` is non-null at that point.

Share requests

Share requests — let the recipient fill it themselves

Generate a token-protected URL pointing at a hosted compilation form. The recipient opens the link on any device, optionally verifies their email via OTP, fills the form, and submits.

POST /share-requests/

Create a single share request.

Fields

  • template uuid · required Template to expose.
  • recipient_email email · optional If set, we deliver the link by email.
  • verify_email bool · default false Gate submission behind an email-OTP challenge.
  • send_copy_to_recipient bool · default false Auto-CC the final PDF on submit.
  • notify_sender_on_complete bool · default false Email you when the recipient submits.
  • prefill_values object · optional Values you already know.
  • expires_in_days int 1–90 · default 7 Link lifetime.
POST /share-requests/batches/

Bulk-create share requests from a list of recipients.

Fields

  • template uuid · required Shared template.
  • expires_in_days int · default 7 Applied to every link in the batch.
  • requests array · required List of recipient rows.
Webhooks

Webhooks — events delivered to your endpoint

Configure an HTTPS endpoint that DataPDFEngine signs with HMAC-SHA256. Every payload includes the event name, the resource ID, and a stable timestamp so you can build idempotent handlers.

Signature verification (HMAC-SHA256)

Each outbound request carries three headers. Verify the signature before trusting the payload — and always compute the HMAC over the raw request body, before any JSON parsing.

  • X-DataPdfEngine-Event Event name, e.g. `batch.completed`.
  • X-DataPdfEngine-Signature `sha256=<hex>` — HMAC of the raw body with your endpoint secret.
  • X-DataPdfEngine-Timestamp ISO-8601 server time; reject requests older than ~5 minutes to defeat replays.
import crypto from "node:crypto";

export function verifyDataPdfEngineSignature(rawBody, headers, secret) {
  const sig = headers["x-datapdfengine-signature"];
  const ts  = headers["x-datapdfengine-timestamp"];
  if (!sig || !ts) return false;
  if (Math.abs(Date.now() - Date.parse(ts)) > 5 * 60_000) return false;

  const [scheme, hex] = sig.split("=");
  if (scheme !== "sha256" || !hex) return false;

  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(hex, "hex");
  const b = Buffer.from(expected, "hex");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
POST /webhooks/endpoints/

Register a new endpoint. Response includes the `secret` once — store it.

GET /webhooks/endpoints/

List your endpoints.

POST /webhooks/endpoints/{id}/test/

Fire a `test.ping` synchronously and capture the response in the delivery log.

GET /webhooks/deliveries/

Inspect recent deliveries: status code, attempt count, response body.

Events

  • batch.completed Batch reached terminal state. Payload: `{ event, batch_id, status, total, succeeded, failed, download_url? }`.
  • test.ping Sent synchronously from the dashboard when you click 'Send test'. Use it to validate signature handling and TLS reachability before going live.

Error model

Errors always come back as JSON with a stable `code` and a human-readable `detail`. HTTP status follows REST conventions.

HTTP Code Detail
400 invalid Payload didn't validate. `detail` lists the offending fields.
401 auth_failed Missing, malformed, or revoked API key.
402 quota_exceeded Plan quota for this feature is exhausted and overage is disabled.
403 feature_locked Your plan doesn't include this feature.
404 not_found Resource doesn't exist, or is owned by another org.
422 render_failed The PDF engine couldn't render the values.
429 rate_limited Hit the per-org API rate cap. Backoff hint in `Retry-After`.
502 delivery_failed Outbound webhook target returned a non-2xx. Inspect the delivery log.