Skip to content

API Reference

We expose a public render endpoint and template CRUD endpoints.

For fully programmatic onboarding, see Agent Onboarding.

Authentication

All API calls require an API key:

X-API-Key: <your_key>

Agent Signup

You can create an account and receive an API key directly:

json
{
  "name": "Agent User",
  "email": "agent-user@example.com",
  "password": "replace-with-strong-password",
  "mode": "agent",
  "attribution": {
    "first_touch_channel": "website:pdfmancer_landing",
    "utm_source": "pdfmancer_landing",
    "utm_medium": "website",
    "utm_campaign": "landing_core",
    "utm_content": "hero_signup",
    "utm_term": "json to pdf api",
    "landing_locale": "en",
    "referrer_path": "/en"
  }
}

Endpoint:

  • POST https://dashboard.pdfmancer.com/api/auth/signup

Attribution fields are optional and allow campaign tracking for lead generation.

Schema Discovery

GET /api/public/schema/current

Returns schema metadata and current version.

json
{
  "schema_name": "document",
  "current_version": "v1",
  "schema_url": "/api/public/schemas/document/v1.json"
}

GET /api/public/schemas/document/{version}.json

Returns the versioned JSON Schema used by the API validator.

Example:

  • GET /api/public/schemas/document/v1.json

Validate

POST /api/public/validate

Runs schema validation only and returns actionable issues for agents.

json
{
  "schema_version": "v1",
  "template": {
    "elements": [{ "type": "text", "value": "Hello {{ customer.name }}" }]
  },
  "data": {
    "customer": { "name": "ACME" }
  }
}

Response shape:

json
{
  "ok": true,
  "schema_version": "v1",
  "issues": [],
  "summary": { "error_count": 0, "warning_count": 0 }
}

Issue shape:

  • code: stable machine code (for example SCHEMA_REQUIRED).
  • phase: template or resolved_template.
  • path: JSON pointer path.
  • message: raw validation error.
  • suggestion: remediation hint for agents.
  • severity: error or warning.

Templating-related issue codes:

  • PLACEHOLDER_UNSAFE_EXPRESSION
  • PLACEHOLDER_FILTER_INVALID
  • PLACEHOLDER_MISSING (warning)

Render

POST /api/public/render

Render either a raw template or a saved template with data.

Supported element types: text, heading, divider, list, image, row, table, spacer, pagebreak.

Raw template

json
{
  "elements": [
    { "type": "heading", "value": "Invoice {{ invoice.number }}", "level": 2 },
    { "type": "divider" },
    { "type": "text", "value": "Hello {{ customer.name }}" }
  ]
}

Dynamic table (loop alias item)

json
{
  "elements": [
    {
      "type": "table",
      "source": "lines",
      "columns": [
        { "label": "Concept", "value": "{{ item.concept }}" },
        { "label": "Qty", "value": "{{ item.quantity }}" },
        { "label": "Total", "value": "{{ item.line_total }}", "format": "currency" }
      ],
      "empty_message": "No lines"
    }
  ]
}

Static table (data matrix)

json
{
  "elements": [
    {
      "type": "table",
      "data": [
        ["Item", "Qty", "Price"],
        ["Widget A", 2, 19.99],
        ["Cable B", 1, 4.5]
      ]
    }
  ]
}

Saved template

json
{
  "template_id": "<template_id>",
  "data": {
    "customer": { "name": "ACME" },
    "total": 123.45
  }
}

You can also pass schema_version in the wrapped payload (template or template_id) to pin validation version. If validation fails, render returns 400 with the same actionable issues[] structure as /api/public/validate. Template placeholders use a strict safe subset (see Templating); unsupported expressions are rejected. In render, missing placeholder data is replaced with empty string.

Async Render Jobs (AI-first)

POST /api/public/render-jobs

Create an async JSON-to-PDF job. This route is designed for paste JSON -> get PDF UX. If input_json is already a valid document template ({ "elements": [...] }), the job skips AI planning and renders that template directly.

json
{
  "input_json": {
    "title": "Article list",
    "items": [
      { "name": "Widget A", "qty": 2, "price": 19.99 }
    ]
  },
  "options": {
    "allow_raw_for_ai": false,
    "max_table_rows": 40,
    "user_prompt": "Treat this payload as an invoice and keep totals prominent."
  }
}

Response (202):

json
{
  "job_id": "job_123",
  "status": "queued"
}

GET /api/public/render-jobs/

Read job status and generated artifacts.

Typical consumer flow:

  1. Create job with POST /api/public/render-jobs.
  2. Poll status until success or error.
  3. Download file from /file when status is success.

Status values:

  • queued
  • processing
  • success
  • error

Example response:

json
{
  "job_id": "job_123",
  "status": "success",
  "progress_stage": "success",
  "template_json": {
    "elements": [
      { "type": "heading", "value": "Article list", "level": 2 }
    ]
  },
  "document_plan": {
    "doc_type": "generic"
  },
  "planning_trace": {
    "strategy": "ai",
    "provider": "openrouter",
    "model": "openai/gpt-4o-mini",
    "attempts": 2,
    "anonymized": true,
    "detected_doc_type": "invoice_basic",
    "doc_type_score": 0.91,
    "matched_signals": ["explicit_doc_kind", "line_items", "totals"],
    "user_prompt_used": true,
    "language_selected": "es",
    "validation": {
      "schema_valid": true,
      "repaired": true
    }
  }
}

GET /api/public/render-jobs/{job_id}/file

Returns the generated PDF (application/pdf) when job status is success. If job is still running, returns 409.

Async job caveats (consumer-facing)

  • input_json must be a JSON object or array.
  • Processing time depends on payload size and structure complexity.
  • Planning input is anonymized by default unless allow_raw_for_ai=true.
  • You can add options.user_prompt (up to 1200 chars) to steer the planner for specific layout goals.
  • If status is error, inspect error and error_code from the status response for recovery.

Templates

POST /api/templates

json
{
  "name": "Invoice",
  "description": "Basic invoice",
  "template": {
    "elements": [
      { "type": "text", "value": "Invoice {{ invoice.number }}" }
    ]
  }
}

GET /api/templates

Returns templates for your team.

GET /api/templates/{id}

Returns a single template.

PUT /api/templates/{id}

json
{
  "name": "Invoice v2",
  "template": {
    "elements": [
      { "type": "text", "value": "Updated" }
    ]
  }
}

DELETE /api/templates/{id}

Deletes a template.


Use the interactive tester in Live Explorer.