> For the complete index of the 402pay docs, see [llms.txt](https://developer.402pay.co/llms.txt).

# Pagination

Walk every list endpoint with limit and cursor.

List endpoints return `{ data, has_more, next_cursor }`. Pass `limit` for the page size, 25 by default and up to 100, and pass `next_cursor` back as `cursor` for the next page.

A cursor only works with the list and filters it came from. If it doesn't match, or isn't one the API gave you, the request returns 400 `invalid_request` with `field: "cursor"`, so start again without it.

GET /links?limit=1, 200 OK:

```json
{
  "data": [
    {
      "id": "lnk_nt842tPNne3lf0ka",
      "kind": "link",
      "code": "v6e4mrczwg",
      "url": "https://checkout.402pay.co/checkout/v6e4mrczwg",
      "name": "Team plan, monthly",
      "description": "Everything in Pro for up to 10 people.",
      "amount": 19900,
      "currency": "USD",
      "success_url": null,
      "status": "active",
      "disabled_at": null,
      "payments_count": 0,
      "volume": {
        "amount": 0,
        "currency": "USD"
      },
      "created_at": "2026-09-26T21:22:46.992Z",
      "updated_at": "2026-09-26T21:22:46.992Z"
    }
  ],
  "has_more": true,
  "next_cursor": "lnk_nt842tPNne3lf0ka"
}
```

Every page, Node.js:

```js
// Walks every page of a list, 100 at a time.
async function* listAll(path) {
  let cursor = null;
  do {
    const url = new URL(`https://dash.402pay.co/api/v1${path}`);
    url.searchParams.set("limit", "100");
    if (cursor) url.searchParams.set("cursor", cursor);

    const response = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}` },
    });
    const page = await response.json();
    yield* page.data;
    cursor = page.has_more ? page.next_cursor : null;
  } while (cursor);
}

for await (const payment of listAll("/payments?status=succeeded")) {
  console.log(payment.id, payment.amount);
}
```
