Skip to content

Browse and download documents

Every render made with persist=true (the default) is stored, and you can find it again later — list it, filter it, and download the PDF. This is how you build a “my documents” view, re-send a document a user lost, or reconcile what actually rendered after a batch.

  • Documents only exist here if they were rendered with persist=true. A persist=false render is never stored and never appears.
  • Your organisation’s retention policy may purge the PDF while keeping the metadata. Plan for that — see handling purged PDFs.
  1. List documents with paging, sorting and filters.

    The default sort is renderedAt ascending and the default page size is 25. You’ll almost always want sortDirection: desc for a “most recent first” view.

  2. Read total to know how far you have to page.

    It’s the full count matching your filters, independent of skip / take.

  3. Advance skip until there’s nothing left.

    Every SDK exposes a “more pages?” flag computed client-side, so the loop needs no extra request.

  4. Check isPdfDeleted before downloading.

    It’s true exactly when the download would fail with 410 PdfDeleted — so you can filter purged documents out in the listing pass.

  5. Download by id, not by viewUrl.

    viewUrl is a signed, time-limited link meant for a browser. The download endpoint re-authorises every call.

List the most recent production documents and download the ones whose PDFs are still stored.

Terminal window
# Page 1 of production documents, newest first
curl -G "https://pagr-prd-api-public.azurewebsites.net/v1/documents" \
-H "Authorization: Bearer pagr_prod_xxxxxxxx" \
--data-urlencode "take=50" \
--data-urlencode "sortBy=renderedAt" \
--data-urlencode "sortDirection=desc" \
--data-urlencode "filters[0].field=environment" \
--data-urlencode "filters[0].value=production"
# Download one (skip any whose isPdfDeleted is true)
curl "https://pagr-prd-api-public.azurewebsites.net/v1/documents/$DOC_ID/file" \
-H "Authorization: Bearer pagr_prod_xxxxxxxx" \
--output "$DOC_ID.pdf"

The full field/operator tables live in Listing & pagination. These are the ones you’ll reach for most:

Goal Filter
Only real, unwatermarked output environment eq production
Everything from one template template.guid eq <templateId>
A date range Two filters together: renderedAt gte <start> and renderedAt lte <end>
A specific language variant language eq fr
Documents by name documentName contains Invoice, or search=Invoice
Large documents only pageCount gte 10 or fileSizeBytes gte 1000000

Filters combine with AND. There’s no OR — run separate queries and merge.

Metadata and PDF have different lifetimes. Retention can remove the file while the record stays, at which point:

  • The document still appears in listings and GET /v1/documents/{id}.
  • isPdfDeleted is true.
  • GET /v1/documents/{id}/file returns 410 Gone with code PdfDeleted.
from pagr import ApiError, NotFoundError
try:
pdf = await client.download_document(doc_id)
except ApiError as exc:
if exc.status_code == 410: # code == "PdfDeleted"
print("The PDF was purged by retention; metadata remains.")
else:
raise
except NotFoundError:
print("No such document.")
  • Offset paging drifts under concurrent renders. New documents arrive while you page, shifting the offsets. If exactness matters, add an upper bound — renderedAt lte a timestamp you captured before starting — so the result set can’t grow underneath you.
  • take is clamped to 1–200, silently. Asking for 5,000 returns 200 with no warning. Read take off the response if you depend on the page size.
  • Raise the timeout per download, not globally. The client-wide default is 30 seconds, which is fine for listings and tight for a large PDF over a slow link. Every SDK’s download method accepts a per-call override.
  • Downloads are reads, so the SDKs retry them. A transient 5xx or connection drop is retried with backoff. 410 and 404 are not retried — they’re deterministic.
  • persist=false renders are invisible here, permanently. There’s no way to recover a non-persisted render; the bytes existed only in that one response.
  • documentType is returned but not queryable. You can read Template / Invoice off each document, but you can’t filter or sort on it.
  • Test and production documents live in the same list. Filter on environment unless you genuinely want both — watermarked test output mixed into a customer-facing list is a common oversight.