REST API Reference

Credit-based PDF generation service. Pay per document size, no monthly fees.

Version: 1.0.0 Base URL: https://api.docpenny.com
get /api/health

Check service health

Responses

200 Service is healthy
application/json
{
"status": 'ok' | 'error'
"db": 'connected' | 'disconnected'
"s3": 'connected' | 'disconnected'
"queue": 'connected' | 'disconnected'
"renderer": 'connected' | 'disconnected'
}
503 Service is unhealthy
application/json
{
"status": 'ok' | 'error'
"db": 'connected' | 'disconnected'
"s3": 'connected' | 'disconnected'
"queue": 'connected' | 'disconnected'
"renderer": 'connected' | 'disconnected'
}
get /api/templates

List templates

Returns a paginated list of all templates available to the authenticated organization. Use `source=system` to list system-wide pre-built templates.

Parameters

source (query)

If set to "system", returns system-wide starter templates instead of org-specific ones.

page (query)

The page number to retrieve.

pageSize (query)

The number of items per page.

Responses

200 Paginated template list
application/json
{
"templates": Template[]
"totalPages": number
"total": number
"page": number
"pageSize": number
}
401 Unauthorized
application/json
{
"error": ErrorBody
}
post /api/templates

Upload a template

Upload a new HTML template using LiquidJS syntax. The system will automatically parse and discover variables within the template.

Request Body

multipart/form-data
{
"file": string (binary)
"name": string
}

Responses

201 Template created successfully
application/json
{
"id": string
"name": string
"variables": string[]
"createdAt": string
}
401 Unauthorized
application/json
{
"error": ErrorBody
}
413 File too large
application/json
{
"error": ErrorBody
}
422 Validation error (e.g. unreadable file or invalid name)
application/json
{
"error": ErrorBody
}
delete /api/templates/{id}

Delete a template

Parameters

id (path) Required

Responses

204 Template deleted
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Template not found
application/json
{
"error": ErrorBody
}
get /api/templates/{id}

Get a template

Returns the details of a specific template, including its variables and schema.

Parameters

id (path) Required

The UUID of the template to retrieve.

Responses

200 Template details retrieved successfully
application/json
{
"id": string
"name": string
"variables": string[]
"schema": object
"createdAt": string
"updatedAt": string
}
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Template not found
application/json
{
"error": ErrorBody
}
get /api/templates/{id}/download

Download a template file

Downloads the HTML template file for a given template. Supports both org-owned and system templates.

Parameters

id (path) Required

The UUID of the template to download.

Responses

200 The template HTML file.
text/html
string (binary)
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Template not found
application/json
{
"error": ErrorBody
}
post /api/preview

Generate a watermarked preview PDF

Request Body

application/json
{
"templateId": string (uuid)
"data": object
}

Responses

200 Preview generated
application/json
{
"downloadUrl": string
}
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Template not found
application/json
{
"error": ErrorBody
}
500 Internal Server Error
application/json
{
"error": ErrorBody
}
get /api/download/preview/{previewId}

Download a preview PDF (one-time download)

Download a preview PDF that was generated on-the-fly. This is a one-time download; the file is deleted from storage immediately after a successful request.

Parameters

previewId (path) Required

The UUID of the preview PDF.

Responses

200 The generated preview PDF file.
application/pdf
string (binary)
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Preview file not found or already downloaded.
application/json
{
"error": ErrorBody
}
get /api/jobs

List jobs

Returns a paginated list of all jobs submitted by the authenticated organization.

Parameters

page (query)

The page number to retrieve.

pageSize (query)

The number of items per page.

Responses

200 Paginated job list retrieved successfully
application/json
{
"jobs": JobSummary[]
"totalPages": number
"total": number
"page": number
"pageSize": number
}
401 Unauthorized
application/json
{
"error": ErrorBody
}
post /api/jobs

Submit a new job

Submit a new PDF generation job. Supports both `application/json` (with JSONL string in `data`) and `multipart/form-data` (with a `.jsonl` file in `data`). **Note:** For `multipart/form-data`, use a `data` field for the file, `templateId` (UUID), and optional `webhookUrl`.

Responses

201 Job created successfully
application/json
{
"jobId": string
"status": string
"totalTasks": number
}
401 Unauthorized
application/json
{
"error": ErrorBody
}
402 Insufficient credits
application/json
{
"error": ErrorBody
}
415 Unsupported Media Type
application/json
{
"error": ErrorBody
}
422 Validation error (e.g. malformed JSONL or missing template fields)
application/json
{
"error": ErrorBody
}
get /api/jobs/{id}

Get job details

Returns the status and progress of a specific job, including task counts.

Parameters

id (path) Required

The UUID of the job to retrieve.

Responses

200 Job details retrieved successfully
application/json
{
"id": string
"status": 'pending' | 'validating' | 'processing' | 'ready_for_zipping' | 'zipping' | 'ready_full_zip' | 'ready_partial_zip' | 'all_tasks_downloaded' | 'job_zip_downloaded' | 'failed' | 'expired'
"totalTasks": number
"completedTasks": number
"failedTasks": number
"createdAt": string
"completedAt": string
"webhookUrl": string
"errorMessage": string
}
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Job not found
application/json
{
"error": ErrorBody
}
get /api/jobs/{id}/tasks

List tasks for a job

Parameters

id (path) Required

The UUID of the job.

page (query)

Page number.

pageSize (query)

Items per page.

Responses

200 Paginated task list
application/json
{
"tasks": Task[]
"total": number
"page": number
"pageSize": number
"totalPages": number
}
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Job not found
application/json
{
"error": ErrorBody
}
get /api/jobs/{id}/tasks/{taskId}/download

Download a task PDF (one-time download)

Parameters

id (path) Required

taskId (path) Required

Responses

200 PDF file
application/pdf
any
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Task not found or already downloaded
application/json
{
"error": ErrorBody
}
get /api/download/zip/{jobId}

Download job ZIP bundle (one-time download)

Parameters

jobId (path) Required

Responses

200 ZIP file
application/zip
any
401 Unauthorized
application/json
{
"error": ErrorBody
}
404 Job not found, ZIP not ready, or already downloaded
application/json
{
"error": ErrorBody
}
get /api/openapi.json

No Summary

Responses

200 The OpenAPI specification in JSON format.
application/json
{
"openapi": string
"info": object
"paths": object
"components": object
}
get /api/openapi.yaml

No Summary

Responses

200 The OpenAPI specification in YAML format.
application/x-yaml
string

Interfaces

ErrorBody

object
{
"code": string
"details": ErrorDetail[]
}

Properties

code string

A stable machine-readable error code.

details ErrorDetail[]

A list of field-specific error details.

ErrorDetail

object
{
"field": string
"code": string
"line": number
}

Properties

field string

The field that caused the error, if applicable.

code string

A field-specific error code.

line number

The line number in the input data where the error occurred, if applicable.

JobDetails

object
{
"id": string
"status": 'pending' | 'validating' | 'processing' | 'ready_for_zipping' | 'zipping' | 'ready_full_zip' | 'ready_partial_zip' | 'all_tasks_downloaded' | 'job_zip_downloaded' | 'failed' | 'expired'
"totalTasks": number
"completedTasks": number
"failedTasks": number
"createdAt": string
"completedAt": string
"webhookUrl": string
"errorMessage": string
}

Properties

id string

The unique identifier for the job.

status 'pending' | 'validating' | 'processing' | 'ready_for_zipping' | 'zipping' | 'ready_full_zip' | 'ready_partial_zip' | 'all_tasks_downloaded' | 'job_zip_downloaded' | 'failed' | 'expired'

The current status of the job.

totalTasks number

The total number of PDFs to be generated in this job.

completedTasks number

The number of PDFs that have been successfully generated.

failedTasks number

The number of PDFs that failed to generate.

createdAt string

The date and time when the job was submitted.

completedAt string

The date and time when the job was finished (all tasks completed or failed).

webhookUrl string

The URL where notifications were/will be sent upon job completion.

errorMessage string

Error message if the job failed.

JobSummary

object
{
"id": string
"status": 'pending' | 'validating' | 'processing' | 'ready_for_zipping' | 'zipping' | 'ready_full_zip' | 'ready_partial_zip' | 'all_tasks_downloaded' | 'job_zip_downloaded' | 'failed' | 'expired'
"totalTasks": number
"completedTasks": number
"failedTasks": number
"createdAt": string
"errorMessage": string
}

Properties

id string

The unique identifier for the job.

status 'pending' | 'validating' | 'processing' | 'ready_for_zipping' | 'zipping' | 'ready_full_zip' | 'ready_partial_zip' | 'all_tasks_downloaded' | 'job_zip_downloaded' | 'failed' | 'expired'

Current status of the job.

totalTasks number

The total number of tasks (PDFs) in this job.

completedTasks number

The number of tasks that have been successfully processed.

failedTasks number

The number of tasks that have failed.

createdAt string

ISO 8601 timestamp when the job was submitted.

errorMessage string

Error message if the job failed.

Task

object
{
"id": string
"sequence": number
"status": string
"fileSizeBytes": number
"completedAt": string
"downloadedAt": string
"downloadUrl": string
"errorMessage": string
}

Properties

id string

The unique identifier for the task.

sequence number

The sequence number of the task in the job.

status string

The current status of the task.

fileSizeBytes number

The size of the generated PDF in bytes.

completedAt string

The date and time when the task was completed.

downloadedAt string

The date and time when the task was downloaded.

downloadUrl string

A temporary URL to download the generated PDF.

errorMessage string

An error message if the task failed.

Template

object
{
"id": string
"name": string
"variables": string[]
"createdAt": string
}

Properties

id string

The unique identifier for the template.

name string

The human-readable name of the template.

variables string[]

A list of variables required by this template.

createdAt string

The date and time when the template was created.

TemplateDetail

object
{
"id": string
"name": string
"variables": string[]
"schema": object
"createdAt": string
"updatedAt": string
}

Properties

id string

The unique identifier for the template.

name string

The human-readable name of the template.

variables string[]

A list of LiquidJS variables required by this template.

schema object

Optional JSON Schema describing the expected variable types and constraints.

createdAt string

The date and time when the template was created.

updatedAt string

The date and time when the template was last updated.

en