Pagination
Some list endpoints return more results than fit in one answer. Those endpoints page with a cursor: every response carries a pagination block, and you send its next_cursor back to get the next page. There is nothing to compute on your side.
When you need it#
Only on list endpoints that page. Their endpoint page shows a Pagination line with the page size and lists cursor as an optional parameter; GET /v1/platforms shows the same (cursor in params, and a pagination object with page_size). Endpoints without it return a single answer and have no pagination key at all, so check for the key rather than assuming it. Today 190 endpoints page.
The pagination block#
{
"success": true,
"data": [ "...10 results..." ],
"metadata": { "platform": "hackernews", "endpoint": "search", "credits_charged": 5, "request_id": "68e6883c5d3240659947f43a20625eb9" },
"error": null,
"pagination": {
"next_cursor": "eyJiIjoiYzVjMzg1MzU2Zjg0IiwicCI6IjEiLCJzIjoiaGFja2VybmV3cy5zZWFyY2giLCJ2IjoxfQ.Ccd505alpSQwnZFwExfUjg",
"has_more": true,
"page_size": 10
}
}| Field | Type | Meaning |
|---|---|---|
next_cursor | string or null | Send it back verbatim as the cursor query parameter, with the same other parameters, to get the next page. null whenever has_more is false. |
has_more | boolean | Whether asking for another page makes sense. |
page_size | number | The fixed number of results per page for this endpoint. It is not a parameter; you cannot change it. |
A cursor is opaque: a signed token bound to the endpoint and to the rest of your query. It is at most 2048 characters and safe to store or pass along. Do not build one yourself, alter one, or reuse one from another query.
Walking a list#
# first page: no cursor
curl "https://api.onekey.dev/v1/hackernews/search?q=startup" \
-H "x-api-key: YOUR_API_KEY"
# next page: same parameters plus the cursor from the previous answer
curl "https://api.onekey.dev/v1/hackernews/search?q=startup&cursor=eyJiIjoiYzVjMzg1..." \
-H "x-api-key: YOUR_API_KEY"Always cap the number of pages you fetch: each page is a separate, billed call.
Edge cases#
- A true has_more is honest but not clairvoyant. Endpoints that page by page number or offset report
has_more: truewhenever the page was full, because the source does not say whether another one exists. The following page can then come back as an emptydata: []withhas_more: false. That empty page is a normal, successful answer and costs the endpoint price. Endpoints that page with a continuation token from the source only saytruewhen the source handed one over. - Cursors do not expire on their own. A source may stop honouring an old continuation, in which case the page simply comes back empty with
has_more: false. - Cache hits page the same way. A page served from cache carries the same
paginationblock as a fresh one. - The first page is the default. Omit
cursor(or send it empty) to start over. - Different parameters, different list. A cursor is bound to the query it came from; changing
qor any other parameter and reusing the cursor is refused.
Invalid cursors#
A cursor that was altered, that came from another endpoint or another query, or that is not a cursor at all is refused with 422 INVALID_CURSOR. Nothing is charged. Start again from the first page.
curl "https://api.onekey.dev/v1/hackernews/search?q=startup&cursor=tampered" \
-H "x-api-key: YOUR_API_KEY"{
"success": false,
"data": null,
"metadata": { "request_id": "7dd14539f2f24ca1bc1eb63809293092" },
"error": {
"code": "invalid_cursor",
"type": "INVALID_CURSOR",
"message": "The cursor is invalid, expired, or from another query",
"request_id": "7dd14539f2f24ca1bc1eb63809293092",
"doc_url": "https://onekey.dev/errors/INVALID_CURSOR"
}
}What it costs#
Every page is one call at the endpoint's price, shown on its page, whether it holds page_size results, fewer, or none. A page served from cache is free like any other cache hit. An invalid cursor is rejected before any charge.
Endpoints that page#
190 endpoints page today; every other list returns one page. The rule above is the same for all of them.