# threadapi > Reddit API for AI agents and data pipelines. One HTTPS call returns a Reddit post with its full comment tree, as JSON or as one compact Markdown document an LLM can read. Also: subreddit and user listings, posts and comments by ID, search over posts, comments, subreddits and users, and keyword monitors that watch all of Reddit. No Reddit account, OAuth app or proxy needed. > Docs: https://docs.threadapi.dev > Full specs: https://threadapi.dev/llms-full.txt > OpenAPI: https://threadapi.dev/openapi.json > Base URL: https://api.threadapi.dev/v1 > MCP server: https://api.threadapi.dev/mcp (Streamable HTTP; OAuth sign-in or Authorization: Bearer ; setup: https://docs.threadapi.dev/mcp) ## When to use threadapi - You need what people on Reddit said about something: a product, a library, a decision. Read a thread with its comments, nested as on Reddit. - You want the thread as LLM input: `format=md` returns the post, a short digest (the original poster's replies, the most upvoted and the controversial comments) and the comment tree, without markup noise. - You are calling from a server or cloud function where requests to Reddit get blocked or rate limited. - You want a subreddit's hot, new or top posts, a user's history, or to search Reddit, without registering a Reddit app. - You want to hear about new posts or comments that mention a keyword, anywhere on Reddit, by webhook or by polling. ## When not to use it - Private, quarantined or banned subreddits, and removed posts. These return an error and cost nothing. - Posting, voting or anything that needs a Reddit account. threadapi only reads public content. - Downloading images or video files. Media come back as URLs. ## Pricing - A post costs 1 credit for up to 500 comments, and 1 more per further 100 comments returned. `max_comments` defaults to 200 (1 credit) and goes up to 2,000. - Every other read (a listing, a search, a profile, up to 100 items by ID) costs 1 credit. - A keyword monitor costs 10 credits per day while it runs; its matches are free. - Failed requests are free. Every response carries `X-Credits-Used`. - Credit packs never expire: $9 for 3,000, $29 for 15,000, $79 for 80,000. New accounts get 200 free credits; no card. https://threadapi.dev/pricing?utm_source=llms ## Errors - Errors are JSON: `{"error": {"code": "...", "message": "...", "retryable": false}}`. - Retry only when `retryable` is true, after `Retry-After` if present. Codes: `invalid_request` 400, `unauthorized` 401, `insufficient_credits` / `monitor_limit_reached` 402, `forbidden` / `nsfw_subreddit` / `reddit_refused` 403, `not_found` 404, `rate_limited` / `daily_limit_reached` 429, `upstream_busy` / `upstream_timeout` / `upstream_error` / `upstream_changed` / `service_unavailable` 503. ## Get an API key - Sign up at https://threadapi.dev/auth/login?utm_source=llms (Google, GitHub or an email code). - Create a key at https://threadapi.dev/app/api-keys?utm_source=llms (keys start with `tapi_`). - An agent can create the account for its user without a browser: the user gives an email address and reads back a 6-digit code (see https://docs.threadapi.dev/agent-signup). - Until a credit pack is bought, a key can make 1 request per second and 100 requests per day (UTC). ## Authentication ```http Authorization: Bearer ``` ## Endpoints - `GET /v1/reddit/post?url={post or comment URL, or ID}&max_comments=200&format=json|md|graph`: a post, its comments and a digest. - `GET /v1/reddit/post/duplicates?id=`: other posts of the same link, and crossposts. - `GET /v1/reddit/things?ids=`: up to 100 posts or comments by fullname, ID or URL. - `GET /v1/reddit/subreddit?sub={name}&sort=hot|new|top|rising|controversial&t=week&limit=25&after=`: a subreddit's posts. - `GET /v1/reddit/subreddit/comments?sub=`: a subreddit's newest comments. - `GET /v1/reddit/subreddit/about?sub=`: description, subscribers and rules. - `GET /v1/reddit/subreddits?sort=popular|new`: popular or new subreddits. - `GET /v1/reddit/user?name=`, `/v1/reddit/user/posts?name=`, `/v1/reddit/user/comments?name=`: a profile and its history. - `GET /v1/reddit/search?q={query}&type=post|subreddit|user&sub=&sort=relevance|new|top|comments&t=week`: search. - `GET /v1/reddit/search/comments?q=`: search comments. - `POST /v1/monitors` and `GET /v1/monitors/{id}/matches`: keyword monitors over all of Reddit. - MCP tools: `get_reddit_post`, `get_reddit_items`, `list_subreddit_posts`, `get_subreddit`, `get_reddit_user`, `search_reddit`, `get_monitor_matches`. --- ## Reading a thread GET /v1/reddit/post?url=https://www.reddit.com/r/programming/comments/1x144ok/&max_comments=200 JSON response (format=json): { "post": { "id": "1x144ok", "subreddit": "programming", "title": "How big is a Git commit?", "author": "fagnerbrack", "score": 79, "upvote_ratio": 0.81, "num_comments": 26, "permalink": "/r/programming/comments/1x144ok/how_big_is_a_git_commit/", "url": "https://...", "selftext": "", "created_at": "2026-10-08T22:00:15Z", "media": [], "comments": [ {"id": "abc", "parent_id": "t3_1x144ok", "author": "Bpofficial", "score": 152, "body": "At least 3", "depth": 0, "is_submitter": false, "replies": [ ... ]} ] }, "discussion_graph": { "author_followups": [ comments by the original poster ], "most_upvoted": [ highest score; the original poster, AutoModerator and deleted comments left out ], "controversial": [ Reddit's controversial flag, or a negative score ], "total_analyzed": 26 }, "meta": {"comments_returned": 26, "comments_total": 26, "has_more": false, "max_comments": 200, "credits_used": 1, "cache": "MISS"} } Markdown response (format=md): # How big is a Git commit? r/programming, u/fagnerbrack, 79 points (81% upvoted), 26 comments, posted 2026-10-08 22:00 UTC https://www.reddit.com/r/programming/comments/1x144ok/how_big_is_a_git_commit/ ## Digest Most upvoted: - u/Bpofficial (+152): At least 3 ## Comments (26 of 26) - u/Bpofficial (+152): At least 3 - u/someone (+12): a reply, indented under its parent --- ## Listings and pagination Listing routes return {"items": [...], "after": "t3_..." or null, "filtered_nsfw": N}. Pass after to get the next page. NSFW items are left out unless nsfw=true; a subreddit marked NSFW answers 403 nsfw_subreddit without it. --- ## MCP Endpoint: https://api.threadapi.dev/mcp (Streamable HTTP, stateless). Auth: OAuth (your MCP client opens a sign-in page) or Authorization: Bearer . Tools: - get_reddit_post(post, comment?, context?, max_comments?, format? = markdown | json) - get_reddit_items(ids) - list_subreddit_posts(subreddit, sort?, time?, limit?, after?, nsfw?) - get_subreddit(subreddit) - get_reddit_user(name, include? = posts | comments) - search_reddit(query, type? = post | comment | subreddit | user, subreddit?, sort?, time?, limit?, after?, nsfw?) - get_monitor_matches(monitor_id, after?, limit?) Tool calls are billed like the REST routes they map to; errors are free. --- # Endpoint reference (from https://threadapi.dev/openapi.json) ## GET /v1/reddit/post Get a post and its comments. Returns the post, its comment tree (up to `max_comments`, widest first: all top-level comments before replies), and a digest: the original poster's replies, the most upvoted comments, and the ones Reddit marks controversial. A comment permalink in `url`, or `comment`, focuses the response on that comment. Pricing: 1 credit for up to 500 comments, plus 1 per further 100 returned. `max_comments` defaults to 200, which always costs 1 credit. If the balance covers fewer pages than asked for, the response holds what it covers and `meta.limited_by_balance` is true. Parameters: - url: A reddit.com post URL (any subdomain), a redd.it link, a `t3_` fullname or a post ID. Either `url` or `id` is required. - id: Post ID, the same as `url`. - comment: A comment ID to focus on, returning its ancestor chain and direct replies. - context (0-8, default 3): Number of ancestor context levels to include when focused on a comment (0 to 8, default 3). - max_comments (0-2000, default 200): Most comments to return. 0 returns the post alone. - format (json | md | graph, default "json"): `json` (post, graph and meta), `md` (one Markdown document for an LLM) or `graph` (discussion graph and meta only). Returns 200: PostResponse. --- ## GET /v1/reddit/post/duplicates Get duplicate posts and crossposts. Returns other discussions and crossposts for a post (/duplicates/.json). 1 credit per call. Parameters: - id: Reddit post ID (e.g. `1x1ai6v` or `t3_1x1ai6v`). Required if `url` is not provided. - url: Reddit post URL. Required if `id` is not provided. - limit (1-100, default 25): Posts to return. - after: Fullname of the last item on the previous page (e.g. `t3_1x2y3z`) for pagination. - nsfw (default false): Include NSFW posts. Default is false (NSFW posts are filtered out). Returns 200: Listing. --- ## GET /v1/reddit/things Look up posts and comments by ID. Looks up to 100 Reddit items (posts and comments) by fullname (`t1_`, `t3_`), bare ID, or URL. Returns items in the order requested, noting any missing IDs. 1 credit per call. Parameters: - ids (required): Comma-separated list of up to 100 Reddit IDs or URLs. Returns 200: ThingsResponse. --- ## GET /v1/reddit/subreddit List a subreddit's posts. 1 credit per call. Parameters: - sub (required): Subreddit name, with or without `r/`. - sort (hot | new | top | rising | controversial, default "hot") - t (hour | day | week | month | year | all): Time window for `sort=top` or `controversial` (and search). - limit (1-100, default 25): Posts to return. - after: Fullname of the last item on the previous page (e.g. `t3_1x2y3z`) for pagination. - nsfw (default false): Include NSFW posts. Default is false (NSFW posts are filtered out). Returns 200: Listing. --- ## GET /v1/reddit/subreddit/about Get subreddit details and rules. Returns subreddit description, subscriber count, settings, and moderation rules. 1 credit per call. Parameters: - sub (required): Subreddit name, with or without `r/`. Returns 200: Subreddit. --- ## GET /v1/reddit/subreddit/comments Get recent comments in a subreddit. Returns recent comments from a subreddit (/r/{sub}/comments.json). 1 credit per call. Parameters: - sub (required): Subreddit name (e.g. `golang` or `r/golang`). - limit (1-100, default 25): Posts to return. - after: Fullname of the last item on the previous page (e.g. `t3_1x2y3z`) for pagination. - nsfw (default false): Include NSFW posts. Default is false (NSFW posts are filtered out). Returns 200: CommentListing. --- ## GET /v1/reddit/subreddits List subreddits. Returns popular or new subreddits (/subreddits/{popular,new}.json). 1 credit per call. Parameters: - sort (popular | new, default "popular"): Subreddit listing sort. - limit (1-100, default 25): Posts to return. - after: Fullname of the last item on the previous page (e.g. `t3_1x2y3z`) for pagination. - nsfw (default false): Include NSFW posts. Default is false (NSFW posts are filtered out). Returns 200: SubredditListing. --- ## GET /v1/reddit/user Get Reddit user profile. Returns user karma breakdown, created timestamp, badges, and suspension status. 1 credit per call. Parameters: - name (required): Reddit username (3 to 20 letters, numbers, underscores, or dashes). Returns 200: User. --- ## GET /v1/reddit/user/posts Get user submissions. Returns posts submitted by a user. 1 credit per call. Parameters: - name (required): Reddit username. - sort (new | hot | top | controversial, default "new") - t (hour | day | week | month | year | all): Time window for `sort=top` or `controversial` (and search). - limit (1-100, default 25): Posts to return. - after: Fullname of the last item on the previous page (e.g. `t3_1x2y3z`) for pagination. - nsfw (default false): Include NSFW posts. Default is false (NSFW posts are filtered out). Returns 200: Listing. --- ## GET /v1/reddit/user/comments Get user comments. Returns comments submitted by a user. 1 credit per call. Parameters: - name (required): Reddit username. - sort (new | hot | top | controversial, default "new") - t (hour | day | week | month | year | all): Time window for `sort=top` or `controversial` (and search). - limit (1-100, default 25): Posts to return. - after: Fullname of the last item on the previous page (e.g. `t3_1x2y3z`) for pagination. - nsfw (default false): Include NSFW posts. Default is false (NSFW posts are filtered out). Returns 200: CommentListing. --- ## GET /v1/reddit/search Search posts. 1 credit per call. Parameters: - q (required; up to 256 characters): Search query, 1 to 256 characters. - type (post | subreddit | user, default "post"): Type of content to search: post (default), subreddit, or user. - sub: Only search this subreddit. - sort (relevance | new | top | comments, default "relevance") - t (hour | day | week | month | year | all): Time window for `sort=top` or `controversial` (and search). - limit (1-100, default 25): Posts to return. - after: Fullname of the last item on the previous page (e.g. `t3_1x2y3z`) for pagination. - nsfw (default false): Include NSFW posts. Default is false (NSFW posts are filtered out). Returns 200: Listing | SubredditListing | UserListing. --- ## GET /v1/reddit/search/comments Search comments. Searches Reddit comments across Reddit or scoped to a subreddit. A page holds what Reddit's comment search page shows, about a dozen comments; there is no `limit`. Pass `after` for the next page. 1 credit per call. Parameters: - q (required; up to 500 characters): Search query, 1 to 500 characters. - sub: Only search this subreddit. - sort (relevance | new | top, default "relevance") - t (hour | day | week | month | year | all): Time window for `sort=top` or `controversial` (and search). - after: Fullname of the last item on the previous page (e.g. `t3_1x2y3z`) for pagination. - nsfw (default false): Include NSFW posts. Default is false (NSFW posts are filtered out). Returns 200: CommentListing. --- ## POST /v1/monitors Create a keyword monitor. Creates a new keyword monitor across Reddit posts and/or comments. Billed 10 credits upfront for the first 24 hours. Daily match volume and webhooks are free. JSON body: - name (string; required) - keywords (string[]; required) - exclude (string[]) - subreddits (string[]) - posts (boolean; default true) - comments (boolean; default true) - nsfw (boolean; default false) - webhook_url (string) - webhook_kind (string; generic | slack | discord) Returns 201: object. --- ## GET /v1/monitors List user monitors. Returns all monitors configured by the authenticated user. Free (0 credits). Returns 200: object. --- ## GET /v1/monitors/{id} Get a monitor and its stats. Returns monitor configuration and 24h/7d delivery and match statistics. Free (0 credits). Parameters: - id (path; required) Returns 200: object. --- ## PATCH /v1/monitors/{id} Update a monitor. Updates monitor settings. Changing the webhook URL clears any webhook_failing status. Free (0 credits). Parameters: - id (path; required) JSON body: - name (string) - keywords (string[]) - exclude (string[]) - subreddits (string[]) - posts (boolean) - comments (boolean) - nsfw (boolean) - webhook_url (string) - webhook_kind (string; generic | slack | discord) Returns 200: object. --- ## DELETE /v1/monitors/{id} Delete a monitor. Soft-deletes a monitor. Charging stops immediately. Free (0 credits). Parameters: - id (path; required) Returns 200: object. --- ## POST /v1/monitors/{id}/pause Pause a monitor. Pauses a monitor. Stops match tracking and daily charges. Free (0 credits). Parameters: - id (path; required) Returns 200: object. --- ## POST /v1/monitors/{id}/resume Resume a monitor. Resumes a paused monitor. Immediately charges 10 credits for the next 24 hours. Parameters: - id (path; required) Returns 200: object. --- ## POST /v1/monitors/{id}/rotate-secret Rotate webhook HMAC secret. Generates and returns a new HMAC secret for generic webhooks. Free (0 credits). Parameters: - id (path; required) Returns 200: object. --- ## POST /v1/monitors/{id}/test Test webhook delivery. Sends a sample test match to the configured webhook URL. Rate limited to 5 per minute. Free (0 credits). Parameters: - id (path; required) Returns 200: object. --- ## GET /v1/monitors/{id}/matches Get matches for a monitor. Oldest first by default, for polling: pass the ID of the last match you received as `after` and you get what arrived since. `after` in the response is set only when more matches are waiting right now. `order=newest` lists newest first, paged with `before`. Free (0 credits). Parameters: - id (path; required) - order (oldest | newest, default "oldest"): `oldest` (default) or `newest`. - after: With `order=oldest`, a match ID; returns the matches after it. - before: With `order=newest`, a match ID; returns the matches before it. - limit (1-200, default 100): Maximum items to return (1-200, default 100). Returns 200: object. --- ## Response objects ### Error - error: object ### PostResponse - post: Post - discussion_graph: DiscussionGraph - meta: PostMeta ### PostMeta - comments_returned: integer. Comments in the response. - comments_total: integer. Reddit's comment count, deleted and hidden comments included. - has_more: boolean. A larger max_comments would return more. - max_comments: integer - credits_used: integer - cache: string - limited_by_balance: boolean - focus_comment_id: string. Comment ID when a comment permalink was requested. ### Post - id: string - name: string - domain: string - is_self: boolean - flair: string - spoiler: boolean - stickied: boolean - locked: boolean - removed: boolean - subreddit: string - title: string - author: string - score: integer - upvote_ratio: number - num_comments: integer - url: string - permalink: string - selftext: string - created_at: string - is_video: boolean - over_18: boolean - media: object[] - poll: object - crosspost_of: object - comments: Comment[] ### Comment - id: string - parent_id: string. t3_ for a top-level comment, t1_ for a reply. - author: string - score: integer - body: string - created_at: string - depth: integer - is_submitter: boolean. Written by the original poster. - controversy: integer - replies: Comment[] ### DiscussionGraph - post_id: string - title: string - author: string - author_followups: Comment[]. The original poster's own comments in the thread. - most_upvoted: Comment[]. Highest-score comments excluding OP, AutoModerator and deleted comments. - controversial: Comment[]. Comments with controversiality flag or negative score, excluding OP. - total_analyzed: integer ### Listing - subreddit: string - query: string - sort: string - count: integer - items: Post[] - after: string - filtered_nsfw: integer - degraded: boolean ### ThingItem - kind: string - post: Post - comment: CommentItem ### ThingsResponse - items: ThingItem[] - missing: string[] ### CommentItem - id: string - name: string - post_id: string - post_title: string - subreddit: string - author: string - score: integer - body: string - created_at: string - permalink: string - parent_id: string - is_submitter: boolean - controversiality: integer ### SubredditRule - kind: string - short_name: string - description: string - violation_reason: string - priority: integer - created_at: string ### Subreddit - name: string - title: string - public_description: string - description: string - subscribers: integer - created_at: string - over_18: boolean - type: string - url: string - icon: string - rules: SubredditRule[] ### User - name: string - created_at: string - link_karma: integer - comment_karma: integer - total_karma: integer - is_employee: boolean - is_mod: boolean - has_verified_email: boolean - icon: string - suspended: boolean ### CommentListing - subreddit: string - query: string - sort: string - count: integer - items: CommentItem[] - after: string - filtered_nsfw: integer - degraded: boolean ### SubredditListing - query: string - sort: string - count: integer - items: Subreddit[] - after: string - filtered_nsfw: integer - degraded: boolean ### UserListing - query: string - sort: string - count: integer - items: User[] - after: string - filtered_nsfw: integer - degraded: boolean ### Monitor - id: string - name: string - keywords: string[] - exclude: string[] - subreddits: string[] - include_posts: boolean - include_comments: boolean - nsfw: boolean - webhook_url: string - webhook_kind: string - status: string - webhook_failing: boolean - next_charge_at: string - last_match_at: string - created_at: string - updated_at: string ### MonitorMatch - id: string - monitor_id: string - thing_id: string - kind: string - subreddit: string - author: string - title: string - body: string - permalink: string - post_id: string - created_utc: string - matched_terms: string[] - suppressed: boolean - delivery_status: string - delivered_at: string - created_at: string ### MonitorStats - matches_today: integer - suppressed_today: integer - matches_7d: integer - last_match_at: string - delivery_failures_24h: integer