# Pagination (https://webmetic.de/docs/en/api/paginierung)

Pagination splits a long result list of the API into pages that you fetch one after the other. For example, your website had 2,450 sessions from companies in October. With `page_size=1000`, the `/session` endpoint returns them on three pages with 1,000, 1,000, and 450 entries.

There is no cursor and no link to the next page, so you count up `page` yourself.

## How paging works [#how-paging-works]

1. **Fetch the first page**: You send the request with `page=1`.
2. **Read the page info**: The `pagination` block names the current page and the number of pages.
3. **Fetch the next page**: If a page is left, you wait a little longer than one second and increase `page` by 1.
4. **Detect the end**: Once `current` is at least `page_total`, you have all pages.

## Page parameters [#page-parameters]

The endpoints `/company-sessions`, `/company`, `/company_nace`, `/session`, and `/session_user_data` take two parameters:

- `page`: the page number, starting at 1, with 1 as the default.
- `page_size`: the number of entries per page, at most 10,000 and also 10,000 by default.

With the default of 10,000, the whole date range often fits on a single page.

If `page` or `page_size` is below 1, or `page_size` is above 10,000, the API answers with status 422 and the code `VALIDATION_ERROR`. For details, see [Errors](https://webmetic.de/docs/en/api/fehler).

## Page info in the response [#page-info-in-the-response]

Every response of these endpoints contains the fields `pagination` and `result`. Note that `pagination` is a list with exactly one entry, not a single object.

This request fetches the second of three pages:

```bash
curl "https://hub.webmetic.de/session?domain=your-website.com&from_date=2026-10-01&to_date=2026-10-31&page=2&page_size=1000" \
  -H "Authorization: wmtc_YOUR_API_KEY"
```

The response, shortened here to the `pagination` block, looks like this:

```json
{
  "pagination": [
    {
      "total": 2450,
      "page_total": 3,
      "isFirst": false,
      "current": 2,
      "isLast": false,
      "page_size": 1000
    }
  ]
}
```

- `total`: the number of entries across all pages.
- `page_total`: the number of pages.
- `current`: the requested page.
- `isFirst`: `true` on page 1.
- `isLast`: `true` when `current` is at least `page_total`. This also holds for an empty result.
- `page_size`: the number of entries per page.

## Loop over all pages [#loop-over-all-pages]

The loop requests one page after the other until `current` is at least `page_total`. Checking `isLast` would give the same result. For an empty result `page_total` is 0, so the loop ends after the first request.

Between two pages the loop waits a little longer than one second, because the visit endpoints answer one request per second per endpoint. For details, see [Rate limits](https://webmetic.de/docs/en/api/anfragelimits).

```js tab="JavaScript" tab-group="lang"
const rows = [];
let page = 1;
while (true) {
  const params = new URLSearchParams({
    domain: 'your-website.com',
    from_date: '2026-10-01',
    to_date: '2026-10-31',
    page: String(page),
    page_size: '1000',
  });
  const res = await fetch(`https://hub.webmetic.de/session?${params}`, {
    headers: { Authorization: 'wmtc_YOUR_API_KEY' },
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const body = await res.json();
  rows.push(...body.result);
  const info = body.pagination[0]; // pagination is a list with one object
  if (info.current >= info.page_total) break;
  page += 1;
  await new Promise((resolve) => setTimeout(resolve, 1100)); // 1 request per second
}
```

```python tab="Python" tab-group="lang"
import time
import requests

params = {"domain": "your-website.com", "from_date": "2026-10-01", "to_date": "2026-10-31",
          "page": 1, "page_size": 1000}
rows = []
while True:
    r = requests.get("https://hub.webmetic.de/session",
                     headers={"Authorization": "wmtc_YOUR_API_KEY"}, params=params)
    r.raise_for_status()
    body = r.json()
    rows += body["result"]
    info = body["pagination"][0]  # pagination is a list with one object
    if info["current"] >= info["page_total"]:
        break
    params["page"] += 1
    time.sleep(1.1)  # 1 request per second
```

Send a fixed `to_date` while you page, for example `2026-10-31`, not `now` or a relative value such as `-1 days`. Otherwise new visits arrive between two requests and shift the entries.

## Order of entries [#order-of-entries]

On the visit endpoints, the order of entries is not fixed, and an entry can be on a different page the next time you fetch. Sort the data yourself after you fetch it.

If you need every entry, fetch them on one page with a large `page_size` or split the request into shorter date ranges. [Date ranges and time zones](https://webmetic.de/docs/en/api/zeitraeume-und-zeitzonen) describes how to set date ranges.

## Endpoints at a glance [#endpoints-at-a-glance]

| Endpoint | One entry | Pages |
| --- | --- | --- |
| `/company-sessions` | One company with its sessions in the date range | `page` from 1 |
| `/company` | One company | `page` from 1 |
| `/company_nace` | One NACE code of a company | `page` from 1 |
| `/session` | One session | `page` from 1 |
| `/session_user_data` | One page view | `page` from 1 |
| `/intensive-visits`, `/returning-visits`, `/new-visits` | One company | Everything in one response |
| `/enrichment/lists` | One list | `page` from 1 |
| `/enrichment/lists/{list_id}/rows` | One row of the list | `page` from 1 |
| `/enrichment/lists/{list_id}/export` | One row of the CSV file | Everything in one response |
| `/contacts/search` | One contact | `page` from 0 |
| `/webhooks` | One webhook endpoint | Everything in one response |

`/intensive-visits`, `/returning-visits`, and `/new-visits` have no pages and return all matching companies at once. If the response gets too large, choose a shorter date range with `from_date` and `to_date`.

## Enrichment lists [#enrichment-lists]

`GET /enrichment/lists` and `GET /enrichment/lists/{list_id}/rows` page like the visit endpoints: `page` starts at 1, and both use `page_size` and the same `pagination` block. Both return the newest entries first.

- `/enrichment/lists`: `page_size` defaults to 1,000 with a maximum of 10,000, and the lists are in the `lists` field.
- `/enrichment/lists/{list_id}/rows`: `page_size` defaults to 10,000, which is also the maximum, and the rows are in the `rows` field next to `total`. With the `status` filter, `total` counts only the matching rows.

Enrichment currently has no rate limit, so the loop needs no pause there. The export `/enrichment/lists/{list_id}/export` returns all rows of a list as CSV in a single response.

## Contact search [#contact-search]

The contact search `POST /contacts/search` counts differently: `page` goes in the JSON body and starts at 0. `size` sets the hits per page, from 10 to 25, with 25 as the default.

The response contains `total` and `page`, but no page count and no `isLast`. You have reached the last page when `(page + 1) * size` is at least `total`.

Every page is a new search, and it costs no credits, not even on later pages. Only unlocking an email address or phone number costs credits. For details, see [Credits in the API](https://webmetic.de/docs/en/api/credits).

## Next steps [#next-steps]

- [Date ranges and time zones](https://webmetic.de/docs/en/api/zeitraeume-und-zeitzonen): Set the date range exactly with `from_date` and `to_date`.
- [Rate limits](https://webmetic.de/docs/en/api/anfragelimits): How many requests the API answers per second.
- [Errors](https://webmetic.de/docs/en/api/fehler): Read the status codes and error codes of the API.
