Skip to content

Renders API

Download previously rendered PDF invoices.

Download Render

GET /api/v1/renders/{render_id}/download

Returns the PDF binary with Content-Type: application/pdf.

There are two ways to authorise this request, and you usually want the first.

The signed link. Every render response carries a complete download_url with a token on it. That token is the permission — follow the URL with no credentials at all and you get the PDF. Put it in a browser, an email, or a chat message; hand it to whoever needs the invoice. The signature grants exactly one thing: read this one render, until this render's expires_at.

Your API key. The endpoint also accepts normal authentication with no token, which is what an integration that builds the path itself has always done. Nothing about that changed.

# download_url comes back complete from any render call. No key, no joining.
curl "https://invoicepdfs.com/api/v1/renders/rnd_01ABC/download?token=eyJrIjoi..." \
  --output invoice.pdf

Self-hosting? The origin comes from PUBLIC_BASE_URL; unset, it is the origin each request arrived on.

curl https://invoicepdfs.com/api/v1/renders/rnd_01ABC/download \
  -H "Authorization: Bearer inv_live_abc123..." \
  --output invoice.pdf
import httpx

resp = httpx.get(
    "https://invoicepdfs.com/api/v1/renders/rnd_01ABC/download",
    headers={"Authorization": "Bearer inv_live_abc123..."},
)
with open("invoice.pdf", "wb") as f:
    f.write(resp.content)
Try it

Get Render Metadata

GET /api/v1/renders/{render_id}

Response:

{
  "data": {
    "id": "rnd_01ABC",
    "status": "completed",
    "document_type": "invoice",
    "format": "pdf",
    "download_url": "https://invoicepdfs.com/api/v1/renders/rnd_01ABC/download?token=eyJrIjoicmVuZGVyIiwiaSI6InJuZF8wMUFCQyIsImUiOjE3ODQ4NTEyMDB9.abc123...",
    "calculation": {
      "subtotal": { "amount": "1500.00", "currency": "USD" },
      "tax_total": { "amount": "133.13", "currency": "USD" },
      "total": { "amount": "1633.13", "currency": "USD" }
    },
    "expires_at": "2026-07-20T01:00:00Z",
    "created_at": "2026-07-20T00:00:00Z"
  }
}
Field Description
status Render status (completed)
document_type Type of document rendered
format Output format (pdf)
download_url Complete, signed URL to the PDF. Follow it as-is — the token carries the permission, so no API key is needed and nothing needs joining. Valid until expires_at
calculation.subtotal Sum of line item net amounts, as a Money object
calculation.tax_total Total taxes (inclusive + exclusive), as a Money object
calculation.total Final document total, as a Money object
expires_at When the render, and the signature on its download_url, stop working. Set by expires_in on the render request (60s to 7 days, default 1 hour)
created_at When the render was generated

Render expiration

Renders expire after the expires_in duration specified at render time (60 seconds to 7 days, default 1 hour). After expiration, the download endpoint returns 404 — for the API key and the signed link alike. Re-render the invoice to get a new download URL.

Treat a signed link like the invoice itself

The token needs no API key, which is the point — but it means anyone holding the URL can fetch that PDF until it expires. It grants nothing else: it names one render, it cannot be edited, and it cannot be used to reach anything else on the account. Keep expires_in as short as the workflow allows, and prefer your API key for server-to-server calls where a link buys you nothing.

Try it