PDF Service

Template-based PDF generation — create Jinja2 templates, validate with JSON Schema, generate PDFs.

checking...

All endpoints except /health require an API key passed via the X-API-Key header.

Header
X-API-Key: YOUR_API_KEY
Example
curl https://your-domain.com/templates \
  -H "X-API-Key: YOUR_API_KEY"
401 Unauthorized — missing or invalid key
{ "error": "Invalid API key", "message": "Authentication failed" }
  1. Create a Jinja2 HTML template with a JSON Schema via POST /templates.
  2. Optionally validate and preview with POST /validate and POST /pdf-preview.
  3. Generate a PDF by calling POST /pdf with the template ID and data — returns base64-encoded PDF.
GET /templates List all templates

Returns a summary list of all templates ordered by creation date (newest first). Does not include the HTML or schema body — use GET /templates/{id} for the full template.

Curl
curl https://your-domain.com/templates \
  -H "X-API-Key: YOUR_API_KEY"
Response fields
FieldTypeDescription
idUUIDUnique template identifier
namestringHuman-readable template name
created_atISO 8601Timestamp when the template was created (UTC)
Responses
[
  {
    "id": "3c755ab7-bd51-4b6d-8b7c-e344e3d5790a",
    "name": "Invoice Template",
    "created_at": "2025-03-02T14:27:40.970556Z"
  }
]
{ "error": "Invalid API key", "message": "Authentication failed" }
GET /templates/{id} Get template detail

Returns the full template detail including the Jinja2 HTML body and JSON Schema definition. Use this to inspect or retrieve a template before generating a PDF.

Path parameters
ParameterTypeDescription
idUUIDThe template's unique identifier
Curl
curl https://your-domain.com/templates/3c755ab7-bd51-4b6d-8b7c-e344e3d5790a \
  -H "X-API-Key: YOUR_API_KEY"
Response fields
FieldTypeDescription
idUUIDUnique template identifier
namestringHuman-readable template name
htmlstringJinja2 HTML template body — supports all Jinja2 syntax (variables, loops, conditionals, filters)
schemaobjectJSON Schema (Draft 7) that defines the expected data shape for rendering
created_atISO 8601Creation timestamp (UTC)
updated_atISO 8601Last update timestamp (UTC)
Responses
{
  "id": "3c755ab7-...",
  "name": "Invoice Template",
  "html": "<html>...</html>",
  "schema": { "type": "object", "properties": { ... } },
  "created_at": "2025-03-02T14:27:40Z",
  "updated_at": "2025-03-02T14:27:40Z"
}
{ "detail": "Template not found" }
POST /templates Create a new template

Create a new template. Both the Jinja2 HTML and JSON Schema are validated before saving — if either has syntax errors, the request will fail with 422 and a list of errors.

Body
FieldTypeDescription
namestringrequiredA descriptive name for the template (e.g. "Kasko Teklif Karsilastirma")
htmlstringrequiredJinja2 HTML template body. Supports variables ({{ var }}), loops ({% for %}), conditionals, and filters. Can include external CSS/fonts via CDN links.
schemaobjectrequiredA valid JSON Schema (Draft 7) defining the data structure expected when rendering. Used for validation — not enforced at render time.
Curl
curl -X POST https://your-domain.com/templates \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Invoice",
    "html": "<h1>{{ title }}</h1>",
    "schema": { "type": "object", "properties": { "title": { "type": "string" } } }
  }'
Responses
{
  "id": "new-uuid-here",
  "name": "Invoice",
  "html": "<h1>{{ title }}</h1>",
  "schema": { ... },
  "created_at": "...",
  "updated_at": "..."
}
{ "detail": ["Jinja2 syntax error at line 1: ..."] }
PUT /templates/{id} Update a template

Update an existing template. Only the fields you include in the request body will be changed — omitted fields remain untouched. If html or schema is provided, it will be re-validated before saving.

Path parameters
ParameterTypeDescription
idUUIDThe template's unique identifier
Body
FieldTypeDescription
namestringoptionalNew template name
htmlstringoptionalNew Jinja2 HTML template body
schemaobjectoptionalNew JSON Schema (Draft 7)
Curl
curl -X PUT https://your-domain.com/templates/{id} \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Updated Invoice" }'
Responses
{ "id": "...", "name": "Updated Invoice", ... }
{ "detail": "Template not found" }
{ "detail": ["Jinja2 syntax error at line 1: ..."] }
DELETE /templates/{id} Delete a template

Permanently deletes a template and all its associated assets (images, etc.). This action is irreversible. Returns 204 No Content on success with an empty response body.

Path parameters
ParameterTypeDescription
idUUIDThe template's unique identifier
Curl
curl -X DELETE https://your-domain.com/templates/{id} \
  -H "X-API-Key: YOUR_API_KEY"
Responses
(empty response)
{ "detail": "Template not found" }
POST /validate Validate template without saving

Validate a Jinja2 HTML template and JSON Schema without persisting anything. Useful for checking syntax before creating or updating a template. If data is provided, the template will also be rendered and the resulting HTML returned in rendered_html.

Body
FieldTypeDescription
htmlstringrequiredJinja2 HTML template to validate
schemaobjectrequiredJSON Schema (Draft 7) to validate
dataobjectoptionalSample data to render the template with. If omitted, only syntax validation is performed.
template_idUUIDoptionalIf provided, the template's stored assets (images) will be injected into the render context as base64 data URIs.
Curl
curl -X POST https://your-domain.com/validate \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>{{ title }}</h1>",
    "schema": { "type": "object", "properties": { "title": { "type": "string" } } },
    "data": { "title": "Hello" }
  }'
Response fields
FieldTypeDescription
validbooleantrue if both HTML and schema are syntactically correct
errorsstring[]List of validation error messages. Empty when valid is true.
rendered_htmlstring | nullRendered HTML output. Only present when data was provided and validation passed.
Responses
{
  "valid": true,
  "errors": [],
  "rendered_html": "<h1>Hello</h1>"
}
{
  "valid": false,
  "errors": ["Jinja2 syntax error at line 3: unexpected '}'"],
  "rendered_html": null
}
POST /pdf-preview Render template as HTML

Render a saved template with data and return the final HTML output — without generating a PDF. Useful for previewing how the template will look before committing to PDF generation. Template assets (images) are automatically injected as base64 data URIs.

Body
FieldTypeDescription
template_idUUIDrequiredID of the template to render
dataobjectrequiredData object matching the template's JSON Schema. All required schema fields must be present.
Curl
curl -X POST https://your-domain.com/pdf-preview \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "3c755ab7-...",
    "data": { "title": "Hello" }
  }'
Response fields
FieldTypeDescription
rendered_htmlstringThe fully rendered HTML string with all variables replaced, loops expanded, and assets injected.
Responses
{ "rendered_html": "<h1>Hello</h1>" }
{ "detail": "Render error: 'title' is undefined" }
{ "detail": "Template not found" }
POST /pdf Generate PDF

The main PDF generation endpoint. Renders the template with the provided data, launches a headless Chromium browser to convert the HTML to a PDF (A4 format, with background graphics), and returns the result as a base64-encoded string. Decode the string and save as .pdf to get the file.

Body
FieldTypeDescription
template_idUUIDrequiredID of the template to render
dataobjectrequiredData object matching the template's JSON Schema. All required schema fields must be present.
Curl
curl -X POST https://your-domain.com/pdf \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "3c755ab7-...",
    "data": { "title": "Hello" }
  }'
Response fields
FieldTypeDescription
pdf_base64stringBase64-encoded PDF file content. Decode with standard base64 decoding to get the raw PDF bytes.
Responses
{ "pdf_base64": "JVBERi0xLjQK..." }
{ "detail": "Template not found" }
{ "detail": "PDF generation failed: ..." }
GET /health Service health check

Check service availability and database connectivity. No authentication required. Use this for uptime monitoring or load balancer health checks.

Curl
curl https://your-domain.com/health
Response fields
FieldTypeDescription
statusstringAlways "ok" if the service is reachable
dbstring"ok" if the database connection is healthy, otherwise contains the error message
Responses
{ "status": "ok", "db": "ok" }
{ "status": "ok", "db": "error" }