Skip to main content
The Tipar API is a small, synchronous HTTP API. There is one endpoint you’ll use in production — POST /generate — plus a public playground endpoint and a health check.

Base URL

https://api.tipar.dev
All requests are HTTPS. .dev is on the HSTS preload list, so plain HTTP is never served.

Authentication

POST /generate requires an API key sent as a bearer token. See Authentication.
Authorization: Bearer tipar_live_<32 characters>

Requests and responses

  • Request bodies are JSON (Content-Type: application/json).
  • A successful generate response is the PDF itselfContent-Type: application/pdf, the raw bytes as the body. There’s no JSON envelope around it.
  • The API is synchronous. You get the finished PDF in the response to your request. There’s no job to create, no status to poll, no webhook to wait for.

Endpoints

MethodPathAuthPurpose
POST/generateAPI keyRender a PDF from template + data.
POST/v1/playground/generatenoneAnonymous, watermarked render for trying things out.
GET/healthnoneLiveness + version. Returns { "status": "ok", "version": "…" }.
API keys themselves are created and revoked in the dashboard, not through this API. The key-management routes are part of the dashboard’s signed-in session, not the programmatic surface.

Errors

Every error is an RFC 7807 Problem Details document, served as application/problem+json:
{
  "title": "Template is structurally invalid",
  "status": 422,
  "detail": "body has 2 cell(s), columns has 3",
  "errors": [
    { "code": "template.page.content.body.row", "message": "body has 2 cell(s), columns has 3" }
  ]
}
  • title, status, and (usually) detail are always present.
  • errors is an array of { code, message } objects, present on most failures. The code is a stable, machine-readable string — branch on it; show message to humans. (It’s a top-level field, per the Problem Details extension convention — not nested under extensions.)
A full catalogue of status codes and code values is on the errors page.

Rate limits

Limits are enforced per API key (and per IP for anonymous endpoints). Exceeding one returns 429 Too Many Requests with a Retry-After header (seconds).
EndpointLimitPartition
POST /generate60 requests/minute sustained, bursts to 120per API key
POST /v1/playground/generate5 renders/dayper IP
The /generate limiter is a token bucket: it refills at 60 permits per minute and lets you spend up to 120 in a burst. The 429 body uses the standard error envelope with code: "rate_limit.exceeded".
Build for 429: on receiving one, wait for the Retry-After seconds and retry. A token bucket means short bursts are fine — you only get limited if your sustained rate exceeds the refill.

Quotas and billing

Separate from the per-minute rate limit, each plan includes a monthly document quota. When you reach it, /generate returns 402 Payment Required with code: "quota.exceeded" — the request is blocked, not billed as overage. You upgrade deliberately, or wait for the month to roll over.
{
  "title": "Monthly quota exceeded",
  "status": 402,
  "detail": "Monthly document quota reached for your plan. Upgrade to keep generating.",
  "errors": [
    { "code": "quota.exceeded", "message": "Monthly document quota reached for your plan. Upgrade to keep generating." }
  ]
}
Quota sizes per plan are on the pricing page.

Request size

EndpointMax request bodyOn exceeding
POST /generate4 MB413 Payload Too Large
POST /v1/playground/generate256 KB413 Payload Too Large
The body includes any base64-encoded images — they’re the usual reason a request gets large.