Skip to main content
List endpoints (GET /developer/vouchers, /customers, /products) accept two pagination shapes on the same endpoint. Pick whichever fits your integration; if both are supplied on the same request, the cursor shape wins. Pass cursor and limit. The response includes next_cursor (null at the end of the walk).
GET /api/v1/developer/vouchers?limit=50
{
  "vouchers": [/* …items… */],
  "next_cursor": "cur_v1_eyJ2IjoxLCJ0Ijoi…uH8.QwR2…"
}
Continue walking by passing the next_cursor value verbatim:
GET /api/v1/developer/vouchers?cursor=cur_v1_eyJ2IjoxLCJ0Ijoi…uH8.QwR2…&limit=50
When next_cursor comes back null, you’ve reached the end.

Properties

  • Opaque. Treat cursors as opaque strings. The format is HMAC-signed and bound to your tenant; tampering, forging, or replaying a cursor against a different API key all return 400 Bad Request.
  • Stable under mid-walk writes. Inserts and deletes that happen between requests do not cause duplicates or skips on the cursor path. New rows created with a created_at newer than the cursor anchor are not surfaced in subsequent pages – start a new walk to pick them up.
  • Forward only. Reverse traversal is not supported; restart the walk from the beginning to revisit earlier rows.
  • Deterministic ordering. Cursor mode returns rows ordered by created_at DESC, id DESC. The legacy sort_by / sort_order params on GET /developer/vouchers are ignored when cursor or limit is set.
  • Per-endpoint limit caps: vouchers 100, customers 100, products 100.

Page pagination (deprecated)

The page / per_page shape is kept for backward compatibility but is subject to row drift if the underlying data mutates mid-walk (a row inserted at the start can shift later pages, causing duplicates or skips). New integrations should use cursor pagination.
Pass page and per_page. The response includes total, page, and per_page.
ParameterTypeDefaultMinMaxNotes
pageinteger111-indexed page number
per_pageintegervaries1100Page size cap
The default per_page differs by endpoint:
  • GET /developer/vouchers – default 50, max 100
  • GET /developer/customers – default 50, max 100
  • GET /developer/products – default 20, max 100
{
  "vouchers": [/* …items… */],
  "total": 247,
  "page": 1,
  "per_page": 50
}
Compute “has more”:
const lastPage = Math.ceil(response.total / response.per_page);
const hasMore = response.page < lastPage;
When the customer search uses a non-email term, the server caps the underlying lookup at 1,000 candidate rows for memory safety. Very large tenants searching for a common substring may not see every match – narrow the search term to recover precision. Both cursor and page shapes apply the same 1,000-row cap, so they return identical row sets for the same search query.