PaperStudio/Render Engine
UsuarioSoporteDeveloper

Render Engine

Docuget's Render Engine is a universal format conversion and template rendering pipeline. It takes data and templates in one format and produces output in another — Typst to PDF, JSON to XLSX, ECharts to SVG, images between formats, and dozens more combinations.

The engine supports three modes:

  • Template rendering — process a Nunjucks template with data and convert the output to a target format
  • Format conversion — convert data between formats without any template (e.g. JSON to CSV)
  • Record rendering — fetch a database record by table and ID, then render it through a template

All modes share the same converter registry, caching layer, and composable rendering pipeline.

Supported Formats

Template Rendering (source_type to output)

Source Type Output Formats Engine
Typst PDF, SVG, PNG Typst compiler
ECharts SVG, HTML, PNG, JSON ECharts SSR
Pintora SVG, PNG Pintora renderer

Data Conversion (input to output)

Input Output Formats
JSON CSV, TSV, XLSX, YAML, TOML, XML, Markdown table, HTML table, GeoJSON, DOCX
CSV JSON, TSV
TSV JSON
GeoJSON CSV, SVG, DXF, JSON
SVG PNG, JPG, WebP, HPGL
HTML DOCX
Markdown DOCX
PNG/JPG/WebP PNG, JPG, WebP (image conversion)

Tip: Use GET /v1/render/converters/matrix to see the full, live conversion matrix for your instance, including any custom converters.

API Endpoints

All endpoints require authentication (Bearer token).

Synchronous Render

Renders data through a template and converts to the target output format. Returns the output inline by default.

POST /v1/render

Request body:

{
  "company_id": "550e8400-e29b-41d4-a716-446655440000",
  "template_id": "tpl_01hjd3...",
  "data": {
    "title": "Q1 Report",
    "items": [{ "name": "Widget", "qty": 42 }]
  },
  "output_format": "pdf",
  "output_filename": "report.pdf",
  "inline": true,
  "cache_ttl": 3600
}
Field Type Description
company_id string Required. Company scope
template_id string Template ID (provide this or template_key)
template_key string Template key lookup (alternative to template_id)
source_table string DB table to fetch record from
source_record_id string Record ID within source_table
data object Data passed to the template
output_format string Required. Target format (pdf, svg, csv, xlsx, etc.)
output_filename string Suggested filename for the output
inline boolean Return output directly (default true). When false, returns metadata JSON.
cache_ttl number Cache duration in seconds. Subsequent identical requests return the cached result.

curl example:

curl -X POST https://api.docuget.com/v1/render \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "550e8400-...",
    "template_key": "invoice_pdf",
    "data": { "invoice_number": "INV-001", "total": 1500 },
    "output_format": "pdf"
  }' \
  --output invoice.pdf

Response headers include X-Render-Duration-Ms, X-Render-From-Cache, and optionally X-Render-Job-Id.

Format Conversion

Converts data between formats without any template rendering.

POST /v1/render/convert

Request body:

{
  "input": [
    { "name": "Alice", "age": 30 },
    { "name": "Bob", "age": 25 }
  ],
  "input_format": "json",
  "output_format": "csv",
  "company_id": "550e8400-...",
  "options": {
    "columns": ["name", "age"],
    "bom": true
  }
}

curl example:

curl -X POST https://api.docuget.com/v1/render/convert \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "input": [{"name": "Alice", "score": 95}],
    "input_format": "json",
    "output_format": "xlsx",
    "options": {
      "sheetName": "Results",
      "style": {
        "headerStyle": { "bold": true, "fillColor": "#4472C4", "fontColor": "#FFFFFF" },
        "alternateRowColor": "#D9E2F3",
        "borders": true
      }
    }
  }' \
  --output results.xlsx

Render a Database Record

Fetches a record from a database table and renders it through a template.

POST /v1/render/record
{
  "company_id": "550e8400-...",
  "table": "customer",
  "record_id": "customer_01hjd3...",
  "template_key": "customer_card",
  "output_format": "pdf"
}

curl example:

curl -X POST https://api.docuget.com/v1/render/record \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "550e8400-...",
    "table": "invoice",
    "record_id": "inv_01hjd4...",
    "template_key": "invoice_pdf",
    "output_format": "pdf"
  }' \
  --output invoice.pdf

Get Record Render (shorthand)

A GET endpoint for quick record rendering via query parameters.

GET /v1/render/record/:table/:id?out=pdf&template_key=invoice_pdf&company_id=...

curl example:

curl "https://api.docuget.com/v1/render/record/invoice/inv_01hjd4...?out=svg&company_id=550e8400-..." \
  -H "Authorization: Bearer $TOKEN" \
  --output invoice.svg

Render via Short Reference

Resolves a @code to a template or record and renders it directly.

GET /v1/render/ref/:code?out=svg&company_id=...&width=800&height=400

curl example:

curl "https://api.docuget.com/v1/render/ref/k7f2n?out=png&company_id=550e8400-...&width=1200&height=600" \
  -H "Authorization: Bearer $TOKEN" \
  --output chart.png

Batch Render

Renders multiple items through a template. Optionally merges all PDF outputs into a single file.

POST /v1/render/batch

Request body:

{
  "company_id": "550e8400-...",
  "template_key": "invoice_pdf",
  "output_format": "pdf",
  "merge_pdf": true,
  "concurrency": 5,
  "items": [
    { "data": { "invoice_number": "INV-001", "total": 1500 } },
    { "data": { "invoice_number": "INV-002", "total": 2300 } },
    { "source_table": "invoice", "source_record_id": "inv_01hjd5..." }
  ]
}
Field Type Description
items array Required. Array of render inputs (each can override template_id, template_key, output_format)
merge_pdf boolean When true and output_format is pdf, merges all outputs into a single PDF (default false)
concurrency number Max parallel renders, 1-20 (default 5)

curl example:

curl -X POST https://api.docuget.com/v1/render/batch \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "550e8400-...",
    "template_key": "invoice_pdf",
    "output_format": "pdf",
    "merge_pdf": true,
    "items": [
      { "data": { "invoice_number": "INV-001" } },
      { "data": { "invoice_number": "INV-002" } }
    ]
  }' \
  --output batch_merged.pdf

When merge_pdf is false, the response is JSON with per-item status:

{
  "total": 2,
  "succeeded": 2,
  "failed": 0,
  "results": [
    {
      "index": 0,
      "status": "fulfilled",
      "job_id": "rjob_01...",
      "mime_type": "application/pdf",
      "size": 14200,
      "duration_ms": 320
    },
    {
      "index": 1,
      "status": "fulfilled",
      "job_id": "rjob_02...",
      "mime_type": "application/pdf",
      "size": 15800,
      "duration_ms": 290
    }
  ]
}

Async Render

Same parameters as POST /v1/render, but returns 202 Accepted immediately with a job_id. The render runs in the background.

POST /v1/render/async

curl example:

# Start async render
curl -X POST https://api.docuget.com/v1/render/async \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "550e8400-...",
    "template_key": "annual_report",
    "data": { "year": 2026 },
    "output_format": "pdf"
  }'

# Response: { "job_id": "rjob_01hjd6...", "status": "queued" }

Job Status and Output

GET /v1/render/jobs?company_id=...&status=completed&page=1&pageSize=20
GET /v1/render/job/:id
GET /v1/render/job/:id/output
DELETE /v1/render/job/:id

curl examples:

# List jobs
curl "https://api.docuget.com/v1/render/jobs?company_id=550e8400-...&status=completed" \
  -H "Authorization: Bearer $TOKEN"

# Check job status
curl "https://api.docuget.com/v1/render/job/rjob_01hjd6..." \
  -H "Authorization: Bearer $TOKEN"

# Download completed output
curl "https://api.docuget.com/v1/render/job/rjob_01hjd6.../output" \
  -H "Authorization: Bearer $TOKEN" \
  --output report.pdf

Job statuses: pending, processing, completed, cached, failed.

Converter Registry

GET /v1/render/converters
GET /v1/render/converters/matrix
POST /v1/render/converters
PUT /v1/render/converters/:id
DELETE /v1/render/converters/:id

curl examples:

# List all converters
curl "https://api.docuget.com/v1/render/converters" \
  -H "Authorization: Bearer $TOKEN"

# Get the full conversion matrix (source -> output mapping)
curl "https://api.docuget.com/v1/render/converters/matrix" \
  -H "Authorization: Bearer $TOKEN"

# Register a custom converter
curl -X POST https://api.docuget.com/v1/render/converters \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_type": "custom_markup",
    "output_format": "html",
    "engine": "custom",
    "is_enabled": true
  }'

Dynamic Data Functions ($fn: Directives)

The render engine supports $fn: directives — special string values in template data that are resolved to live database query results during Phase 1 (Data Resolution). This powers the Data Science module's charts and tabular views.

Available functions: count, sum, avg, min, max, list, table, group_count, daily_count, monthly_count.

{
  "series": [{
    "data": [{
      "value": "$fn:count(telegram_messages)",
      "name": "Messages"
    }]
  }]
}

After resolution, $fn:count(telegram_messages) becomes the actual row count (e.g. 4287). All queries are company-scoped and read-only.

See the full Data Science documentation for the complete function reference, security model, and examples.

Nunjucks Filters

The render engine registers several Nunjucks filters for use inside templates. These enable inline format conversion and composable rendering.

render

Renders a template by ID or key and returns the output inline. This is how composable (recursive) rendering works — a template can embed the output of another template.

{{ "tpl_01hjd3..." | render("svg") }}
{{ "invoice_header" | render("html", extra_data) }}

to_yaml

Converts a data object to YAML.

{{ config | to_yaml }}

to_csv

Converts an array of objects to CSV. Optionally pass column names.

{{ rows | to_csv }}
{{ rows | to_csv(["name", "email", "score"]) }}

to_toml

Converts a data object to TOML.

{{ settings | to_toml }}

to_json

Serializes data to JSON with optional indentation.

{{ data | to_json }}
{{ data | to_json(2) }}

to_md_table

Converts an array of objects to a Markdown table. Optionally pass column names.

{{ rows | to_md_table }}
{{ rows | to_md_table(["name", "score"]) }}

render_chart

Renders an ECharts template inline as SVG, PNG, or HTML. Used to embed Data Science charts in other templates.

{{ "sales-chart" | render_chart("svg", 800, 400) }}
{{ "@k7f2n" | render_chart("png", 600, 300, {"year": 2026}) }}

Arguments: format (default "svg"), width, height, data (optional override object). Respects the MAX_DEPTH = 5 recursion limit.

CLI Usage

The docuget CLI provides a render subcommand for rendering templates and converting formats from the terminal.

# Render a template to PDF
docuget render --template-key invoice_pdf --out pdf --save invoice.pdf

# Render a specific DB record
docuget render --table invoice --id inv_01hjd4... --template-key invoice_pdf --out pdf

# Render via short reference
docuget render @k7f2n --out svg --save chart.svg

# Convert JSON file to CSV
docuget render --convert input.json --out csv --save output.csv

# Render and print to stdout
docuget render --template-key sales_chart --out svg
Flag Description
--template-key Template key to render
--table Source DB table for record rendering
--id Record ID within the source table
--out Output format (pdf, svg, csv, xlsx, etc.)
--save Save output to a file path
--convert Input file for format conversion (no template)
@code Short reference — resolved to a template or record automatically

Composable Rendering

Templates can embed other templates using the render Nunjucks filter. This creates a recursive rendering pipeline where the output of one template becomes part of another.

{# Main report template #}
<h1>{{ title }}</h1>

{# Embed a chart rendered as SVG #}
<div class="chart">
  {{ "sales_chart_template" | render("svg", { year: 2026 }) }}
</div>

{# Embed a data table rendered as HTML #}
<div class="table">
  {{ rows | to_md_table(["product", "revenue"]) }}
</div>

The engine tracks recursion depth and enforces a maximum of 5 levels (MAX_DEPTH = 5). If a render chain exceeds this limit, a RenderDepthError is raised with a 400 status code.

Each nested render call inherits the parent's company_id and increments the depth counter, preventing infinite loops.

Caching

The render engine supports output caching via the cache_ttl parameter (in seconds). When set:

  1. A cache key is computed from the render request parameters (template, data, output format)
  2. If a cached result exists and has not expired, it is returned immediately
  3. The response header X-Render-From-Cache indicates whether the result was served from cache
{
  "cache_ttl": 3600
}

This is useful for expensive renders (large PDFs, complex charts) that are requested frequently with the same data. Set cache_ttl to 0 or omit it to disable caching.

XLSX Styling

When converting JSON to XLSX via POST /v1/render/convert, you can pass XlsxStyleOptions in the options.style field to control the appearance of the generated spreadsheet.

{
  "input": [
    { "name": "Alice", "score": 95 },
    { "name": "Bob", "score": 87 }
  ],
  "input_format": "json",
  "output_format": "xlsx",
  "options": {
    "sheetName": "Results",
    "columns": ["name", "score"],
    "style": {
      "headerStyle": {
        "bold": true,
        "fillColor": "#4472C4",
        "fontColor": "#FFFFFF"
      },
      "alternateRowColor": "#D9E2F3",
      "borders": true
    }
  }
}
Option Type Description
headerStyle.bold boolean Bold header text (default true)
headerStyle.fillColor string Header background color as hex (e.g. #4472C4)
headerStyle.fontColor string Header text color as hex (e.g. #FFFFFF)
alternateRowColor string Background color for odd data rows as hex (zebra striping)
borders boolean Apply thin borders to all cells

Additional XLSX options:

Option Type Description
sheetName string Name of the worksheet (default Sheet1, max 31 characters)
columns string[] Column order. If omitted, all keys from the first row are used.
sheets array Multi-sheet mode: [{ name, data, columns }]. Overrides sheetName and root data.