Publisher Service
The Publisher service generates PDFs and images from Typograph templates. It supports batch processing with CSV data for generating multiple documents from a single template.
Base URL: /v1/publisher/
Scopes: publisher (full), publisher:read, publisher:write
Token type: any — publisher endpoints accept either a user token or a client token. See Token Types.
Endpoints
| Method | Path | Scopes | Description |
|---|---|---|---|
GET | /v1/publisher/jobs | publisher / publisher:read | List generation jobs |
POST | /v1/publisher/jobs | publisher / publisher:write | Create a generation job |
GET | /v1/publisher/jobs/{path} | publisher / publisher:read | Job detail and output files |
GET | /health/publisher | — | Service health (public, unauthenticated) |
The single-item endpoint uses a catch-all {path} — concrete sub-paths handled by the publisher service include /v1/publisher/jobs/{id} (job details) and /v1/publisher/jobs/{id}/files (download generated files, see File Types below).
Create a Generation Job
Generate a document from a Typograph template:
curl -X POST https://api.typograph.nl/v1/publisher/jobs \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tag": "invoice-alpha",
"input": {
"template": {
"url": "https://example.com/templates/invoice.json"
},
"manifest": {
"url": "https://example.com/templates/manifest.json"
}
},
"output": {
"upload": {
"url": "https://example.com/webhook/upload"
},
"config": {
"type": "pdf",
"color_mode": "cmyk",
"bleed": 3
}
}
}'
Response
{
"id": "01234567-89ab-cdef-0123-456789abcdef",
"tag": "invoice-alpha",
"status": "queued",
"created_at": "<ISO 8601 timestamp>"
}
Request Structure
Input Object
| Property | Type | Required | Description |
|---|---|---|---|
template | object | Yes | Typograph template JSON |
template.url | string | Yes | URL to template file |
template.headers | object | No | HTTP headers for downloading |
manifest | object | Yes | Typograph manifest JSON |
manifest.url | string | Yes | URL to manifest file |
manifest.headers | object | No | HTTP headers for downloading |
csv | object | No | CSV data file for batch processing |
csv.url | string | No | URL to CSV file |
csv.headers | object | No | HTTP headers for downloading |
The Publisher takes two separate JSON URLs — not the typograph_package.zip produced by the Converter Service. Unzip the package and host templatebundle.template and templatebundle.manifest as two reachable JSON files, then pass them as input.template.url and input.manifest.url. Any images/ and fonts/ from the package need to stay reachable too — the template references them by URL.
Output Object
| Property | Type | Required | Description |
|---|---|---|---|
upload | object | Yes | Target for generated files |
upload.url | string | Yes | URL to upload generated files |
upload.headers | object | No | HTTP headers for uploading |
config | object | Yes | Generator configuration |
Output Formats
| Format | Description |
|---|---|
pdf | PDF document |
png | PNG image (one per page) |
jpg / jpeg | JPEG image (one per page) |
webp | WebP image (one per page) |
Generator Configuration
Configure the output with the output.config object:
| Property | Type | Description |
|---|---|---|
type | string | Output format: pdf, png, jpg, jpeg, webp |
dpi | integer | Resolution for images (36-600, default: 300) |
quality | integer | Quality for lossy formats (0-100, default: 90) |
color_mode | string | Color space: rgb or cmyk |
bleed | number | Print bleed in millimeters (0-25.4) |
pages | string | Page range, e.g., "1-5,8-10" |
crop_marks | boolean | Include crop marks for printing |
spreads_as_single_pages | boolean | Split spread pages |
watermark | object | Watermark overlay configuration |
Watermark Configuration
Add a watermark overlay to generated documents:
{
"output": {
"config": {
"type": "pdf",
"watermark": {
"type": "center",
"image": {
"url": "https://example.com/watermark.png",
"headers": {
"Authorization": "Bearer your-storage-token"
}
},
"width": 50,
"height": 20,
"opacity": 0.3
}
}
}
}
| Property | Type | Description |
|---|---|---|
type | string | Positioning: center or repeat_horizontal |
image | object | Watermark image URL and optional headers |
image.url | string | URL to PNG watermark image |
image.headers | object | Optional HTTP headers for downloading (max 5) |
width | number | Width in millimeters |
height | number | Height in millimeters |
opacity | number | Transparency (0.0-1.0, default: 0.5) |
Batch Processing with CSV
Generate multiple documents by providing a CSV data file:
curl -X POST https://api.typograph.nl/v1/publisher/jobs \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tag": "invoice-batch-alpha",
"input": {
"template": {
"url": "https://example.com/templates/invoice.json"
},
"manifest": {
"url": "https://example.com/templates/manifest.json"
},
"csv": {
"url": "https://example.com/data/invoices.csv"
}
},
"output": {
"upload": {
"url": "https://example.com/webhook/upload"
},
"config": {
"type": "pdf"
}
}
}'
When a CSV file is provided:
- A parent job is created for the batch
- Child jobs are automatically created for each row in the CSV
- Use
parent_idto filter and list child jobs
Listing Child Jobs
curl "https://api.typograph.nl/v1/publisher/jobs?parent_id=PARENT_JOB_ID" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Download Generated Files
Download the output once the job is completed:
curl "https://api.typograph.nl/v1/publisher/jobs/{id}/files?file_type=output" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-o document.pdf
File Types
| Type | Description |
|---|---|
output | Generated document (default) |
template | Original template file |
manifest | Original manifest file |
csv | CSV data file (if used) |
Upload Request Format
When a job completes successfully and you've configured output.upload.url, Typograph sends the generated file as a single HTTP PUT request to that URL. Your upload target must accept this request shape:
| Property | Value |
|---|---|
| Method | PUT |
| URL | Exactly the URL you provided in output.upload.url (no redirects are followed) |
Content-Type | Detected from the file — e.g. application/pdf, image/png, image/jpeg, image/webp |
User-Agent | Typograph/Util-Upload |
| Custom headers | Whatever you passed in output.upload.headers (merged in, can't override Content-Type or User-Agent) |
| Body | Raw file bytes, streamed (no multipart / form-data wrapper) |
| Connection timeout | 10 seconds |
| Transfer timeout | 300 seconds |
Your endpoint must respond with an HTTP status in the 200–299 range to be considered successful; anything else marks the job as failed.
Minimal receiver (Node.js / Express)
const express = require('express');
const fs = require('fs');
const app = express();
app.put('/uploads/:filename',
// Use a raw body parser — the request body is the file itself.
express.raw({ type: '*/*', limit: '200mb' }),
(req, res) => {
const filename = req.params.filename;
fs.writeFileSync(`./uploads/${filename}`, req.body);
console.log(`Received ${req.headers['content-type']} (${req.body.length} bytes)`);
res.status(200).send();
},
);
Minimal receiver (PHP)
<?php
// PUT /uploads/{filename}
$rawBody = file_get_contents('php://input');
$filename = basename($_SERVER['REQUEST_URI']);
file_put_contents('/var/uploads/' . $filename, $rawBody);
http_response_code(200);
Uploading Directly to Cloud Storage
You can point output.upload.url straight at a presigned URL from S3, GCS, Azure Blob, Cloudflare R2, etc. — each provider accepts signed PUT requests with a raw body. Set output.upload.headers to whatever the presigner expects (e.g. specific Content-Type, x-amz-* metadata). Protected headers (Content-Type, User-Agent) can't be overridden, so make sure the presigned URL is signed against the content type Typograph will send (see the list above).
Custom Headers
Include authentication headers when downloading from or uploading to protected URLs:
{
"input": {
"template": {
"url": "https://example.com/private/template.json",
"headers": {
"Authorization": "Bearer your-storage-token"
}
},
"manifest": {
"url": "https://example.com/private/manifest.json",
"headers": {
"Authorization": "Bearer your-storage-token"
}
}
},
"output": {
"upload": {
"url": "https://example.com/webhook/upload",
"headers": {
"X-API-Key": "your-api-key"
}
}
}
}
Complete Example
Generate a PDF invoice with watermark and custom headers:
curl -X POST https://api.typograph.nl/v1/publisher/jobs \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tag": "invoice-premium-001",
"input": {
"template": {
"url": "https://storage.example.com/templates/invoice.json",
"headers": {
"Authorization": "Bearer storage-token"
}
},
"manifest": {
"url": "https://storage.example.com/templates/manifest.json",
"headers": {
"Authorization": "Bearer storage-token"
}
}
},
"output": {
"upload": {
"url": "https://webhook.example.com/documents",
"headers": {
"X-Webhook-Secret": "secret-key"
}
},
"config": {
"type": "pdf",
"color_mode": "cmyk",
"bleed": 3,
"crop_marks": true,
"watermark": {
"type": "center",
"image": {
"url": "https://storage.example.com/draft-watermark.png",
"headers": {
"Authorization": "Bearer storage-token"
}
},
"width": 100,
"height": 30,
"opacity": 0.2
}
}
}
}'