# 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

```json
{
  "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

```bash
# 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"
```

```python
import requests

def all_pages(path, params, key, max_pages=10):
    cursor = None
    for _ in range(max_pages):
        q = {**params, **({"cursor": cursor} if cursor else {})}
        body = requests.get(f"https://api.onekey.dev{path}", params=q, headers={"x-api-key": key}, timeout=30).json()
        if not body["success"]:
            raise RuntimeError(body["error"]["type"])
        yield from body["data"]
        page = body.get("pagination")
        if not page or not page["has_more"]:
            break
        cursor = page["next_cursor"]
```

```javascript
async function* allPages(path, params, key, maxPages = 10) {
  let cursor = null;
  for (let i = 0; i < maxPages; i++) {
    const q = new URLSearchParams({ ...params, ...(cursor ? { cursor } : {}) });
    const body = await (await fetch(`https://api.onekey.dev${path}?${q}`, { headers: { "x-api-key": key } })).json();
    if (!body.success) throw new Error(body.error.type);
    yield* body.data;
    const page = body.pagination;
    if (!page || !page.has_more) break;
    cursor = page.next_cursor;
  }
}
```

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: true` whenever the page was full, because the source does not say whether another one exists. The following page can then come back as an empty `data: []` with `has_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 say `true` when 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 `pagination` block 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 `q` or 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.

```bash
curl "https://api.onekey.dev/v1/hackernews/search?q=startup&cursor=tampered" \
  -H "x-api-key: YOUR_API_KEY"
```

```json
{
  "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.

| Platform | Endpoints |
| --- | --- |
| [Aliexpress](https://onekey.dev/docs/api/aliexpress.md) | [`product_similar`](https://onekey.dev/docs/api/aliexpress/product_similar.md), [`reviews`](https://onekey.dev/docs/api/aliexpress/reviews.md), [`search_hot`](https://onekey.dev/docs/api/aliexpress/search_hot.md), [`search_promo`](https://onekey.dev/docs/api/aliexpress/search_promo.md) |
| [Bluesky](https://onekey.dev/docs/api/bluesky.md) | [`feed`](https://onekey.dev/docs/api/bluesky/feed.md), [`followers`](https://onekey.dev/docs/api/bluesky/followers.md), [`likes`](https://onekey.dev/docs/api/bluesky/likes.md), [`list_members`](https://onekey.dev/docs/api/bluesky/list_members.md), [`media`](https://onekey.dev/docs/api/bluesky/media.md), [`popular_feeds`](https://onekey.dev/docs/api/bluesky/popular_feeds.md), [`posts`](https://onekey.dev/docs/api/bluesky/posts.md), [`posts_no_replies`](https://onekey.dev/docs/api/bluesky/posts_no_replies.md), [`posts_with_replies`](https://onekey.dev/docs/api/bluesky/posts_with_replies.md), [`quotes`](https://onekey.dev/docs/api/bluesky/quotes.md), [`reposted_by`](https://onekey.dev/docs/api/bluesky/reposted_by.md), [`search`](https://onekey.dev/docs/api/bluesky/search.md), [`suggested_feeds`](https://onekey.dev/docs/api/bluesky/suggested_feeds.md), [`threads`](https://onekey.dev/docs/api/bluesky/threads.md) |
| [Douyin](https://onekey.dev/docs/api/douyin.md) | [`comment_replies`](https://onekey.dev/docs/api/douyin/comment_replies.md), [`search_users`](https://onekey.dev/docs/api/douyin/search_users.md) |
| [Facebook](https://onekey.dev/docs/api/facebook.md) | [`adlibrary_company_ads`](https://onekey.dev/docs/api/facebook/adlibrary_company_ads.md), [`events`](https://onekey.dev/docs/api/facebook/events.md), [`events_search`](https://onekey.dev/docs/api/facebook/events_search.md), [`group_posts`](https://onekey.dev/docs/api/facebook/group_posts.md), [`marketplace_search`](https://onekey.dev/docs/api/facebook/marketplace_search.md), [`page_events`](https://onekey.dev/docs/api/facebook/page_events.md), [`page_photos`](https://onekey.dev/docs/api/facebook/page_photos.md), [`page_posts`](https://onekey.dev/docs/api/facebook/page_posts.md), [`post_comment_replies`](https://onekey.dev/docs/api/facebook/post_comment_replies.md), [`post_comments`](https://onekey.dev/docs/api/facebook/post_comments.md), [`search_groups`](https://onekey.dev/docs/api/facebook/search_groups.md), [`search_people`](https://onekey.dev/docs/api/facebook/search_people.md), [`search_posts`](https://onekey.dev/docs/api/facebook/search_posts.md), [`search_videos`](https://onekey.dev/docs/api/facebook/search_videos.md) |
| [G2](https://onekey.dev/docs/api/g2.md) | [`category`](https://onekey.dev/docs/api/g2/category.md), [`product_index`](https://onekey.dev/docs/api/g2/product_index.md), [`reviews`](https://onekey.dev/docs/api/g2/reviews.md), [`seller_products`](https://onekey.dev/docs/api/g2/seller_products.md) |
| [GitHub](https://onekey.dev/docs/api/github.md) | [`advisories`](https://onekey.dev/docs/api/github/advisories.md), [`branches`](https://onekey.dev/docs/api/github/branches.md), [`commits`](https://onekey.dev/docs/api/github/commits.md), [`contributors`](https://onekey.dev/docs/api/github/contributors.md), [`forks`](https://onekey.dev/docs/api/github/forks.md), [`issue_comments`](https://onekey.dev/docs/api/github/issue_comments.md), [`issues`](https://onekey.dev/docs/api/github/issues.md), [`labels`](https://onekey.dev/docs/api/github/labels.md), [`licenses`](https://onekey.dev/docs/api/github/licenses.md), [`milestones`](https://onekey.dev/docs/api/github/milestones.md), [`org_events`](https://onekey.dev/docs/api/github/org_events.md), [`org_members`](https://onekey.dev/docs/api/github/org_members.md), [`org_repos`](https://onekey.dev/docs/api/github/org_repos.md), [`public_gists`](https://onekey.dev/docs/api/github/public_gists.md), [`pull_commits`](https://onekey.dev/docs/api/github/pull_commits.md), [`pull_files`](https://onekey.dev/docs/api/github/pull_files.md), [`pulls`](https://onekey.dev/docs/api/github/pulls.md), [`releases`](https://onekey.dev/docs/api/github/releases.md), [`repo_events`](https://onekey.dev/docs/api/github/repo_events.md), [`repos`](https://onekey.dev/docs/api/github/repos.md), [`search`](https://onekey.dev/docs/api/github/search.md), [`search_code`](https://onekey.dev/docs/api/github/search_code.md), [`search_commits`](https://onekey.dev/docs/api/github/search_commits.md), [`search_issues`](https://onekey.dev/docs/api/github/search_issues.md), [`search_repos`](https://onekey.dev/docs/api/github/search_repos.md), [`search_topics`](https://onekey.dev/docs/api/github/search_topics.md), [`stargazers`](https://onekey.dev/docs/api/github/stargazers.md), [`subscribers`](https://onekey.dev/docs/api/github/subscribers.md), [`tags`](https://onekey.dev/docs/api/github/tags.md), [`user_events`](https://onekey.dev/docs/api/github/user_events.md), [`user_followers`](https://onekey.dev/docs/api/github/user_followers.md), [`user_following`](https://onekey.dev/docs/api/github/user_following.md), [`user_gists`](https://onekey.dev/docs/api/github/user_gists.md), [`user_starred`](https://onekey.dev/docs/api/github/user_starred.md), [`workflow_runs`](https://onekey.dev/docs/api/github/workflow_runs.md) |
| [Google](https://onekey.dev/docs/api/google.md) | [`company_ads`](https://onekey.dev/docs/api/google/company_ads.md) |
| [Gumtree](https://onekey.dev/docs/api/gumtree.md) | [`search`](https://onekey.dev/docs/api/gumtree/search.md), [`seller_listings`](https://onekey.dev/docs/api/gumtree/seller_listings.md) |
| [Hacker News](https://onekey.dev/docs/api/hackernews.md) | [`ask_hn`](https://onekey.dev/docs/api/hackernews/ask_hn.md), [`author_comments`](https://onekey.dev/docs/api/hackernews/author_comments.md), [`author_submissions`](https://onekey.dev/docs/api/hackernews/author_submissions.md), [`front_page`](https://onekey.dev/docs/api/hackernews/front_page.md), [`jobs`](https://onekey.dev/docs/api/hackernews/jobs.md), [`polls`](https://onekey.dev/docs/api/hackernews/polls.md), [`search`](https://onekey.dev/docs/api/hackernews/search.md), [`search_by_date`](https://onekey.dev/docs/api/hackernews/search_by_date.md), [`search_comments`](https://onekey.dev/docs/api/hackernews/search_comments.md), [`search_url`](https://onekey.dev/docs/api/hackernews/search_url.md), [`show_hn`](https://onekey.dev/docs/api/hackernews/show_hn.md), [`story_comments`](https://onekey.dev/docs/api/hackernews/story_comments.md) |
| [Hm](https://onekey.dev/docs/api/hm.md) | [`search`](https://onekey.dev/docs/api/hm/search.md) |
| [Home Depot](https://onekey.dev/docs/api/home_depot.md) | [`search`](https://onekey.dev/docs/api/home_depot/search.md) |
| [Instagram](https://onekey.dev/docs/api/instagram.md) | [`audio_reels`](https://onekey.dev/docs/api/instagram/audio_reels.md), [`comment_likers`](https://onekey.dev/docs/api/instagram/comment_likers.md), [`location_posts`](https://onekey.dev/docs/api/instagram/location_posts.md), [`post_comment_replies`](https://onekey.dev/docs/api/instagram/post_comment_replies.md), [`posts`](https://onekey.dev/docs/api/instagram/posts.md), [`reels`](https://onekey.dev/docs/api/instagram/reels.md), [`search_music`](https://onekey.dev/docs/api/instagram/search_music.md), [`search_popular`](https://onekey.dev/docs/api/instagram/search_popular.md), [`search_reels`](https://onekey.dev/docs/api/instagram/search_reels.md), [`tagged`](https://onekey.dev/docs/api/instagram/tagged.md) |
| [Jobs](https://onekey.dev/docs/api/jobs.md) | [`search`](https://onekey.dev/docs/api/jobs/search.md) |
| [Klarna](https://onekey.dev/docs/api/klarna.md) | [`category`](https://onekey.dev/docs/api/klarna/category.md), [`reviews`](https://onekey.dev/docs/api/klarna/reviews.md), [`reviews_pro`](https://onekey.dev/docs/api/klarna/reviews_pro.md), [`store_products`](https://onekey.dev/docs/api/klarna/store_products.md), [`stores`](https://onekey.dev/docs/api/klarna/stores.md) |
| [Kohls](https://onekey.dev/docs/api/kohls.md) | [`questions`](https://onekey.dev/docs/api/kohls/questions.md), [`reviews`](https://onekey.dev/docs/api/kohls/reviews.md), [`search`](https://onekey.dev/docs/api/kohls/search.md) |
| [Kwai](https://onekey.dev/docs/api/kwai.md) | [`user_posts`](https://onekey.dev/docs/api/kwai/user_posts.md) |
| [LinkedIn](https://onekey.dev/docs/api/linkedin.md) | [`ads_search`](https://onekey.dev/docs/api/linkedin/ads_search.md), [`article_comments`](https://onekey.dev/docs/api/linkedin/article_comments.md), [`article_reactions`](https://onekey.dev/docs/api/linkedin/article_reactions.md), [`company_jobs`](https://onekey.dev/docs/api/linkedin/company_jobs.md), [`company_people`](https://onekey.dev/docs/api/linkedin/company_people.md), [`group_posts`](https://onekey.dev/docs/api/linkedin/group_posts.md), [`post_comment_replies`](https://onekey.dev/docs/api/linkedin/post_comment_replies.md), [`post_reactions`](https://onekey.dev/docs/api/linkedin/post_reactions.md), [`post_reposts`](https://onekey.dev/docs/api/linkedin/post_reposts.md), [`profile_articles`](https://onekey.dev/docs/api/linkedin/profile_articles.md), [`profile_certifications`](https://onekey.dev/docs/api/linkedin/profile_certifications.md), [`profile_educations`](https://onekey.dev/docs/api/linkedin/profile_educations.md), [`profile_experiences`](https://onekey.dev/docs/api/linkedin/profile_experiences.md), [`profile_honors`](https://onekey.dev/docs/api/linkedin/profile_honors.md), [`profile_interests_companies`](https://onekey.dev/docs/api/linkedin/profile_interests_companies.md), [`profile_interests_groups`](https://onekey.dev/docs/api/linkedin/profile_interests_groups.md), [`profile_interests_newsletters`](https://onekey.dev/docs/api/linkedin/profile_interests_newsletters.md), [`profile_interests_schools`](https://onekey.dev/docs/api/linkedin/profile_interests_schools.md), [`profile_publications`](https://onekey.dev/docs/api/linkedin/profile_publications.md), [`profile_recommendations`](https://onekey.dev/docs/api/linkedin/profile_recommendations.md), [`profile_skills`](https://onekey.dev/docs/api/linkedin/profile_skills.md), [`profile_volunteers`](https://onekey.dev/docs/api/linkedin/profile_volunteers.md), [`search_jobs`](https://onekey.dev/docs/api/linkedin/search_jobs.md), [`search_posts`](https://onekey.dev/docs/api/linkedin/search_posts.md), [`search_schools`](https://onekey.dev/docs/api/linkedin/search_schools.md) |
| [Pinterest](https://onekey.dev/docs/api/pinterest.md) | [`search_pins`](https://onekey.dev/docs/api/pinterest/search_pins.md) |
| [Reddit](https://onekey.dev/docs/api/reddit.md) | [`frontpage`](https://onekey.dev/docs/api/reddit/frontpage.md), [`new_subreddits`](https://onekey.dev/docs/api/reddit/new_subreddits.md), [`popular_subreddits`](https://onekey.dev/docs/api/reddit/popular_subreddits.md), [`search_posts`](https://onekey.dev/docs/api/reddit/search_posts.md), [`search_subreddit`](https://onekey.dev/docs/api/reddit/search_subreddit.md), [`search_subreddits`](https://onekey.dev/docs/api/reddit/search_subreddits.md), [`subreddit_controversial`](https://onekey.dev/docs/api/reddit/subreddit_controversial.md), [`subreddit_hot`](https://onekey.dev/docs/api/reddit/subreddit_hot.md), [`subreddit_new`](https://onekey.dev/docs/api/reddit/subreddit_new.md), [`subreddit_rising`](https://onekey.dev/docs/api/reddit/subreddit_rising.md), [`subreddit_top`](https://onekey.dev/docs/api/reddit/subreddit_top.md), [`user_comments`](https://onekey.dev/docs/api/reddit/user_comments.md), [`user_posts`](https://onekey.dev/docs/api/reddit/user_posts.md) |
| [Rumble](https://onekey.dev/docs/api/rumble.md) | [`search`](https://onekey.dev/docs/api/rumble/search.md) |
| [Sephora](https://onekey.dev/docs/api/sephora.md) | [`brand_products`](https://onekey.dev/docs/api/sephora/brand_products.md), [`category`](https://onekey.dev/docs/api/sephora/category.md), [`reviews`](https://onekey.dev/docs/api/sephora/reviews.md), [`search`](https://onekey.dev/docs/api/sephora/search.md) |
| [Snapchat](https://onekey.dev/docs/api/snapchat.md) | [`spotlight_comments`](https://onekey.dev/docs/api/snapchat/spotlight_comments.md) |
| [Spotify](https://onekey.dev/docs/api/spotify.md) | [`podcast_episodes`](https://onekey.dev/docs/api/spotify/podcast_episodes.md) |
| [Target](https://onekey.dev/docs/api/target.md) | [`categories`](https://onekey.dev/docs/api/target/categories.md), [`reviews`](https://onekey.dev/docs/api/target/reviews.md) |
| [Threads](https://onekey.dev/docs/api/threads.md) | [`search`](https://onekey.dev/docs/api/threads/search.md) |
| [TikTok](https://onekey.dev/docs/api/tiktok.md) | [`adlibrary_search`](https://onekey.dev/docs/api/tiktok/adlibrary_search.md), [`collection_videos`](https://onekey.dev/docs/api/tiktok/collection_videos.md), [`comment_replies`](https://onekey.dev/docs/api/tiktok/comment_replies.md), [`comments`](https://onekey.dev/docs/api/tiktok/comments.md), [`effect_videos`](https://onekey.dev/docs/api/tiktok/effect_videos.md), [`location_posts`](https://onekey.dev/docs/api/tiktok/location_posts.md), [`music_videos`](https://onekey.dev/docs/api/tiktok/music_videos.md), [`playlist_videos`](https://onekey.dev/docs/api/tiktok/playlist_videos.md), [`search_mentions`](https://onekey.dev/docs/api/tiktok/search_mentions.md), [`search_music`](https://onekey.dev/docs/api/tiktok/search_music.md), [`search_top`](https://onekey.dev/docs/api/tiktok/search_top.md), [`search_users`](https://onekey.dev/docs/api/tiktok/search_users.md), [`search_videos`](https://onekey.dev/docs/api/tiktok/search_videos.md), [`user_liked`](https://onekey.dev/docs/api/tiktok/user_liked.md) |
| [Tiktokshop](https://onekey.dev/docs/api/tiktokshop.md) | [`product_reviews`](https://onekey.dev/docs/api/tiktokshop/product_reviews.md), [`products`](https://onekey.dev/docs/api/tiktokshop/products.md), [`search`](https://onekey.dev/docs/api/tiktokshop/search.md), [`user_showcase`](https://onekey.dev/docs/api/tiktokshop/user_showcase.md) |
| [Truthsocial](https://onekey.dev/docs/api/truthsocial.md) | [`user_posts`](https://onekey.dev/docs/api/truthsocial/user_posts.md) |
| [Walmart](https://onekey.dev/docs/api/walmart.md) | [`category`](https://onekey.dev/docs/api/walmart/category.md), [`reviews`](https://onekey.dev/docs/api/walmart/reviews.md) |
| [Wayfair](https://onekey.dev/docs/api/wayfair.md) | [`reviews`](https://onekey.dev/docs/api/wayfair/reviews.md), [`search`](https://onekey.dev/docs/api/wayfair/search.md) |
| [X (Twitter)](https://onekey.dev/docs/api/x.md) | [`retweeters`](https://onekey.dev/docs/api/x/retweeters.md), [`search_users`](https://onekey.dev/docs/api/x/search_users.md), [`user_media`](https://onekey.dev/docs/api/x/user_media.md) |
| [Xiaohongshu](https://onekey.dev/docs/api/xiaohongshu.md) | [`post_comments`](https://onekey.dev/docs/api/xiaohongshu/post_comments.md), [`profile_posts`](https://onekey.dev/docs/api/xiaohongshu/profile_posts.md), [`search`](https://onekey.dev/docs/api/xiaohongshu/search.md) |
| [Yelp](https://onekey.dev/docs/api/yelp.md) | [`search_full`](https://onekey.dev/docs/api/yelp/search_full.md) |
| [YouTube](https://onekey.dev/docs/api/youtube.md) | [`search_hashtag`](https://onekey.dev/docs/api/youtube/search_hashtag.md) |
