Fetch Posts From Any Subreddit by Sort
Fetch posts from any subreddit via a simple HTTP GET. Supports all Reddit sort tabs, New, Hot, Top, Rising, Controversial, Best, plus timeframe, cursor.
/api/reddit/posts$0.002 / callPosts from a subreddit. Supports all Reddit sort tabs: New / Hot / Top / Rising / Controversial / Best.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
subreddit | string | Yes | Subreddit name (no r/ prefix) |
sort | string | No | new (default) | hot | top | rising | controversial | best |
t | string | No | Timeframe for sort=top/controversial: hour | day | week | month | year | all |
limit | number | No | Number of posts to return, 1-100 (default 25) |
after | string | No | Pagination cursor. Pass back the after value from the previous response exactly as issued; it is opaque and carries your paging depth. Reddit caps any single listing at roughly 1000 posts, see Pagination depth below. |
Pagination depth
This section is the reference for every listing and search endpoint on this API, not just this one. They all issue the same kind of cursor and all publish the same exhaustion fields, so the other endpoint pages link here rather than repeating it. The one exception is a post's comment thread, which is a tree rather than a paged listing and is covered on its own page.
Reddit caps a single listing at roughly 1000 posts. Page past that and after
comes back null, even when the subreddit plainly holds more history.
This is a Reddit platform limit, not a limit we add, and it applies to every client hitting a listing, including reddit.com itself. When Reddit stops issuing a cursor, pagination ends.
Measured on r/stocks, 100 posts per page:
| page | posts | cumulative | after |
|---|---|---|---|
| 1-9 | 100 | 900 | present |
| 10 | 83 | 983 | null |
The cap is not the only reason a listing stops, and busy feeds stop far
sooner. Paging r/all with sort=new on 2026-08-14 terminated after 400
posts spanning 67 seconds of Reddit, and four sweeps the previous day stopped at
153, 384, 400 and 383 posts. None of those is the end of the data, and no count
threshold separates them from a subreddit that genuinely holds a few hundred
posts.
So when after comes back null, read the exhaustion fields below rather than
inferring an answer from the count.
Exhaustion fields
When after is null, the response carries these extra fields:
| Field | Values | Meaning |
|---|---|---|
listing_status | complete | truncated | unknown | The field to branch on. |
exhausted_reason | end_of_listing | listing_cap | short_page_after_full_pages | unknown | How we reached that verdict. New reasons may be added; listing_status stays three-valued, so branch on that. |
items_returned | number | null | Total posts delivered across the whole paging run. null if you paged with a raw Reddit token. |
final_page_items | number | null | Posts on the final page, published so you can re-derive the verdict instead of trusting it. |
hint | string | Plain-language explanation, safe to show a human. |
listing_status answers the only question a paging client has:
completemeans the whole run came back in under one page: you asked for 100 and got fewer, and Reddit then stopped. Nothing was ever served whole, so there is no cut-off story competing with the obvious reading, and no older posts are expected in this listing.truncatedmeans you reached Reddit's ~1000 cap. More history exists and this listing cannot reach it.unknownmeans we cannot tell, and we will not guess. Do not treatunknownas the end of the data. Three things land here: Reddit stopped on an exact page boundary; you paged with a raw Reddit token so we never knew your depth; or Reddit stopped part way through a page after already serving at least one full page (exhausted_reason: short_page_after_full_pages).
For both truncated and unknown, widen across listings rather than paging
deeper into this one.
Why a short final page is not enough on its own. Until 2026-08-14 any run
that ended part way through a page was called complete. Re-reading the r/all
measurements above against that rule showed why it was wrong: the 153, 384 and
383 sweeps all ended mid-page, so all three were being reported as complete
on a feed whose entire run covered about a minute. A short page after one or
more full pages is equally the shape of a busy feed Reddit decided to stop
serving, so it now resolves to unknown. The practical cost is that a small
subreddit of a few hundred posts reports unknown instead of complete: page
once more and you get nothing, which is cheap. Being told your data is
complete when most of it is missing is not.
Getting more than 1000 posts
Narrow the window rather than paging deeper. Each of these is a separate listing with its own ~1000 budget:
- Sort tabs:
new,hot,top,rising,controversial,besteach return a different listing. - Timeframes: pair
sort=topwitht=hour|day|week|month|year|allto slice history into chunks that individually stay under the cap. - Search:
/api/reddit/searchwith a query scoped to the subreddit reaches posts a listing will not.
Example
curl -H "Authorization: Bearer $TOKEN" \
"https://api.redditapis.com/api/reddit/posts?subreddit=ClaudeCode&sort=top&t=week"const response = await fetch(
"https://api.redditapis.com/api/reddit/posts?subreddit=ClaudeCode&sort=top&t=week",
{ headers: { Authorization: "Bearer TOKEN" } }
);
const data = await response.json();import requests
response = requests.get(
"https://api.redditapis.com/api/reddit/posts",
params={"subreddit": "ClaudeCode", "sort": "top", "t": "week"},
headers={"Authorization": "Bearer TOKEN"},
)Response Shape
{
"posts": [
{
"id": "1tkez6e",
"name": "t3_1tkez6e",
"title": "...",
"author": "user123",
"author_info": {
"fullname": "t2_ugmf7dmn",
"premium": false,
"is_blocked": false,
"flair": null
},
"permalink": "/r/ClaudeCode/comments/1tkez6e/...",
"url": "https://reddit.com/r/ClaudeCode/comments/1tkez6e/...",
"link_url": "https://i.redd.it/ec3ynsn66n2h1.png",
"text": "",
"subreddit": "ClaudeCode",
"upvotes": 42,
"comments": 12,
"upvote_ratio": 0.96,
"over_18": false,
"stickied": false,
"locked": false,
"spoiler": false,
"is_self": false,
"is_crosspost": true,
"crosspost_origin": {
"id": "1tkbqvk",
"name": "t3_1tkbqvk",
"title": "...",
"author": "Agitated_Usual7089",
"subreddit": "Class12thBoard",
"permalink": "/r/Class12thBoard/comments/1tkbqvk/...",
"url": "https://reddit.com/r/Class12thBoard/comments/1tkbqvk/...",
"link_url": null,
"text": "...",
"created_utc": 1779435116,
"created": "2026-05-22T07:31:56.000Z"
},
"created_utc": 1779445765,
"created": "2026-05-22T10:29:25.000Z"
}
],
"after": "t3_xyz"
}Response Fields
| Field | Type | Notes |
|---|---|---|
id | string | Post id without prefix |
name | string | Full id with t3_ prefix. This is Reddit's own id for the post, NOT a pagination cursor. Use the response's after value for paging. |
title | string | Post title |
author | string | Username (no u/ prefix) |
author_info | object | { fullname, premium, is_blocked, flair }. fullname is the t2_xxx account id. flair is null when no flair is set, otherwise { text, type, background_color, text_color }. For karma / account age / profile icon call /api/reddit/user/:name. |
permalink | string | Path on reddit.com |
url | string | Full reddit.com URL |
link_url | string | null | External link / media URL the post points at. null for self/text posts since the post has no separate destination. |
text | string | Self-post body (empty for link/image posts) |
subreddit | string | Subreddit name (no r/ prefix) |
upvotes | number | Net votes (upvotes − downvotes). Reddit doesn't expose raw counts. |
comments | number | Comment count |
upvote_ratio | number | Approximate (Reddit fuzzes this for fresh posts) |
over_18, stickied, locked, spoiler | boolean | Post flags |
is_self | boolean | True for text/self posts |
is_crosspost | boolean | True if this post was crossposted from another subreddit |
crosspost_origin | object | null | When is_crosspost: true, the original post (id, name, title, author, subreddit, permalink, url, link_url, text, created_utc, created). null otherwise. url is the original's reddit thread; link_url is what the original pointed at (null if it was a text post) and text is the original's own body, neither of which survives onto the crosspost itself. When Reddit sends only a parent id the object is just { name }. |
created_utc | number | Unix epoch seconds |
created | string | ISO-8601 form of created_utc |
Independent third-party API for developers and researchers. Not affiliated with, endorsed by, or sponsored by Reddit, Inc.
FAQ
Straight answers to the questions customers actually ask support. Commercial use, reselling, minimum top-up, signup credit, login methods, Reddit account requirements, historical data, and what is on the roadmap.
Home Feed
Fetch your own Reddit front page over HTTP with your session cookies. Six sorts, cursor pagination, and the same post shape as every other listing.
