pdfs-build Template gallery API
The pdfs.build design library over the API: list the designs, preview one, and copy one into your organization in a single call. The Odoo module's "Add designs for Odoo" button uses these.
The pdfs.build design library over the API: list the designs, preview one, and copy one into your organization in a single call. The Odoo module's "Add designs for Odoo" button uses these.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/pdfs-build:pdfs-build-template-gallery-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: pdfs.build Template gallery API
version: '2.0'
summary: Render PDFs from templates, manage templates, webhooks, embedded editor sessions and delegated agent access.
description: 'All requests are authenticated with an organization-scoped API key (`prs_...`) sent as a Bearer token. Create keys under **Settings → API Keys** in the dashboard or with the MCP `create_api_key` tool. Keys are shown once.
The organization in every `/v2` URL must match the key''s organization, otherwise the request fails with `403 organization_scope_mismatch`.
**Errors** are JSON with a top-level `error` string — a machine-readable code for most failures, a phrase for a few legacy ones — usually alongside a human-readable `message`. Data validation and template compilation failures carry `details` / `diagnostics` instead of a `message`.
**Versions.** `/v2` addresses templates by an external id you control. The legacy `/v1` routes identify templates by their generated internal id and remain supported for existing integrations.
**Timestamps.** Objects served by the render service (templates, render jobs, logs, webhook endpoints) carry UTC timestamps in ISO 8601 form without a timezone suffix, e.g. `2026-08-30T12:00:00.123456`. Embedded-editor sessions and delegated access return RFC 3339 with a trailing `Z`.
The narrative guide — authentication, webhook signatures, the MCP server, migrating from v1 — lives at https://pdfs.build/docs/ (Markdown mirror: https://pdfs.build/docs.md).'
contact:
name: pdfs.build
url: https://pdfs.build
email: hello@pdfs.build
termsOfService: https://pdfs.build/terms/
license:
name: Proprietary
url: https://pdfs.build/terms/
servers:
- url: https://api.pdfs.build
description: Production
security:
- apiKey: []
tags:
- name: Template gallery
description: 'The pdfs.build design library over the API: list the designs, preview one, and copy one into your organization in a single call. The Odoo module''s "Add designs for Odoo" button uses these.'
paths:
/v2/organizations/{organizationId}/gallery:
parameters:
- $ref: '#/components/parameters/organizationId'
get:
tags:
- Template gallery
summary: List gallery designs
operationId: listGalleryTemplates
description: Every design in the pdfs.build gallery, without its source. Filter with `category` (for example `odoo`, whose designs are named after Odoo's own fields) or `useCase` (for example `odoo-invoice`). The `id` is what `POST …/templates/from-gallery` takes.
parameters:
- name: category
in: query
schema:
type: string
description: Only designs in this category, e.g. `odoo`, `finance`.
- name: useCase
in: query
schema:
type: string
description: Only designs for this document type, e.g. `odoo-invoice`, `invoice`.
responses:
'200':
description: The matching designs and the per-category counts of the whole library.
content:
application/json:
schema:
$ref: '#/components/schemas/GalleryListing'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/OrganizationScopeMismatch'
'502':
$ref: '#/components/responses/BackendUnavailable'
/v2/organizations/{organizationId}/gallery/{galleryId}/preview:
parameters:
- $ref: '#/components/parameters/organizationId'
- $ref: '#/components/parameters/galleryId'
get:
tags:
- Template gallery
summary: Preview a gallery design
operationId: previewGalleryTemplate
description: Page 1 of the design rendered from its own sample data, as a PNG. Rendered once and cached, so the first call takes a second and later ones do not.
responses:
'200':
description: The page-1 render.
content:
image/png:
schema:
type: string
format: binary
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/OrganizationScopeMismatch'
'404':
description: '`gallery_template_not_found`, or `preview_unavailable` when the design did not render.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'502':
$ref: '#/components/responses/BackendUnavailable'
/v2/organizations/{organizationId}/templates/from-gallery:
parameters:
- $ref: '#/components/parameters/organizationId'
post:
tags:
- Template gallery
summary: Add a gallery design to the organization
operationId: createTemplateFromGallery
description: 'Copies a gallery design into your organization as a template of your own and, unless `publish` is `false`, publishes it in the same call so the render API can use it at once. Give it an `externalId` to render it by a slug of your choosing; the default is the new template''s UUID. The copy is yours from then on: edits, versions and the published-template quota are the organization''s, and the gallery is never rendered from directly.'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FromGalleryRequest'
responses:
'201':
description: The new template. `publishedVersion` is the version the API serves, or `null` when `publish` was `false`.
content:
application/json:
schema:
$ref: '#/components/schemas/FromGalleryResult'
'400':
description: '`invalid_from_gallery_request` (with `issues`) or `invalid_external_id`.'
content:
application/json:
schema:
anyOf:
- $ref: '#/components/schemas/ValidationIssues'
- $ref: '#/components/schemas/Error'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
description: '`template_limit_reached`: publishing one more template would pass the plan''s published-template limit.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
$ref: '#/components/responses/OrganizationScopeMismatch'
'404':
description: '`gallery_template_not_found`.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: '`external_id_conflict`: the organization already has a template with that external id.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: The design failed the compile gate; the draft is kept and returned as `template`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'502':
$ref: '#/components/responses/BackendUnavailable'
components:
schemas:
FromGalleryRequest:
type: object
required:
- galleryId
properties:
galleryId:
type: string
example: odoo-invoice-stub-band
externalId:
type: string
description: The slug to render the copy by. 1-128 URL-safe characters; defaults to the new template's UUID.
name:
type: string
description: A name for the copy; defaults to the design's.
publish:
type: boolean
default: true
description: '`false` leaves the copy as a draft for the editor instead of publishing it.'
FromGalleryResult:
type: object
required:
- id
- externalId
- galleryId
- name
- status
- publishedVersion
properties:
id:
type: string
format: uuid
externalId:
type: string
galleryId:
type: string
name:
type: string
status:
type: string
enum:
- draft
- published
publishedVersion:
type: integer
nullable: true
GalleryListing:
type: object
required:
- templates
- categories
properties:
templates:
type: array
items:
$ref: '#/components/schemas/GalleryTemplate'
categories:
type: array
description: Every category in the library with its design count, whatever the filter.
items:
type: object
required:
- id
- count
properties:
id:
type: string
count:
type: integer
ValidationIssues:
type: object
required:
- error
- issues
properties:
error:
type: string
issues:
type: object
description: Per-field problems, keyed by field name.
additionalProperties: true
Error:
type: object
required:
- error
properties:
error:
type: string
description: Machine-readable code (e.g. `draft_not_renderable`) or, for a few legacy failures, a short phrase.
message:
type: string
description: Human-readable detail. Present on most coded errors.
example:
error: draft_not_renderable
message: Only published templates can be rendered via the API. Publish this template first.
GalleryTemplate:
type: object
required:
- id
- name
- useCase
- category
- page
- pages
properties:
id:
type: string
example: odoo-invoice-stub-band
name:
type: string
example: Odoo Invoice — Stub Band
description:
type: string
useCase:
type: string
example: odoo-invoice
category:
type: string
example: odoo
archetype:
type: string
example: band-header
palette:
type: string
example: royal-bone
tier:
type: string
example: expressive
page:
type: string
example: A4-portrait
pages:
type: integer
example: 1
responses:
BackendUnavailable:
description: The service that owns this resource could not be reached. Safe to retry.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: embed_backend_unavailable
OrganizationScopeMismatch:
description: The organization in the URL does not match the API key's organization.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: organization_scope_mismatch
message: The organization in the URL does not match the API key organization
Unauthorized:
description: Missing, invalid or expired API key.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Unauthorized
parameters:
organizationId:
name: organizationId
in: path
required: true
schema:
type: string
description: Your organization id. Must match the API key's organization.
example: org_abc
galleryId:
name: galleryId
in: path
required: true
schema:
type: string
description: A gallery design id, `<use-case>-<variant>`, as listed by `GET …/gallery`; e.g. `odoo-invoice-stub-band`.
securitySchemes:
apiKey:
type: http
scheme: bearer
bearerFormat: prs_...
description: Organization-scoped API key, created under Settings → API Keys or with the MCP `create_api_key` tool.
externalDocs:
description: 'API guide: authentication, errors, webhooks, MCP, migrating from v1'
url: https://pdfs.build/docs/