Skip to main content

Pagination

QRForge API endpoints that return collections (e.g., List Projects, List QR Codes) use a cursor‑based pagination model designed for scalability and enterprise‑grade performance.

This document explains how pagination works, how to retrieve the next page, and how to handle edge cases.


Overview​

QRForge uses cursor-based pagination, not offset-based pagination.

Cursor pagination is more stable and performant at scale because it avoids skipping records and remains efficient on large Firestore datasets.

Each paginated endpoint returns:

  • items: Array of results
  • next_page_token: Opaque string or null
  • Other metadata depending on the endpoint

If next_page_token is present in the response, its value must be passed back into the API — as the page_token request parameter — to retrieve the next page.


Request Parameters​

page_size (optional)​

  • Defines how many items to return per page.
  • Integer between 1 and 100.
  • If omitted or non-numeric, the API defaults to 20 items.
  • Values above 100 are silently capped at 100.

An out-of-range page_size is never rejected with an error — it's always normalized to a safe value instead:

  • page_size=1 → returns exactly one item (if available)
  • page_size=0 or a negative value → normalized up (to 1 on some endpoints, or back to the default of 20 on others — never an error either way)

page_token (optional)​

  • Used to continue fetching results from the previous page.
  • Set this to the next_page_token value returned in the previous response.
  • Opaque value generated by the backend.
  • Must never be modified or decoded by the client.

Example call:

GET /v1/qr-codes?page_size=50&page_token=eyJjIjoxMjM0NTY3ODkwfQ

Response Structure​

All paginated responses follow this pattern:

{
"ok": true,
"version": "2025-11-14-v1",
"request_id": "UUID",
"items": [
{ /* item */ }
],
"next_page_token": "opaque-string-or-null"
}

Example Flow​

1. First request (no token)​

GET /v1/projects?page_size=2

Response:

{
"ok": true,
"items": [
{ "project_id": "projA", ... },
{ "project_id": "projB", ... }
],
"next_page_token": "eyJjIjoxMjM0NTY3ODkwfQ"
}

2. Fetch next page​

GET /v1/projects?page_size=2&page_token=eyJjIjoxMjM0NTY3ODkwfQ

Response:

{
"ok": true,
"items": [
{ "project_id": "projC", ... }
],
"next_page_token": null
}

At this point:

  • next_page_token is null, so no further pages exist.

When next_page_token Is null​

A null token always means:

  • You have reached the end of the dataset
  • No additional requests are needed

Error Handling​

The pagination parameters themselves degrade gracefully rather than erroring:

  • An out-of-range or non-numeric page_size is normalized (see above) — it never causes an invalid_request error.
  • A corrupted, expired, or malformed page_token is silently ignored — the request simply restarts from the first page instead of erroring. Don't rely on a bad token producing a visible failure; if you need to detect this, compare the returned items against what you expect for "page 2+".

The usual endpoint-level errors (missing/invalid API key, rate limits, plan entitlements) still apply on top of this — see the Error Reference for the full catalog.


Best Practices​

Always check for next_page_token​

Do not assume the number of pages based on item count.

Do not reuse tokens indefinitely​

Tokens should only be used for a single pagination chain.

Do not attempt to interpret the token​

It is intentionally opaque and may change formats in the future.

For bulk or export use cases​

Use the Exports API when available (coming in v2), not pagination loops.


Summary​

Pagination in QRForge is:

  • Cursor-based
  • Efficient at scale
  • Consistent across endpoints
  • Simple for clients to consume

Endpoints supporting pagination include:

  • /v1/projects
  • /v1/qr-codes

More endpoints will adopt this structure as the API expands.