Skip to content
CastPDF
API reference

Documents and files

List your generated documents, download stored PDFs through signed links, and fetch first-page thumbnails, your logo and your fonts.

On this page

Every PDF you generate becomes a document in your workspace's log. GET /v1/documents pages through that log. The other endpoints on this page serve files through signed links: URLs that carry their own exp and sig query parameters, so they work without an API key and can be handed to a browser or a customer. You never build these URLs yourself; the API returns them as url, thumbnail_url or brand.logo_url, and a link that was changed in any way stops working.

GET /v1/documents

Your workspace's documents, newest first. Test keys see only test documents; live keys see all of them.

Request
curl "https://api.castpdf.com/v1/documents?limit=50" \
  -H "Authorization: Bearer YOUR_API_KEY"
let before = null;
do {
  const url = new URL('https://api.castpdf.com/v1/documents');
  url.searchParams.set('limit', '100');
  if (before) url.searchParams.set('before', before);
  const res = await fetch(url, { headers: { Authorization: 'Bearer YOUR_API_KEY' } });
  const page = await res.json();
  for (const doc of page.data) console.log(doc.id, doc.status);
  before = page.next_before;
} while (before);
import requests

params = {"limit": 100}
while True:
    res = requests.get(
        "https://api.castpdf.com/v1/documents",
        headers={"Authorization": "Bearer YOUR_API_KEY"},
        params=params,
        timeout=30,
    )
    page = res.json()
    for doc in page["data"]:
        print(doc["id"], doc["status"])
    if not page["next_before"]:
        break
    params["before"] = page["next_before"]
200
{
  "data": [
    {
      "id": "3f0c9a4e-6b1d-4c2a-9a57-0d8e4b7f21c3",
      "status": "succeeded",
      "pages": 2,
      "bytes": 48213,
      "mode": "print",
      "test": false,
      "template_id": "8d1f2c3b-4a5e-4f60-9b7a-1c2d3e4f5a6b",
      "template_version": 4,
      "error_code": null,
      "created_at": "2026-09-30T10:15:02.123Z",
      "expires_at": "2026-10-07T10:15:02.123Z",
      "url": "https://api.castpdf.com/v1/files/3f0c9a4e-6b1d-4c2a-9a57-0d8e4b7f21c3?exp=1791368102&sig=Jx0k...",
      "thumbnail_url": "https://api.castpdf.com/v1/thumbnails/documents/3f0c9a4e-6b1d-4c2a-9a57-0d8e4b7f21c3.png?exp=1790935200&sig=Qm4t...",
      "delivery": null
    }
  ],
  "next_before": "2026-09-30T10:15:02.123456Z_3f0c9a4e-6b1d-4c2a-9a57-0d8e4b7f21c3"
}
Query parameterDescription
limit1 to 100. Default 20.
beforeThe previous page's next_before, to get the next page. A bare ISO 8601 timestamp also works and means "older than this".

The response has cache-control: no-store. Each item is a document object, the same as GET /v1/pdf/:id returns; queued background PDFs appear only once they are made. next_before is null on the last page. Treat it as opaque and pass it back unchanged: it keeps documents made in the same instant from being skipped or repeated. Document records are kept for 120 days.

CodeWhen
invalid_request (400)limit is out of range, or before is not a cursor or a valid timestamp

GET /v1/files/:id

Downloads a stored PDF. It is the url returned by POST /v1/pdf (with response: "url"), GET /v1/pdf/:id and GET /v1/documents, and it needs no API key. It stops working when the file expires.

curl
curl "https://api.castpdf.com/v1/files/3f0c9a4e-6b1d-4c2a-9a57-0d8e4b7f21c3?exp=1791368102&sig=Jx0k...&download=1" \
  --output invoice-042.pdf
Query parameterDescription
exp, sigRequiredThe expiry and signature, as returned in the link.
download1 to save the file instead of opening it in the browser (content-disposition: attachment). It is not part of the signature, so you can add it to any link.

200 with the file and these headers:

HeaderDescription
content-typeapplication/pdf, or application/xml for an XRechnung e-invoice
content-dispositioninline; filename="invoice-042.pdf" (opens in the browser), or attachment with download=1
cache-controlprivate, with a max-age of 300 seconds
content-security-policysandbox
x-content-type-optionsnosniff
CodeWhen
forbidden (403)The signature does not match
file_expired (410)The link expired, or the file is no longer stored

GET /v1/brand-assets/:file

Serves your team's logo or one of its uploaded fonts (set in the dashboard: Simple mode, Design panel). Templates get the logo's link as brand.logo_url (see your brand), and the dashboard shows it. The sig query parameter signs it, so it needs no API key; it does not expire, and a replaced logo gets a new URL. When CastPDF renders your PDFs it uses these files directly, without fetching the URL.

curl
curl "https://api.castpdf.com/v1/brand-assets/0b6f2a4c-9d1e-4f3a-8b7c-5e6d7a8b9c10.png?sig=Hk2p..." --output logo.png

200 with the file: image/png or image/jpeg for a logo (an SVG logo is turned into a PNG when you upload it), font/woff2, font/ttf or font/otf for a font.

HeaderDescription
cache-controlpublic, max-age=86400: a deleted file stops being served within a day
access-control-allow-origin*, so web pages may load your fonts
cross-origin-resource-policycross-origin
content-security-policysandbox; default-src 'none'; style-src 'unsafe-inline'
x-content-type-optionsnosniff
CodeWhen
forbidden (403)The signature does not match
not_found (404)The file was replaced or deleted

GET /v1/thumbnails/documents/:file

A PNG of a stored PDF's first page, 480 px wide: the thumbnail_url of a document, which is null when nothing is stored. The :file is the document id followed by .png. Signed by its exp and sig parameters, so it needs no API key. The image is made from the stored PDF the first time it is asked for (nothing is rendered or counted) and is removed with the PDF.

curl
curl "https://api.castpdf.com/v1/thumbnails/documents/3f0c9a4e-6b1d-4c2a-9a57-0d8e4b7f21c3.png?exp=1790935200&sig=Qm4t..." \
  --output page-1.png

200 with content-type: image/png, cache-control: private, max-age=3600, content-security-policy: default-src 'none' and x-content-type-options: nosniff. A thumbnail link lasts one to two hours (it is rounded to the hour, so the URL stays the same for an hour and browsers can cache it); ask the API again for a fresh one.

CodeWhen
forbidden (403)A wrong or expired signature
not_found (404)The PDF is no longer stored

GET /v1/thumbnails/templates/:file

A PNG of the first page of a template version, rendered with that version's sample data, 480 px wide. It is the thumbnail_url of a template; the :file is the template id followed by .png, and the v query parameter names the version, so every new version gets a new URL. The image is made the first time it is asked for, as a preview: not counted, not stored as a document and not watermarked. It is signed like the document thumbnails, lasts as long, and has the same headers.

curl
curl "https://api.castpdf.com/v1/thumbnails/templates/8d1f2c3b-4a5e-4f60-9b7a-1c2d3e4f5a6b.png?v=4&exp=1790935200&sig=Lw8d..." \
  --output template.png
CodeWhen
invalid_request (400)v is not a version number
forbidden (403)A wrong or expired signature
not_found (404)The template was deleted, or the version is newer than its current one
rate_limited (429)Every concurrent render slot of your team is busy; try again in a moment
Updated Something unclear? [email protected], a real person replies.