Skip to main content

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

MethodPathScopesDescription
GET/v1/publisher/jobspublisher / publisher:readList generation jobs
POST/v1/publisher/jobspublisher / publisher:writeCreate a generation job
GET/v1/publisher/jobs/{path}publisher / publisher:readJob detail and output files
GET/health/publisherService 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

PropertyTypeRequiredDescription
templateobjectYesTypograph template JSON
template.urlstringYesURL to template file
template.headersobjectNoHTTP headers for downloading
manifestobjectYesTypograph manifest JSON
manifest.urlstringYesURL to manifest file
manifest.headersobjectNoHTTP headers for downloading
csvobjectNoCSV data file for batch processing
csv.urlstringNoURL to CSV file
csv.headersobjectNoHTTP headers for downloading
Coming from the Converter Service?

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

PropertyTypeRequiredDescription
uploadobjectYesTarget for generated files
upload.urlstringYesURL to upload generated files
upload.headersobjectNoHTTP headers for uploading
configobjectYesGenerator configuration

Output Formats

FormatDescription
pdfPDF document
pngPNG image (one per page)
jpg / jpegJPEG image (one per page)
webpWebP image (one per page)

Generator Configuration

Configure the output with the output.config object:

PropertyTypeDescription
typestringOutput format: pdf, png, jpg, jpeg, webp
dpiintegerResolution for images (36-600, default: 300)
qualityintegerQuality for lossy formats (0-100, default: 90)
color_modestringColor space: rgb or cmyk
bleednumberPrint bleed in millimeters (0-25.4)
pagesstringPage range, e.g., "1-5,8-10"
crop_marksbooleanInclude crop marks for printing
spreads_as_single_pagesbooleanSplit spread pages
watermarkobjectWatermark 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
}
}
}
}
PropertyTypeDescription
typestringPositioning: center or repeat_horizontal
imageobjectWatermark image URL and optional headers
image.urlstringURL to PNG watermark image
image.headersobjectOptional HTTP headers for downloading (max 5)
widthnumberWidth in millimeters
heightnumberHeight in millimeters
opacitynumberTransparency (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_id to 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

TypeDescription
outputGenerated document (default)
templateOriginal template file
manifestOriginal manifest file
csvCSV 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:

PropertyValue
MethodPUT
URLExactly the URL you provided in output.upload.url (no redirects are followed)
Content-TypeDetected from the file — e.g. application/pdf, image/png, image/jpeg, image/webp
User-AgentTypograph/Util-Upload
Custom headersWhatever you passed in output.upload.headers (merged in, can't override Content-Type or User-Agent)
BodyRaw file bytes, streamed (no multipart / form-data wrapper)
Connection timeout10 seconds
Transfer timeout300 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
}
}
}
}'