Skip to main content

API Overview

The Typograph API lets your systems, and AI agents acting for your users, manage templates and projects, generate press-ready documents, convert files, and collaborate. For AI agents, the MCP server offers the same capabilities as tools.

An integration built on names from before Typograph's naming convention: Renamed fields and paths lists every old name and its new one.

Base URL​

https://api.typograph.nl

API Gateway Architecture​

All API requests go through the Typograph API Gateway, which handles:

  • Authentication - OAuth 2.0 token validation
  • Authorization - Scope-based access control
  • Rate Limiting - Request throttling per client
  • Request Routing - Proxying to internal microservices

Services​

The API consists of these services:

ServiceDescriptionBase PathScope
IdentityUsers, sessions, organizations, OAuth clients/v1/identity/identity
FileTeams, projects, templates, media, sharing/v1/file/file
PublisherPDF and image generation/v1/publisher/publisher
ConverterFile format conversion/v1/converter/converter
DocumentTemplate validation and schema upgrade/v1/document/document
WebhookEvent subscriptions and deliveries/v1/webhook/webhook
SubscriptionSubscription plan, usage, add-ons/v1/subscription/subscription

Quick Start​

1. Get an Access Token​

curl -X POST https://api.typograph.nl/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=file document publisher"

2. Make API Requests​

curl https://api.typograph.nl/v1/file/teams \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Rate Limiting​

Rate limits are tiered by your organization's subscription and split across four layers (burst, hourly, daily, monthly) and five endpoint categories (general, file, converter, publisher, webhook), plus ai for the portal's AI assistant. Anonymous requests are capped at 100/hour on the general category only.

Rate Limit Headers​

Responses use the IETF draft rate-limit headers:

HeaderDescription
RateLimitCurrent status, format: "category";r=remaining;t=reset_seconds
RateLimit-PolicyConfigured policies (quota + window per layer)
Retry-AfterOn 429, seconds until you should retry

Example:

RateLimit: "general";r=3542;t=1800
RateLimit-Policy: "general_hourly";q=3600;w=3600, "general_burst";q=50;w=60

Rate Limit Exceeded​

{
"error": "rate_limit_exceeded",
"error_description": "Hourly rate limit exceeded for general endpoints."
}

See Rate Limiting for the full breakdown, per-layer error codes, and handler patterns.

Request Headers​

Required Headers​

HeaderDescription
AuthorizationBearer {access_token} for authenticated requests
Content-Typeapplication/json for request bodies

Response Headers​

HeaderDescription
X-Powered-ByTypograph (www.typograph.nl)
X-Typograph-Request-IdUUID v7 correlation ID for support
X-Typograph-User-IdThe ID of the person your token acts for; absent for a token without a person (client credentials)
X-Typograph-Organization-IdThe ID of the organization the request worked in, the one your token reaches (Which organization a token reaches)
RateLimitCurrent window status (see Rate Limiting)
RateLimit-PolicyConfigured rate-limit policies

Asynchronous Processing​

Most operations are processed asynchronously using a job-based architecture:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ Create Job │ ──▶ │ Processing │ ──▶ │ Completed │ ──▶ │ Download │
│ (POST) │ │ (async) │ │ (poll) │ │ (GET) │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
  1. Create Job - Submit a request, receive a job ID with queued status
  2. Processing - Job progresses through stages (downloading, processing, uploading)
  3. Completion - Job reaches completed or failed status
  4. Download - Retrieve generated files using the job ID

Webhook Notifications​

Instead of polling, subscribe to webhooks to receive real-time notifications:

EventDescription
publication.completedPublisher job finished successfully
publication.failedPublisher job failed
conversion.completedConverter job finished successfully
conversion.failedConverter job failed

See Webhooks for setup, delivery semantics, and signature verification.

File Retention​

Generated files are available for 4 days after job completion. After this period, files expire and return 410 Gone.

Job Status Values​

Publisher Job States​

StatusDescription
queuedJob is waiting to be processed
queued_by_csv_processorChild job queued by CSV batch processing
queued_by_image_generatorJob queued for image generation
downloadingDownloading template and data files
processing_csvProcessing CSV data file
waiting_for_rowsA CSV merge whose rows are queued, waiting for them to print; printed_row_count and failed_row_count show how far it is
mergingA CSV merge whose rows have all ended, being finished
generatingGenerating output document
uploadingUploading generated files
completedJob finished successfully
failedJob encountered an error
expiredGenerated files have expired

Converter Job States​

StatusDescription
queuedJob is waiting to be processed
downloadingDownloading source file
convertingConverting file to target format
uploadingUploading converted file
completedConversion finished successfully
failedConversion encountered an error
expiredConverted files have expired

Error Handling​

The API uses standard HTTP status codes:

CodeDescription
200Success
201Resource created
204Success with no content
400Invalid request parameters
401Authentication required
403Insufficient permissions (scope)
404Resource not found
410File expired (no longer available)
422Validation failure
429Rate limit exceeded
500Internal server error
503Service unavailable

Error Response Format​

Error responses follow a hybrid format compatible with OAuth 2.0 (RFC 6749) and inspired by RFC 9457 Problem Details:

{
"error": "invalid_request",
"error_description": "Email is required.",
"request_id": "019397ab-cdef-7890-abcd-ef1234567890"
}
FieldTypeDescription
errorstringMachine-readable error code
error_descriptionstringHuman-readable error message
request_idstringUUID v7 correlation ID (also in X-Typograph-Request-Id header)
typestring(optional) URI to error documentation
detailsarray(optional) Field-level validation errors

Standard Error Codes​

HTTP StatusError CodeDescription
400invalid_requestMalformed request or missing parameters
400validation_errorField validation failures
401unauthorizedMissing or invalid authentication
401invalid_tokenToken expired or revoked
403access_deniedInsufficient permissions or scope
404not_foundResource does not exist
405method_not_allowedHTTP method not allowed
409conflictResource conflict (duplicate, concurrent edit)
409in_trashWhat the call works on is in the trash, or in a project or team that is: restore it first (see File Service)
409container_in_trashA restore of something whose project or team is still in the trash
409rotation_in_progressA webhook secret rotation inside the 24-hour overlap of the previous one (see Rotate Secret)
410goneThe files of a publisher or converter job that has expired (see File Retention)
422validation_errorValid syntax but semantic validation failed
429rate_limit_exceededToo many requests
500server_errorInternal server error
503service_unavailableService temporarily unavailable

A few endpoints return a code of their own, listed with the endpoint. Using a premade template (File Service) can answer 400 with premade_template_not_ready (no package yet), premade_template_unavailable (the package could not be downloaded) or premade_template_invalid (the package is not an importable zip).

Validation Errors​

When validation fails, the response includes a details array with field-level errors:

{
"error": "validation_error",
"error_description": "Request validation failed",
"request_id": "019397ab-cdef-7890-abcd-ef1234567890",
"details": [
{
"field": "email",
"code": "required",
"message": "Email is required."
},
{
"field": "handle",
"code": "too_long",
"message": "Handle must be at most 255 characters."
}
]
}

Request Correlation​

Every request is assigned a unique request_id (UUID v7):

  • Returned in the X-Typograph-Request-Id response header on all responses
  • Included in the JSON body for error responses
  • Used for request tracing and debugging

When contacting support, always include the request_id from the error response for faster issue resolution.

API Discovery​

OAuth Server Metadata​

Discover OAuth endpoints programmatically:

curl https://api.typograph.nl/.well-known/oauth-authorization-server

API Home Document​

Get API metadata and the gateway's routes, with their methods and scopes. It needs no token and counts against the anonymous rate limit:

curl https://api.typograph.nl/

It answers name, version, website_url, portal_url and documentation_url, the OAuth endpoints by name, and under resources the routes of each service, each with its path, methods, scopes and authentication: public (no token), token (an access token) or internal (for the platform's own services).

Supports JSON Home format (RFC draft):

curl https://api.typograph.nl/ \
-H "Accept: application/json-home"

OpenAPI Reference​

Explore the complete API specification with the interactive Swagger UI:

Open OpenAPI Reference →

Using the API​

Typograph's REST API speaks standard HTTP + JSON, so any HTTP client works — fetch/axios in the browser or Node.js, requests in Python, cURL, Postman, etc. See Authentication for how to obtain an access token, and browse the OpenAPI Reference for the full endpoint surface.

Support​