RedditapisRedditapis
Listings & Search

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.

GET/api/reddit/posts$0.002 / call

Posts from a subreddit. Supports all Reddit sort tabs: New / Hot / Top / Rising / Controversial / Best.

Query Parameters

ParameterTypeRequiredDescription
subredditstringYesSubreddit name (no r/ prefix)
sortstringNonew (default) | hot | top | rising | controversial | best
tstringNoTimeframe for sort=top/controversial: hour | day | week | month | year | all
limitnumberNoNumber of posts to return, 1-100 (default 25)
afterstringNoPagination 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:

pagepostscumulativeafter
1-9100900present
1083983null

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:

FieldValuesMeaning
listing_statuscomplete | truncated | unknownThe field to branch on.
exhausted_reasonend_of_listing | listing_cap | short_page_after_full_pages | unknownHow we reached that verdict. New reasons may be added; listing_status stays three-valued, so branch on that.
items_returnednumber | nullTotal posts delivered across the whole paging run. null if you paged with a raw Reddit token.
final_page_itemsnumber | nullPosts on the final page, published so you can re-derive the verdict instead of trusting it.
hintstringPlain-language explanation, safe to show a human.

listing_status answers the only question a paging client has:

  • complete means 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.
  • truncated means you reached Reddit's ~1000 cap. More history exists and this listing cannot reach it.
  • unknown means we cannot tell, and we will not guess. Do not treat unknown as 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, best each return a different listing.
  • Timeframes: pair sort=top with t=hour|day|week|month|year|all to slice history into chunks that individually stay under the cap.
  • Search: /api/reddit/search with 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

FieldTypeNotes
idstringPost id without prefix
namestringFull 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.
titlestringPost title
authorstringUsername (no u/ prefix)
author_infoobject{ 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.
permalinkstringPath on reddit.com
urlstringFull reddit.com URL
link_urlstring | nullExternal link / media URL the post points at. null for self/text posts since the post has no separate destination.
textstringSelf-post body (empty for link/image posts)
subredditstringSubreddit name (no r/ prefix)
upvotesnumberNet votes (upvotes − downvotes). Reddit doesn't expose raw counts.
commentsnumberComment count
upvote_rationumberApproximate (Reddit fuzzes this for fresh posts)
over_18, stickied, locked, spoilerbooleanPost flags
is_selfbooleanTrue for text/self posts
is_crosspostbooleanTrue if this post was crossposted from another subreddit
crosspost_originobject | nullWhen 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_utcnumberUnix epoch seconds
createdstringISO-8601 form of created_utc

Independent third-party API for developers and researchers. Not affiliated with, endorsed by, or sponsored by Reddit, Inc.

On this page