API reference

The base URL is wherever you installed the service (Deployment), for example http://reportdesigner:8080. All request bodies are application/json. The machine-readable specification is GET /openapi.json (OpenAPI 3.1). Import it into Postman or your client generator.

Method and pathPurpose
POST /api/v1/renderRender a template with data to PDF
POST /api/v1/validateValidate a template without rendering
GET /api/v1/fontsList the fonts available on the server
GET /v1/infoName, version, license and designer SDK of this installation
GET /health, GET /readyLiveness and readiness probes
GET /openapi.jsonOpenAPI document
GET /, GET /help/, GET /sdk/…This portal, the user guide and the standalone designer bundle: static pages, not part of the API or openapi.json (see Guides served by the service)

Endpoints on this server

Download openapi.json

Rendered from this server's GET /openapi.json (OpenAPI 3.1), so it always matches the installed version. Click an endpoint for its parameters, body and responses.

Loading the API description…

POST /api/v1/render#

The template and the data are separate parameters:

{
  "template": { "version": 1, "name": "VICS BOL", "page": { "...": "..." }, "bands": { "...": "..." } },
  "data": { "bolNumber": "BOL2026102001", "shipFrom": { "name": "Acme Distribution" }, "lines": [ ] },
  "options": { "filename": "BOL2026102001", "disposition": "attachment", "locale": "en-US", "now": "2026-10-20T12:00:00Z" }
}
FieldRequiredNotes
templateyesTemplate JSON from the designer (getTemplate() or the save event)
datanoAny JSON value, default {}. It is the root scope for {{ expressions }}. Preview text ({{ x | sample }}) is ignored
options.filenamenoDownload name without .pdf (max 200 characters, sanitized). Default: the template's name
options.dispositionnoinline (default, opens in the browser) or attachment (download)
options.localenoBCP-47 tag that overrides the template's document language (number, date and currency formatting, CJK font choice), e.g. fr-FR
options.nownoISO date-time used for {{ now }} / today(), for reproducible output (tests, reprints). Doesn't affect license expiry

Response 200: application/pdf, with:

HeaderMeaning
Content-Dispositioninline; filename="…pdf"; filename*=UTF-8''… (or attachment)
X-Page-CountNumber of pages
X-Render-WarningsNumber of non-fatal problems: a missing image, an unknown font (falls back to Arimo), an expression error (prints empty), an invalid barcode value
X-License-Statusvalid, trial, expired, missing or invalid. Anything but valid means a watermarked PDF (License). Sent on every response, not only renders
X-Request-IdCorrelates with the server log. A well-formed incoming X-Request-Id (≤ 64 chars, [A-Za-z0-9._-]) is echoed

?format=json returns the PDF base64-encoded together with the warning texts, which helps when testing templates:

{ "pdfBase64": "JVBERi0xLjcK…", "pageCount": 3, "warnings": [ { "elementId": "bc1", "message": "Barcode '12' (ean13): …" } ], "license": "trial", "watermark": "trial" }

license is the same value as X-License-Status; watermark is the mark on every page: trial, expired, unlicensed, or null (none). Rendering is never refused for licensing reasons: without a valid paid license the request still succeeds and the PDF is watermarked.

Batches. If the template sets recordsPath (the author's Records → One copy per setting, e.g. "shipments"), send { "shipments": [ {…}, {…} ] }. The service renders one copy per record into one PDF, with page numbers restarting for each copy.

POST /api/v1/validate#

Request { "template": { … } }. Response:

{ "valid": false, "issues": [ { "path": "bands.body.elements[3].dataPath", "message": "Expected an expression", "severity": "error" } ] }

Structural checks, value bounds and expression syntax, without rendering. Use it on template save. severity: "warning" issues don't prevent rendering. A call to a function that doesn't exist is a warning (Unknown function 'formatCurency' (did you mean formatCurrency?)): the template renders, and that placeholder prints empty.

GET /api/v1/fonts#

Returns the bundled font families (family, aliases such as Arial → Arimo, category, variants) plus the fonts installed from RD_FONT_DIR.

GET /v1/info#

{
  "name": "reportdesigner",
  "version": "1.0.0",
  "license": {
    "status": "valid", "trial": false, "source": "configured", "watermark": null, "products": ["reportdesigner"],
    "licensee": "Acme Corp", "id": "LIC-0007", "expires": "2027-12-31", "daysLeft": 437, "maxInstances": 2, "instanceId": "rd-3f9c0a1e…"
  },
  "sdk": { "version": "1.0.0", "url": "/sdk/1.0.0/", "latest": "/sdk/latest/" }
}
license fieldMeaning
statusvalid, expired (past the end of its expiry day, UTC), missing (no license key) or invalid (not accepted)
trialtrue for a trial license, including the evaluation license bundled with the release
sourceconfigured (LICENSE_KEY / LICENSE_FILE) or bundled (the evaluation license of the release); absent when missing
watermarkWhat rendered PDFs carry now: trial, expired, unlicensed, or null (none)
licensee, id, expires, daysLeftFrom the license; expires and daysLeft are absent for a trial without expiry
maxInstances, instanceIdInstallations the license covers, and this installation's id (License)

The answer is the same for everyone. It never contains the license key, and never why a key was not accepted (that is in the server log).

GET /health, GET /ready#

  • /health returns { "status": "ok", "version": "1.0.0", "license": "trial", "sdk": { … } } (license as in X-License-Status). Use it for liveness.
  • /ready returns { "status": "ready", "inFlight": 0, "capacity": 40 }, and 503 while shutting down. Use it for readiness and load-balancer health.

Errors#

Every error is an RFC 9457 application/problem+json body:

{ "type": "/problems/invalid-template", "title": "Invalid template", "status": 400, "detail": "The template failed validation",
  "instance": "/api/v1/render", "requestId": "8c88…", "issues": [ { "path": "page", "message": "Required", "severity": "error" } ] }
StatustypeWhenClient action
400invalid-requestMalformed JSON, missing template, a bad option, an unknown localeFix the request. Don't retry
400invalid-templateThe template failed validation (issues lists the problems)Fix the template. Don't retry
404not-foundUnknown route—
413payload-too-largeBody over RD_BODY_LIMIT_MBSmaller images, or raise the limit
415unsupported-media-typeBody isn't JSONSend Content-Type: application/json
422render-failedValid template, but rendering failed (e.g. more pages than RD_MAX_PAGES)Check detail. Don't retry unchanged
422render-memory-exceededThe render needed more than RD_WORKER_MAX_MEMORY_MBReduce images or data, or raise the limit
499client-closedThe client disconnected; the render was aborted—
503server-busyAll workers busy and the queue full, or shutting downRetry after the Retry-After header (seconds)
504render-timeoutOver RD_RENDER_TIMEOUT_MS (queue time included)Retry once. If it persists, simplify the document or raise the timeout
500internal-errorA bug. Details are in the server log under requestIdRetry once. Report it with the requestId

Limits#

LimitDefaultSetting
Request size20 MBRD_BODY_LIMIT_MB
Pages per document2,000RD_MAX_PAGES
Render time (including queue)60 sRD_RENDER_TIMEOUT_MS
Memory per render512 MBRD_WORKER_MAX_MEMORY_MB
Pixels per image / image bytes per render25 M / 50 MBRD_MAX_IMAGE_PIXELS / RD_MAX_IMAGE_BYTES
Table rows per table100,000 (then truncated with a warning)—
Template boundsFont size ≤ 1000 pt, page ≤ 14,400 pt, Min. rows ≤ 10,000, ≤ 20,000 elements— (validation errors)
Expression results≤ 1,000,000 characters per text—

See Render API clients for code in several languages.