Pagination
Pagination splits long result lists of the API into pages that you fetch one after the other.
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
- 1Fetch the first pageYou send the request with
page=1. - 2Read the page infoThe
paginationblock names the current page and the number of pages. - 3Fetch the next pageIf a page is left, you wait a little longer than one second and increase
pageby 1. - 4Detect the endOnce
currentis at leastpage_total, you have all pages.
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.
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:
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:
{
"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:trueon page 1.isLast:truewhencurrentis at leastpage_total. This also holds for an empty result.page_size: the number of entries per page.
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.
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
}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
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 describes how to set date ranges.
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
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_sizedefaults to 1,000 with a maximum of 10,000, and the lists are in thelistsfield./enrichment/lists/{list_id}/rows:page_sizedefaults to 10,000, which is also the maximum, and the rows are in therowsfield next tototal. With thestatusfilter,totalcounts 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
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.