A fast, read-only Reddit API — posts, comments, comment trees, subreddits, and user profiles. Pay per request — 1 credit = 1 call, $0.50 (333 credits) free on signup, no card required. Full machine-readable spec at /openapi.json.
curl "https://api.threadsnoop.com/v1/posts?subreddit=startups&limit=25" \
-H "x-api-key: ts_live_YOUR_KEY"import requests
r = requests.get(
"https://api.threadsnoop.com/v1/posts",
headers={"x-api-key": "ts_live_YOUR_KEY"},
params={"subreddit": "startups", "limit": 25},
)
data = r.json()
print(data["_threadsnoop"])Pass your key as either header — both are accepted on every request:
x-api-key: ts_live_YOUR_KEY
# or
Authorization: Bearer ts_live_YOUR_KEYA missing key returns 401; an unknown or revoked key also returns 401.
1 credit = 1 read = 1 request, regardless of endpoint. Credits never expire. The price you pay per credit is set at top-up time by a bulk-discount ladder — metering itself stays a flat 1 credit/request forever:
| Top-up | Per read | Per 1,000 reads | Credits |
|---|---|---|---|
| $5 – $24 | $0.0015 | $1.50 | 3,333 per $5 |
| $25 – $49 | $0.0013 | $1.30 | 19,230 at $25 |
| $50 – $99 | $0.0012 | $1.20 | 41,666 at $50 |
| $100+ | $0.0010 | $1.00 | 100,000 per $100 |
Run out of balance and a request returns 402 with a top-up link in the body — never silent degradation. If a call is charged and then fails upstream (502), the credit is refunded automatically.
Every key gets the same limit: 2 requests/second sustained, burst 10. Go over it and you get 429 with a Retry-After header (seconds to wait). Separately, all API traffic shares one global upstream reserve that protects capacity for ThreadSnoop's own discovery pipeline — if that shared pool is briefly exhausted you also get 429, but with an x-ratelimit-scope: global header so you can tell it apart from your own per-key limit. Neither case charges a credit.
7 endpoints. Every 200 response carries x-credits-used and x-credits-remaining headers alongside the JSON body's _threadsnoop block. Jump to a specific one from the sidebar (or the chip row above, on a narrow screen).
Post and comment objects both include permalink — a relative path, so prepend https://www.reddit.com for a clickable URL — and posts also carry an absolute url field.
List posts by subreddit/author, or fetch specific posts by id in one call.
Two modes on one route. Pass subreddit and/or author to page through a listing (newest-first by default). Or pass ids (comma-separated, capped at 100) to fetch exact posts by id — in that mode every other listing param is ignored, and the response has cursor: null, has_more: false (there's no next page for a fixed id list). Either mode is 1 credit.
| Param | Type | Default | Notes |
|---|---|---|---|
| subreddit | string | — | Subreddit name, no r/. One of subreddit/author/ids is required. |
| author | string | — | Reddit username, no u/. |
| ids | string | — | Comma-separated post ids (max 100). When set, listing params below are ignored. |
| after | string | — | Epoch seconds or relative form (e.g. 7d), passed through as-is. |
| before | string | — | Same accepted forms as after. |
| limit | integer | 25 | 1–100. |
| sort | asc | desc | desc | By created_utc. |
| fields | string | — | Comma-separated field allowlist. Omit for the full untrimmed object. |
| q | string | — | Client-side exact-phrase filter over title + selftext. See the pagination guide below. |
curl "https://api.threadsnoop.com/v1/posts?subreddit=startups&limit=2" \
-H "x-api-key: ts_live_YOUR_KEY"{
"data": [
{
"id": "1abcxyz",
"title": "Anyone know a tool that watches Reddit for me?",
"selftext": "Tired of manually searching every day...",
"author": "some_founder",
"created_utc": 1753000000,
"subreddit": "startups",
"permalink": "/r/startups/comments/1abcxyz/anyone_know_a_tool_that_watches_reddit_for_me/",
"url": "https://www.reddit.com/r/startups/comments/1abcxyz/anyone_know_a_tool_that_watches_reddit_for_me/",
"num_comments": 4,
"score": 12,
"hide_score": false
}
],
"_threadsnoop": {
"cursor": 1753000000,
"has_more": true,
"credits_used": 1,
"credits_remaining": 332
}
}Full nested comment tree for a post, with a real comment count.
One call returns the whole tree, so there's no pagination — cursor/has_more are always null/false. Fresh posts can briefly report a score of 1 and 0 comments; use this endpoint for live comment counts.
| Param | Type | Default | Notes |
|---|---|---|---|
| post_id * | string | — | With or without the t3_ prefix. |
| limit | integer | 50 | 1–500. |
curl "https://api.threadsnoop.com/v1/comments/tree?post_id=1abcxyz&limit=50" \
-H "x-api-key: ts_live_YOUR_KEY"{
"data": [
{
"kind": "t1",
"data": {
"id": "kxyzabc",
"body": "I've been looking for exactly this",
"author": "some_founder",
"created_utc": 1753001200,
"score": 3
},
"replies": []
}
],
"_threadsnoop": {
"cursor": null,
"has_more": false,
"credits_used": 1,
"credits_remaining": 330
}
}Search subreddits by name.
Returns up to 10 matches. No customer-facing limit and no pagination — cursor/has_more are always null/false.
| Param | Type | Default | Notes |
|---|---|---|---|
| q * | string | — | Subreddit name or name prefix. |
curl "https://api.threadsnoop.com/v1/subreddits/search?q=saas" \
-H "x-api-key: ts_live_YOUR_KEY"{
"data": [
{ "name": "SaaS", "subscribers": 180000, "description": "A place for SaaS founders..." }
],
"_threadsnoop": {
"cursor": null,
"has_more": false,
"credits_used": 1,
"credits_remaining": 329
}
}A subreddit's posting rules.
| Param | Type | Default | Notes |
|---|---|---|---|
| name * | string (path) | — | 3–21 chars, letters/digits/underscore only. |
curl "https://api.threadsnoop.com/v1/subreddits/SaaS/rules" \
-H "x-api-key: ts_live_YOUR_KEY"{
"data": {
"subreddit": "SaaS",
"rules": [
{ "short_name": "No self-promotion", "description": "Do not post ads or referral links.", "priority": 0 }
]
},
"_threadsnoop": { "credits_used": 1, "credits_remaining": 328 }
}A Reddit user's profile aggregate — karma, post/comment counts, first/last activity.
Roughly Reddit's own /user/{name}/about. Exact username match, not prefix/fuzzy search. A username with no matching account is still 1 credit — the lookup made a real upstream call either way — and comes back as a normal 200 with data.user: null rather than a 404.
| Param | Type | Default | Notes |
|---|---|---|---|
| name * | string (path) | — | 3–64 chars, letters/digits/underscore/hyphen. A name with no matching account is still charged — see above. |
curl "https://api.threadsnoop.com/v1/users/spez" \
-H "x-api-key: ts_live_YOUR_KEY"{
"data": {
"user": {
"author": "spez",
"id": "1w72",
"_meta": {
"num_posts": 549,
"num_comments": 2568,
"post_karma": 832984,
"comment_karma": 666948,
"total_karma": 1499932,
"earliest_post_at": 1119552314,
"earliest_comment_at": 1134392748,
"last_post_at": 1751475161,
"last_comment_at": 1729645028
}
}
},
"_threadsnoop": { "credits_used": 1, "credits_remaining": 327 }
}{
"data": { "user": null },
"_threadsnoop": { "credits_used": 1, "credits_remaining": 326 }
}Check your credit balance and rate limit. Free — 0 credits.
Costs nothing and doesn't make an upstream request, but it's still key-authed and rate-limited like every other endpoint.
curl "https://api.threadsnoop.com/v1/account" \
-H "x-api-key: ts_live_YOUR_KEY"{
"data": { "credits_balance": 328, "rate_limit": { "qps": 2, "burst": 10 } },
"_threadsnoop": { "credits_used": 0, "credits_remaining": 328 }
}The cursor is the created_utc of the last row in the page you got back. Pass it forward as after when sorting asc, or as before when sorting desc (the default), to fetch the next page. has_moreis true whenever the page came back full — keep going until it's false or you have enough.
q= is a client-side exact-phrase filter (with basic singular/plural flexibility) applied to whatever page comes back — it is not server-side search. You pay 1 credit per page fetched whether it matched your phrase or not, and cursor/has_more always describe the raw page, not the filtered result — a page that comes back with 0 rows after filtering does notmean there's nothing left; it means keep paginating with the returned cursor. Scope your window with after/before to control how much you scan (and pay for) per search.
A remote MCP server at https://api.threadsnoop.com/mcp, authenticated with the same x-api-key header. Seven tools, each billed exactly like the HTTP endpoint it wraps (1 credit/call; check_credits is free):
search_posts, search_comments — list/search posts and comments, or fetch by id.get_comment_tree — full comment tree for a post.search_subreddits, get_subreddit_rules — subreddit lookup.get_user_profile — a Reddit user's karma/post/comment aggregate.check_credits — balance + rate limit. Free.claude mcp add --transport http threadsnoop https://api.threadsnoop.com/mcp \
--header "x-api-key: YOUR_KEY"{
"mcpServers": {
"threadsnoop": {
"url": "https://api.threadsnoop.com/mcp",
"headers": {
"x-api-key": "YOUR_KEY"
}
}
}
}Machine-readable reference: OpenAPI spec.
GET/v1/comments
List comments by subreddit/author, or fetch specific comments by id.
Same shape as
/v1/posts, including a matchingidsbatch mode: passids(comma-separated, capped at 100) to fetch exact comments by id in one call — every other listing param is ignored in that mode, and the response hascursor: null,has_more: false. Either mode is 1 credit.