# ThreadAPI Docs > Guides and API reference for ThreadAPI. Index: https://staging.threadapi.dev/llms.txt # ThreadAPI API > Public REST API for billing, user balance, and Reddit data extraction. Source: https://staging.threadapi.dev/api/ · Markdown: https://staging.threadapi.dev/api/index.md Public REST API for billing, user balance, and Reddit data extraction. Version: 1.0.0 ## Servers - `https://api.threadapi.dev` - `https://staging.threadapi.dev` ## Sections - [System](/api/tags/System/) - [User](/api/tags/User/) - [Jobs](/api/tags/Jobs/) - [Reddit](/api/tags/Reddit/) - [Monitors](/api/tags/Monitors/) # Execute job > Runs a billable job by action name and parameters, deducting credits accordingly. Source: https://staging.threadapi.dev/api/Jobs/executeJob/ · Markdown: https://staging.threadapi.dev/api/Jobs/executeJob/index.md Path: ThreadAPI API › Jobs `POST /api/v1/jobs/execute` Runs a billable job by action name and parameters, deducting credits accordingly. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Request body _Required._ - `action` (`executeJob.action`; string, required) — Name of the job action to execute - one of `"transcribe_video_summary"`, `"generate_embeddings_batch"`, `"dispatch_webhook_event"`; example `"generate_embeddings_batch"` - `params` (`executeJob.params`; object, optional) — Arbitrary parameters for the job action - example `{}` ## Example request ```json { "action": "generate_embeddings_batch", "params": {} } ``` ## Code samples ### cURL ```bash curl --request POST \ --url https://api.threadapi.dev/api/v1/jobs/execute \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data ' { "action": "generate_embeddings_batch", "params": {} } ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/api/v1/jobs/execute'; const options = { method: 'POST', headers: {'Content-Type': 'application/json', Authorization: 'Bearer '}, body: JSON.stringify({action: 'generate_embeddings_batch', params: {}}) }; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/api/v1/jobs/execute" payload = { "action": "generate_embeddings_batch", "params": {} } headers = { "Content-Type": "application/json", "Authorization": "Bearer " } response = requests.post(url, json=payload, headers=headers) print(response.text) ``` ## Responses ### 200 Job executed successfully #### Example ```json { "success": true, "action": "generate_embeddings_batch", "credits_deducted": 10, "remaining_credits": 90, "processed_at": "2026-10-23T12:00:00Z", "output": "Job completed successfully by core-go engine" } ``` - `success` (`executeJob.response.200.success`; boolean, required) - example `true` - `action` (`executeJob.response.200.action`; string, required) - example `"generate_embeddings_batch"` - `credits_deducted` (`executeJob.response.200.credits_deducted`; integer, required) - example `10` - `remaining_credits` (`executeJob.response.200.remaining_credits`; integer, required) - example `90` - `processed_at` (`executeJob.response.200.processed_at`; string, required) - format `date-time`; example `"2026-10-23T12:00:00Z"` - `output` (`executeJob.response.200.output`; string, required) - example `"Job completed successfully by core-go engine"` ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 Insufficient credit balance to execute the requested job #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` - `error` (`executeJob.response.402.error`; string, required) — Human-readable error message - example `"unauthorized: missing or invalid credentials"` - `error_code` (`executeJob.response.402.error_code`; string, optional) — Machine-readable error code. Known values include: forbidden_scope, rate_limited, daily_quota_exceeded, insufficient_credits, duplicate_transaction. Additional codes may be introduced in future releases. - one of `"forbidden_scope"`, `"rate_limited"`, `"daily_quota_exceeded"`, `"insufficient_credits"`, `"duplicate_transaction"`; example `"insufficient_credits"` ### 403 Insufficient permissions or scope for this endpoint #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 409 Conflict (e.g. duplicate transaction or idempotent request collision) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` - `error` (`executeJob.response.409.error`; string, required) — Human-readable error message - example `"unauthorized: missing or invalid credentials"` - `error_code` (`executeJob.response.409.error_code`; string, optional) — Machine-readable error code. Known values include: forbidden_scope, rate_limited, daily_quota_exceeded, insufficient_credits, duplicate_transaction. Additional codes may be introduced in future releases. - one of `"forbidden_scope"`, `"rate_limited"`, `"daily_quota_exceeded"`, `"insufficient_credits"`, `"duplicate_transaction"`; example `"insufficient_credits"` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 500 Internal server error #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` - `error` (`executeJob.response.500.error`; string, required) — Human-readable error message - example `"unauthorized: missing or invalid credentials"` - `error_code` (`executeJob.response.500.error_code`; string, optional) — Machine-readable error code. Known values include: forbidden_scope, rate_limited, daily_quota_exceeded, insufficient_credits, duplicate_transaction. Additional codes may be introduced in future releases. - one of `"forbidden_scope"`, `"rate_limited"`, `"daily_quota_exceeded"`, `"insufficient_credits"`, `"duplicate_transaction"`; example `"insufficient_credits"` # Create 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. Source: https://staging.threadapi.dev/api/Monitors/createMonitor/ · Markdown: https://staging.threadapi.dev/api/Monitors/createMonitor/index.md Path: ThreadAPI API › Monitors `POST /v1/monitors` 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. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Request body _Required._ - `name` (`createMonitor.name`; string, required) - example `"Mentions of restic"` - `keywords` (`createMonitor.keywords`; array, required) - example `["restic","\"borg backup\""]` - `exclude` (`createMonitor.exclude`; array, optional) - example `["hiring"]` - `subreddits` (`createMonitor.subreddits`; array, optional) - example `["selfhosted","DataHoarder"]` - `posts` (`createMonitor.posts`; boolean, optional) - default `true` - `comments` (`createMonitor.comments`; boolean, optional) - default `true` - `nsfw` (`createMonitor.nsfw`; boolean, optional) - default `false` - `webhook_url` (`createMonitor.webhook_url`; string, optional) - example `"https://example.com/hook"` - `webhook_kind` (`createMonitor.webhook_kind`; string, optional) - one of `"generic"`, `"slack"`, `"discord"`, `"telegram"` ## Example request ```json { "name": "Mentions of restic", "keywords": [ "restic", "\"borg backup\"" ], "exclude": [ "hiring" ], "subreddits": [ "selfhosted", "DataHoarder" ], "posts": true, "comments": true, "nsfw": false, "webhook_url": "https://example.com/hook", "webhook_kind": "generic" } ``` ## Code samples ### cURL ```bash curl --request POST \ --url https://api.threadapi.dev/v1/monitors \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data ' { "name": "Mentions of restic", "keywords": [ "restic", "\"borg backup\"" ], "exclude": [ "hiring" ], "subreddits": [ "selfhosted", "DataHoarder" ], "posts": true, "comments": true, "nsfw": false, "webhook_url": "https://example.com/hook", "webhook_kind": "generic" } ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors'; const options = { method: 'POST', headers: {'Content-Type': 'application/json', Authorization: 'Bearer '}, body: JSON.stringify({ name: 'Mentions of restic', keywords: ['restic', '"borg backup"'], exclude: ['hiring'], subreddits: ['selfhosted', 'DataHoarder'], posts: true, comments: true, nsfw: false, webhook_url: 'https://example.com/hook', webhook_kind: 'generic' }) }; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors" payload = { "name": "Mentions of restic", "keywords": ["restic", "\"borg backup\""], "exclude": ["hiring"], "subreddits": ["selfhosted", "DataHoarder"], "posts": True, "comments": True, "nsfw": False, "webhook_url": "https://example.com/hook", "webhook_kind": "generic" } headers = { "Content-Type": "application/json", "Authorization": "Bearer " } response = requests.post(url, json=payload, headers=headers) print(response.text) ``` ## Responses ### 201 Created monitor and HMAC secret #### Example ```json { "monitor": { "id": "string", "name": "string", "keywords": [ "string" ], "exclude": [ "string" ], "subreddits": [ "string" ], "include_posts": true, "include_comments": true, "nsfw": true, "webhook_url": "string", "webhook_kind": "generic", "status": "active", "webhook_failing": true, "next_charge_at": "2019-08-24T14:15:22Z", "last_match_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }, "webhook_secret": "string" } ``` - `monitor` (`createMonitor.response.201.monitor`; object, optional) - `id` (`createMonitor.response.201.monitor.id`; string, required) - `name` (`createMonitor.response.201.monitor.name`; string, required) - `keywords` (`createMonitor.response.201.monitor.keywords`; array, required) - `include_posts` (`createMonitor.response.201.monitor.include_posts`; boolean, required) - `include_comments` (`createMonitor.response.201.monitor.include_comments`; boolean, required) - `nsfw` (`createMonitor.response.201.monitor.nsfw`; boolean, required) - `status` (`createMonitor.response.201.monitor.status`; string, required) - one of `"active"`, `"paused"`, `"paused_balance"`, `"deleted"` - `next_charge_at` (`createMonitor.response.201.monitor.next_charge_at`; string, required) - format `date-time` - `created_at` (`createMonitor.response.201.monitor.created_at`; string, required) - format `date-time` - `updated_at` (`createMonitor.response.201.monitor.updated_at`; string, required) - format `date-time` - `exclude` (`createMonitor.response.201.monitor.exclude`; array, optional) - `subreddits` (`createMonitor.response.201.monitor.subreddits`; array, optional) - `webhook_url` (`createMonitor.response.201.monitor.webhook_url`; string | null, optional) - `webhook_kind` (`createMonitor.response.201.monitor.webhook_kind`; string | null, optional) - one of `"generic"`, `"slack"`, `"discord"`, `"telegram"`, `null` - `webhook_failing` (`createMonitor.response.201.monitor.webhook_failing`; boolean, optional) - `last_match_at` (`createMonitor.response.201.monitor.last_match_at`; string | null, optional) - format `date-time` - `webhook_secret` (`createMonitor.response.201.webhook_secret`; string, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`createMonitor.response.402.error`; object, required) - `code` (`createMonitor.response.402.error.code`; string, required) - example `"not_found"` - `message` (`createMonitor.response.402.error.message`; string, required) - `retryable` (`createMonitor.response.402.error.retryable`; boolean, required) - `retry_after` (`createMonitor.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Delete Monitor > Soft-deletes a monitor. Charging stops immediately. Source: https://staging.threadapi.dev/api/Monitors/deleteMonitor/ · Markdown: https://staging.threadapi.dev/api/Monitors/deleteMonitor/index.md Path: ThreadAPI API › Monitors `DELETE /v1/monitors/{id}` Soft-deletes a monitor. Charging stops immediately. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Path parameters - `id` (`deleteMonitor.path.id`; string, required) ## Code samples ### cURL ```bash curl --request DELETE \ --url 'https://api.threadapi.dev/v1/monitors/' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors/'; const options = {method: 'DELETE', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors/" headers = {"Authorization": "Bearer "} response = requests.delete(url, headers=headers) print(response.text) ``` ## Responses ### 200 Monitor deleted #### Example ```json { "status": "deleted" } ``` - `status` (`deleteMonitor.response.200.status`; string, optional) - example `"deleted"` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Get Monitor > Returns monitor configuration and 24-hour/7-day delivery and match statistics. Source: https://staging.threadapi.dev/api/Monitors/getMonitor/ · Markdown: https://staging.threadapi.dev/api/Monitors/getMonitor/index.md Path: ThreadAPI API › Monitors `GET /v1/monitors/{id}` Returns monitor configuration and 24-hour/7-day delivery and match statistics. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Path parameters - `id` (`getMonitor.path.id`; string, required) ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/monitors/' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors/'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors/" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 Monitor with statistics #### Example ```json { "monitor": { "id": "string", "name": "string", "keywords": [ "string" ], "exclude": [ "string" ], "subreddits": [ "string" ], "include_posts": true, "include_comments": true, "nsfw": true, "webhook_url": "string", "webhook_kind": "generic", "status": "active", "webhook_failing": true, "next_charge_at": "2019-08-24T14:15:22Z", "last_match_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }, "stats": { "matches_today": 0, "suppressed_today": 0, "matches_7d": 0, "last_match_at": "2019-08-24T14:15:22Z", "delivery_failures_24h": 0 } } ``` - `monitor` (`getMonitor.response.200.monitor`; object, optional) - `id` (`getMonitor.response.200.monitor.id`; string, required) - `name` (`getMonitor.response.200.monitor.name`; string, required) - `keywords` (`getMonitor.response.200.monitor.keywords`; array, required) - `include_posts` (`getMonitor.response.200.monitor.include_posts`; boolean, required) - `include_comments` (`getMonitor.response.200.monitor.include_comments`; boolean, required) - `nsfw` (`getMonitor.response.200.monitor.nsfw`; boolean, required) - `status` (`getMonitor.response.200.monitor.status`; string, required) - one of `"active"`, `"paused"`, `"paused_balance"`, `"deleted"` - `next_charge_at` (`getMonitor.response.200.monitor.next_charge_at`; string, required) - format `date-time` - `created_at` (`getMonitor.response.200.monitor.created_at`; string, required) - format `date-time` - `updated_at` (`getMonitor.response.200.monitor.updated_at`; string, required) - format `date-time` - `exclude` (`getMonitor.response.200.monitor.exclude`; array, optional) - `subreddits` (`getMonitor.response.200.monitor.subreddits`; array, optional) - `webhook_url` (`getMonitor.response.200.monitor.webhook_url`; string | null, optional) - `webhook_kind` (`getMonitor.response.200.monitor.webhook_kind`; string | null, optional) - one of `"generic"`, `"slack"`, `"discord"`, `"telegram"`, `null` - `webhook_failing` (`getMonitor.response.200.monitor.webhook_failing`; boolean, optional) - `last_match_at` (`getMonitor.response.200.monitor.last_match_at`; string | null, optional) - format `date-time` - `stats` (`getMonitor.response.200.stats`; object, optional) - `matches_today` (`getMonitor.response.200.stats.matches_today`; integer, required) - `suppressed_today` (`getMonitor.response.200.stats.suppressed_today`; integer, required) - `matches_7d` (`getMonitor.response.200.stats.matches_7d`; integer, required) - `delivery_failures_24h` (`getMonitor.response.200.stats.delivery_failures_24h`; integer, required) - `last_match_at` (`getMonitor.response.200.stats.last_match_at`; string | null, optional) - format `date-time` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Get Monitor Matches > Returns matches collected by the monitor. Supports streaming pagination via `after`, or reverse chronological sorting with `order=newest`. Source: https://staging.threadapi.dev/api/Monitors/getMonitorMatches/ · Markdown: https://staging.threadapi.dev/api/Monitors/getMonitorMatches/index.md Path: ThreadAPI API › Monitors `GET /v1/monitors/{id}/matches` Returns matches collected by the monitor. Supports streaming pagination via `after`, or reverse chronological sorting with `order=newest`. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Path parameters - `id` (`getMonitorMatches.path.id`; string, required) ## Query parameters - `order` (`getMonitorMatches.query.order`; string, optional) — Sort ordering for returned matches. - one of `"oldest"`, `"newest"`; default `"oldest"` - `after` (`getMonitorMatches.query.after`; string, optional) — With `order=oldest`, cursor for the next page of matches. - `before` (`getMonitorMatches.query.before`; string, optional) — With `order=newest`, cursor for the next page of matches. - `limit` (`getMonitorMatches.query.limit`; integer, optional) — Maximum items to return. - min 1; max 200; default `100` ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/monitors//matches' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors//matches'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors//matches" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 List of matches #### Example ```json { "items": [ { "id": "string", "monitor_id": "string", "thing_id": "string", "kind": "post", "subreddit": "string", "author": "string", "title": "string", "body": "string", "permalink": "string", "post_id": "string", "created_utc": "2019-08-24T14:15:22Z", "matched_terms": [ "string" ], "suppressed": true, "delivery_status": "none", "delivered_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z" } ], "after": "string", "before": "string" } ``` - `items` (`getMonitorMatches.response.200.items`; array, optional) - `id` (`getMonitorMatches.response.200.items.id`; string, required) - `monitor_id` (`getMonitorMatches.response.200.items.monitor_id`; string, required) - `thing_id` (`getMonitorMatches.response.200.items.thing_id`; string, required) - `kind` (`getMonitorMatches.response.200.items.kind`; string, required) - one of `"post"`, `"comment"` - `subreddit` (`getMonitorMatches.response.200.items.subreddit`; string, required) - `author` (`getMonitorMatches.response.200.items.author`; string, required) - `title` (`getMonitorMatches.response.200.items.title`; string, required) - `body` (`getMonitorMatches.response.200.items.body`; string, required) - `permalink` (`getMonitorMatches.response.200.items.permalink`; string, required) - `post_id` (`getMonitorMatches.response.200.items.post_id`; string, required) - `created_utc` (`getMonitorMatches.response.200.items.created_utc`; string, required) - format `date-time` - `matched_terms` (`getMonitorMatches.response.200.items.matched_terms`; array, required) - `suppressed` (`getMonitorMatches.response.200.items.suppressed`; boolean, required) - `delivery_status` (`getMonitorMatches.response.200.items.delivery_status`; string, required) - one of `"none"`, `"pending"`, `"delivered"`, `"failed"`, `"skipped"` - `created_at` (`getMonitorMatches.response.200.items.created_at`; string, required) - format `date-time` - `delivered_at` (`getMonitorMatches.response.200.items.delivered_at`; string | null, optional) - format `date-time` - `after` (`getMonitorMatches.response.200.after`; string, optional) — With `order=oldest`, the cursor for the next page when one is waiting. - `before` (`getMonitorMatches.response.200.before`; string, optional) ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # List Monitors > Returns all monitors configured by the authenticated user. Source: https://staging.threadapi.dev/api/Monitors/listMonitors/ · Markdown: https://staging.threadapi.dev/api/Monitors/listMonitors/index.md Path: ThreadAPI API › Monitors `GET /v1/monitors` Returns all monitors configured by the authenticated user. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Code samples ### cURL ```bash curl --request GET \ --url https://api.threadapi.dev/v1/monitors \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 List of monitors #### Example ```json { "items": [ { "id": "string", "name": "string", "keywords": [ "string" ], "exclude": [ "string" ], "subreddits": [ "string" ], "include_posts": true, "include_comments": true, "nsfw": true, "webhook_url": "string", "webhook_kind": "generic", "status": "active", "webhook_failing": true, "next_charge_at": "2019-08-24T14:15:22Z", "last_match_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" } ], "limit": 0, "used": 0, "daily_match_cap": 0 } ``` - `items` (`listMonitors.response.200.items`; array, optional) - `id` (`listMonitors.response.200.items.id`; string, required) - `name` (`listMonitors.response.200.items.name`; string, required) - `keywords` (`listMonitors.response.200.items.keywords`; array, required) - `include_posts` (`listMonitors.response.200.items.include_posts`; boolean, required) - `include_comments` (`listMonitors.response.200.items.include_comments`; boolean, required) - `nsfw` (`listMonitors.response.200.items.nsfw`; boolean, required) - `status` (`listMonitors.response.200.items.status`; string, required) - one of `"active"`, `"paused"`, `"paused_balance"`, `"deleted"` - `next_charge_at` (`listMonitors.response.200.items.next_charge_at`; string, required) - format `date-time` - `created_at` (`listMonitors.response.200.items.created_at`; string, required) - format `date-time` - `updated_at` (`listMonitors.response.200.items.updated_at`; string, required) - format `date-time` - `exclude` (`listMonitors.response.200.items.exclude`; array, optional) - `subreddits` (`listMonitors.response.200.items.subreddits`; array, optional) - `webhook_url` (`listMonitors.response.200.items.webhook_url`; string | null, optional) - `webhook_kind` (`listMonitors.response.200.items.webhook_kind`; string | null, optional) - one of `"generic"`, `"slack"`, `"discord"`, `"telegram"`, `null` - `webhook_failing` (`listMonitors.response.200.items.webhook_failing`; boolean, optional) - `last_match_at` (`listMonitors.response.200.items.last_match_at`; string | null, optional) - format `date-time` - `limit` (`listMonitors.response.200.limit`; integer, optional) - `used` (`listMonitors.response.200.used`; integer, optional) - `daily_match_cap` (`listMonitors.response.200.daily_match_cap`; integer, optional) ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Pause Monitor > Pauses a monitor, halting match tracking and daily charges. Source: https://staging.threadapi.dev/api/Monitors/pauseMonitor/ · Markdown: https://staging.threadapi.dev/api/Monitors/pauseMonitor/index.md Path: ThreadAPI API › Monitors `POST /v1/monitors/{id}/pause` Pauses a monitor, halting match tracking and daily charges. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Path parameters - `id` (`pauseMonitor.path.id`; string, required) ## Code samples ### cURL ```bash curl --request POST \ --url 'https://api.threadapi.dev/v1/monitors//pause' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors//pause'; const options = {method: 'POST', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors//pause" headers = {"Authorization": "Bearer "} response = requests.post(url, headers=headers) print(response.text) ``` ## Responses ### 200 Monitor paused #### Example ```json { "status": "paused" } ``` - `status` (`pauseMonitor.response.200.status`; string, optional) - example `"paused"` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Resume Monitor > Resumes a paused monitor. Immediately charges 10 credits for the next 24 hours. Source: https://staging.threadapi.dev/api/Monitors/resumeMonitor/ · Markdown: https://staging.threadapi.dev/api/Monitors/resumeMonitor/index.md Path: ThreadAPI API › Monitors `POST /v1/monitors/{id}/resume` Resumes a paused monitor. Immediately charges 10 credits for the next 24 hours. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Path parameters - `id` (`resumeMonitor.path.id`; string, required) ## Code samples ### cURL ```bash curl --request POST \ --url 'https://api.threadapi.dev/v1/monitors//resume' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors//resume'; const options = {method: 'POST', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors//resume" headers = {"Authorization": "Bearer "} response = requests.post(url, headers=headers) print(response.text) ``` ## Responses ### 200 Resumed monitor #### Example ```json { "monitor": { "id": "string", "name": "string", "keywords": [ "string" ], "exclude": [ "string" ], "subreddits": [ "string" ], "include_posts": true, "include_comments": true, "nsfw": true, "webhook_url": "string", "webhook_kind": "generic", "status": "active", "webhook_failing": true, "next_charge_at": "2019-08-24T14:15:22Z", "last_match_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" } } ``` - `monitor` (`resumeMonitor.response.200.monitor`; object, optional) - `id` (`resumeMonitor.response.200.monitor.id`; string, required) - `name` (`resumeMonitor.response.200.monitor.name`; string, required) - `keywords` (`resumeMonitor.response.200.monitor.keywords`; array, required) - `include_posts` (`resumeMonitor.response.200.monitor.include_posts`; boolean, required) - `include_comments` (`resumeMonitor.response.200.monitor.include_comments`; boolean, required) - `nsfw` (`resumeMonitor.response.200.monitor.nsfw`; boolean, required) - `status` (`resumeMonitor.response.200.monitor.status`; string, required) - one of `"active"`, `"paused"`, `"paused_balance"`, `"deleted"` - `next_charge_at` (`resumeMonitor.response.200.monitor.next_charge_at`; string, required) - format `date-time` - `created_at` (`resumeMonitor.response.200.monitor.created_at`; string, required) - format `date-time` - `updated_at` (`resumeMonitor.response.200.monitor.updated_at`; string, required) - format `date-time` - `exclude` (`resumeMonitor.response.200.monitor.exclude`; array, optional) - `subreddits` (`resumeMonitor.response.200.monitor.subreddits`; array, optional) - `webhook_url` (`resumeMonitor.response.200.monitor.webhook_url`; string | null, optional) - `webhook_kind` (`resumeMonitor.response.200.monitor.webhook_kind`; string | null, optional) - one of `"generic"`, `"slack"`, `"discord"`, `"telegram"`, `null` - `webhook_failing` (`resumeMonitor.response.200.monitor.webhook_failing`; boolean, optional) - `last_match_at` (`resumeMonitor.response.200.monitor.last_match_at`; string | null, optional) - format `date-time` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`resumeMonitor.response.402.error`; object, required) - `code` (`resumeMonitor.response.402.error.code`; string, required) - example `"not_found"` - `message` (`resumeMonitor.response.402.error.message`; string, required) - `retryable` (`resumeMonitor.response.402.error.retryable`; boolean, required) - `retry_after` (`resumeMonitor.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Rotate Webhook Secret > Generates and returns a new HMAC secret for generic webhooks. Source: https://staging.threadapi.dev/api/Monitors/rotateMonitorSecret/ · Markdown: https://staging.threadapi.dev/api/Monitors/rotateMonitorSecret/index.md Path: ThreadAPI API › Monitors `POST /v1/monitors/{id}/rotate-secret` Generates and returns a new HMAC secret for generic webhooks. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Path parameters - `id` (`rotateMonitorSecret.path.id`; string, required) ## Code samples ### cURL ```bash curl --request POST \ --url 'https://api.threadapi.dev/v1/monitors//rotate-secret' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors//rotate-secret'; const options = {method: 'POST', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors//rotate-secret" headers = {"Authorization": "Bearer "} response = requests.post(url, headers=headers) print(response.text) ``` ## Responses ### 200 New secret #### Example ```json { "webhook_secret": "string" } ``` - `webhook_secret` (`rotateMonitorSecret.response.200.webhook_secret`; string, optional) ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Test Webhook Delivery > Sends a sample test match to the configured webhook URL. Rate limited to 5 per minute. Source: https://staging.threadapi.dev/api/Monitors/testMonitor/ · Markdown: https://staging.threadapi.dev/api/Monitors/testMonitor/index.md Path: ThreadAPI API › Monitors `POST /v1/monitors/{id}/test` Sends a sample test match to the configured webhook URL. Rate limited to 5 per minute. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Path parameters - `id` (`testMonitor.path.id`; string, required) ## Code samples ### cURL ```bash curl --request POST \ --url 'https://api.threadapi.dev/v1/monitors//test' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors//test'; const options = {method: 'POST', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors//test" headers = {"Authorization": "Bearer "} response = requests.post(url, headers=headers) print(response.text) ``` ## Responses ### 200 Test delivery outcome #### Example ```json { "delivered": true, "status": 0, "error": "string" } ``` - `delivered` (`testMonitor.response.200.delivered`; boolean, optional) - `status` (`testMonitor.response.200.status`; integer, optional) - `error` (`testMonitor.response.200.error`; string | null, optional) ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Update Monitor > Updates monitor settings. Changing the webhook URL clears any webhook_failing status. Source: https://staging.threadapi.dev/api/Monitors/updateMonitor/ · Markdown: https://staging.threadapi.dev/api/Monitors/updateMonitor/index.md Path: ThreadAPI API › Monitors `PATCH /v1/monitors/{id}` Updates monitor settings. Changing the webhook URL clears any webhook_failing status. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Path parameters - `id` (`updateMonitor.path.id`; string, required) ## Request body _Required._ - `name` (`updateMonitor.name`; string, optional) - `keywords` (`updateMonitor.keywords`; array, optional) - `exclude` (`updateMonitor.exclude`; array, optional) - `subreddits` (`updateMonitor.subreddits`; array, optional) - `posts` (`updateMonitor.posts`; boolean, optional) - `comments` (`updateMonitor.comments`; boolean, optional) - `nsfw` (`updateMonitor.nsfw`; boolean, optional) - `webhook_url` (`updateMonitor.webhook_url`; string | null, optional) - `webhook_kind` (`updateMonitor.webhook_kind`; string | null, optional) - one of `"generic"`, `"slack"`, `"discord"`, `"telegram"`, `null` ## Example request ```json { "name": "string", "keywords": [ "string" ], "exclude": [ "string" ], "subreddits": [ "string" ], "posts": true, "comments": true, "nsfw": true, "webhook_url": "string", "webhook_kind": "generic" } ``` ## Code samples ### cURL ```bash curl --request PATCH \ --url 'https://api.threadapi.dev/v1/monitors/' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data ' { "name": "string", "keywords": [ "string" ], "exclude": [ "string" ], "subreddits": [ "string" ], "posts": true, "comments": true, "nsfw": true, "webhook_url": "string", "webhook_kind": "generic" } ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/monitors/'; const options = { method: 'PATCH', headers: {'Content-Type': 'application/json', Authorization: 'Bearer '}, body: JSON.stringify({ name: 'string', keywords: ['string'], exclude: ['string'], subreddits: ['string'], posts: true, comments: true, nsfw: true, webhook_url: 'string', webhook_kind: 'generic' }) }; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/monitors/" payload = { "name": "string", "keywords": ["string"], "exclude": ["string"], "subreddits": ["string"], "posts": True, "comments": True, "nsfw": True, "webhook_url": "string", "webhook_kind": "generic" } headers = { "Content-Type": "application/json", "Authorization": "Bearer " } response = requests.patch(url, json=payload, headers=headers) print(response.text) ``` ## Responses ### 200 Updated monitor #### Example ```json { "monitor": { "id": "string", "name": "string", "keywords": [ "string" ], "exclude": [ "string" ], "subreddits": [ "string" ], "include_posts": true, "include_comments": true, "nsfw": true, "webhook_url": "string", "webhook_kind": "generic", "status": "active", "webhook_failing": true, "next_charge_at": "2019-08-24T14:15:22Z", "last_match_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" } } ``` - `monitor` (`updateMonitor.response.200.monitor`; object, optional) - `id` (`updateMonitor.response.200.monitor.id`; string, required) - `name` (`updateMonitor.response.200.monitor.name`; string, required) - `keywords` (`updateMonitor.response.200.monitor.keywords`; array, required) - `include_posts` (`updateMonitor.response.200.monitor.include_posts`; boolean, required) - `include_comments` (`updateMonitor.response.200.monitor.include_comments`; boolean, required) - `nsfw` (`updateMonitor.response.200.monitor.nsfw`; boolean, required) - `status` (`updateMonitor.response.200.monitor.status`; string, required) - one of `"active"`, `"paused"`, `"paused_balance"`, `"deleted"` - `next_charge_at` (`updateMonitor.response.200.monitor.next_charge_at`; string, required) - format `date-time` - `created_at` (`updateMonitor.response.200.monitor.created_at`; string, required) - format `date-time` - `updated_at` (`updateMonitor.response.200.monitor.updated_at`; string, required) - format `date-time` - `exclude` (`updateMonitor.response.200.monitor.exclude`; array, optional) - `subreddits` (`updateMonitor.response.200.monitor.subreddits`; array, optional) - `webhook_url` (`updateMonitor.response.200.monitor.webhook_url`; string | null, optional) - `webhook_kind` (`updateMonitor.response.200.monitor.webhook_kind`; string | null, optional) - one of `"generic"`, `"slack"`, `"discord"`, `"telegram"`, `null` - `webhook_failing` (`updateMonitor.response.200.monitor.webhook_failing`; boolean, optional) - `last_match_at` (`updateMonitor.response.200.monitor.last_match_at`; string | null, optional) - format `date-time` ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` # Read Post > Returns a Reddit post with its nested comment tree and synthesized discussion digest, formatted as JSON, Markdown, or a graph. Reddit hides long threads behind "load more comments"; threadapi automatically follows those links until it has collected the requested comments. The digest highlights OP follow-up replies, top-upvoted comments, and controversial discussions. Source: https://staging.threadapi.dev/api/Reddit/getPost/ · Markdown: https://staging.threadapi.dev/api/Reddit/getPost/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/post` Returns a Reddit post with its nested comment tree and synthesized discussion digest, formatted as JSON, Markdown, or a graph. Reddit hides long threads behind "load more comments"; threadapi automatically follows those links until it has collected the requested comments. The digest highlights OP follow-up replies, top-upvoted comments, and controversial discussions. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `url` (`getPost.query.url`; string, optional) — Reddit post URL (any reddit.com, redd.it, or share link) or post ID. Either `url` or `id` is required. - `id` (`getPost.query.id`; string, optional) — Post ID (e.g. `1x144ok`) or `t3_` fullname. Alternative to `url`. - `comment` (`getPost.query.comment`; string, optional) — Comment ID to focus on. When set, returns its parent ancestor chain and direct replies. - `context` (`getPost.query.context`; integer, optional) — Number of ancestor context levels to include above the focused comment. - min 0; max 8; default `3` - `max_comments` (`getPost.query.max_comments`; integer, optional) — Maximum comments to return. Set to `0` to return the post alone. - min 0; max 2000; default `200` - `format` (`getPost.query.format`; string, optional) — Response format: `json` (complete post and digest), `md` (Markdown for LLMs), or `graph` (discussion digest only). - one of `"json"`, `"md"`, `"graph"`; default `"json"` ## Code samples ### cURL ```bash curl --request GET \ --url https://api.threadapi.dev/v1/reddit/post \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/post'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/post" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 The post. #### Body (application/json) - `post` (`getPost.response.200.post`; object, optional) - `id` (`getPost.response.200.post.id`; string, optional) - `name` (`getPost.response.200.post.name`; string, optional) - `domain` (`getPost.response.200.post.domain`; string, optional) - `is_self` (`getPost.response.200.post.is_self`; boolean, optional) - `flair` (`getPost.response.200.post.flair`; string, optional) - `spoiler` (`getPost.response.200.post.spoiler`; boolean, optional) - `stickied` (`getPost.response.200.post.stickied`; boolean, optional) - `locked` (`getPost.response.200.post.locked`; boolean, optional) - `removed` (`getPost.response.200.post.removed`; boolean, optional) - `subreddit` (`getPost.response.200.post.subreddit`; string, optional) - `title` (`getPost.response.200.post.title`; string, optional) - `author` (`getPost.response.200.post.author`; string, optional) - `score` (`getPost.response.200.post.score`; integer, optional) - `upvote_ratio` (`getPost.response.200.post.upvote_ratio`; number, optional) - `num_comments` (`getPost.response.200.post.num_comments`; integer, optional) - `url` (`getPost.response.200.post.url`; string, optional) - `permalink` (`getPost.response.200.post.permalink`; string, optional) - `selftext` (`getPost.response.200.post.selftext`; string, optional) - `created_at` (`getPost.response.200.post.created_at`; string, optional) - format `date-time` - `is_video` (`getPost.response.200.post.is_video`; boolean, optional) - `over_18` (`getPost.response.200.post.over_18`; boolean, optional) - `media` (`getPost.response.200.post.media`; array, optional) - `type` (`getPost.response.200.post.media.type`; string, optional) - one of `"image"`, `"video"`, `"gallery"` - `url` (`getPost.response.200.post.media.url`; string, optional) - `width` (`getPost.response.200.post.media.width`; integer, optional) - `height` (`getPost.response.200.post.media.height`; integer, optional) - `caption` (`getPost.response.200.post.media.caption`; string, optional) - `poll` (`getPost.response.200.post.poll`; object, optional) - `total_votes` (`getPost.response.200.post.poll.total_votes`; integer, optional) - `is_closed` (`getPost.response.200.post.poll.is_closed`; boolean, optional) - `options` (`getPost.response.200.post.poll.options`; array, optional) - `id` (`getPost.response.200.post.poll.options.id`; string, optional) - `text` (`getPost.response.200.post.poll.options.text`; string, optional) - `vote_count` (`getPost.response.200.post.poll.options.vote_count`; integer, optional) - `crosspost_of` (`getPost.response.200.post.crosspost_of`; object, optional) - `id` (`getPost.response.200.post.crosspost_of.id`; string, optional) - `subreddit` (`getPost.response.200.post.crosspost_of.subreddit`; string, optional) - `title` (`getPost.response.200.post.crosspost_of.title`; string, optional) - `author` (`getPost.response.200.post.crosspost_of.author`; string, optional) - `permalink` (`getPost.response.200.post.crosspost_of.permalink`; string, optional) - `comments` (`getPost.response.200.post.comments`; array, optional) - `id` (`getPost.response.200.post.comments.id`; string, optional) - `parent_id` (`getPost.response.200.post.comments.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPost.response.200.post.comments.author`; string, optional) - `score` (`getPost.response.200.post.comments.score`; integer, optional) - `body` (`getPost.response.200.post.comments.body`; string, optional) - `created_at` (`getPost.response.200.post.comments.created_at`; string, optional) - format `date-time` - `depth` (`getPost.response.200.post.comments.depth`; integer, optional) - `is_submitter` (`getPost.response.200.post.comments.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPost.response.200.post.comments.controversy`; integer, optional) - `replies` (`getPost.response.200.post.comments.replies`; array, optional) - `id` (`getPost.response.200.post.comments.replies.id`; string, optional) - `parent_id` (`getPost.response.200.post.comments.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPost.response.200.post.comments.replies.author`; string, optional) - `score` (`getPost.response.200.post.comments.replies.score`; integer, optional) - `body` (`getPost.response.200.post.comments.replies.body`; string, optional) - `created_at` (`getPost.response.200.post.comments.replies.created_at`; string, optional) - format `date-time` - `depth` (`getPost.response.200.post.comments.replies.depth`; integer, optional) - `is_submitter` (`getPost.response.200.post.comments.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPost.response.200.post.comments.replies.controversy`; integer, optional) - `replies` (`getPost.response.200.post.comments.replies.replies`; array, optional) - `discussion_graph` (`getPost.response.200.discussion_graph`; object, optional) - `post_id` (`getPost.response.200.discussion_graph.post_id`; string, optional) - `title` (`getPost.response.200.discussion_graph.title`; string, optional) - `author` (`getPost.response.200.discussion_graph.author`; string, optional) - `author_followups` (`getPost.response.200.discussion_graph.author_followups`; array, optional) — The original poster's own comments in the thread. - `id` (`getPost.response.200.discussion_graph.author_followups.id`; string, optional) - `parent_id` (`getPost.response.200.discussion_graph.author_followups.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPost.response.200.discussion_graph.author_followups.author`; string, optional) - `score` (`getPost.response.200.discussion_graph.author_followups.score`; integer, optional) - `body` (`getPost.response.200.discussion_graph.author_followups.body`; string, optional) - `created_at` (`getPost.response.200.discussion_graph.author_followups.created_at`; string, optional) - format `date-time` - `depth` (`getPost.response.200.discussion_graph.author_followups.depth`; integer, optional) - `is_submitter` (`getPost.response.200.discussion_graph.author_followups.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPost.response.200.discussion_graph.author_followups.controversy`; integer, optional) - `replies` (`getPost.response.200.discussion_graph.author_followups.replies`; array, optional) - `id` (`getPost.response.200.discussion_graph.author_followups.replies.id`; string, optional) - `parent_id` (`getPost.response.200.discussion_graph.author_followups.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPost.response.200.discussion_graph.author_followups.replies.author`; string, optional) - `score` (`getPost.response.200.discussion_graph.author_followups.replies.score`; integer, optional) - `body` (`getPost.response.200.discussion_graph.author_followups.replies.body`; string, optional) - `created_at` (`getPost.response.200.discussion_graph.author_followups.replies.created_at`; string, optional) - format `date-time` - `depth` (`getPost.response.200.discussion_graph.author_followups.replies.depth`; integer, optional) - `is_submitter` (`getPost.response.200.discussion_graph.author_followups.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPost.response.200.discussion_graph.author_followups.replies.controversy`; integer, optional) - `replies` (`getPost.response.200.discussion_graph.author_followups.replies.replies`; array, optional) - `most_upvoted` (`getPost.response.200.discussion_graph.most_upvoted`; array, optional) — Highest-score comments excluding OP, AutoModerator and deleted comments. - `id` (`getPost.response.200.discussion_graph.most_upvoted.id`; string, optional) - `parent_id` (`getPost.response.200.discussion_graph.most_upvoted.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPost.response.200.discussion_graph.most_upvoted.author`; string, optional) - `score` (`getPost.response.200.discussion_graph.most_upvoted.score`; integer, optional) - `body` (`getPost.response.200.discussion_graph.most_upvoted.body`; string, optional) - `created_at` (`getPost.response.200.discussion_graph.most_upvoted.created_at`; string, optional) - format `date-time` - `depth` (`getPost.response.200.discussion_graph.most_upvoted.depth`; integer, optional) - `is_submitter` (`getPost.response.200.discussion_graph.most_upvoted.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPost.response.200.discussion_graph.most_upvoted.controversy`; integer, optional) - `replies` (`getPost.response.200.discussion_graph.most_upvoted.replies`; array, optional) - `id` (`getPost.response.200.discussion_graph.most_upvoted.replies.id`; string, optional) - `parent_id` (`getPost.response.200.discussion_graph.most_upvoted.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPost.response.200.discussion_graph.most_upvoted.replies.author`; string, optional) - `score` (`getPost.response.200.discussion_graph.most_upvoted.replies.score`; integer, optional) - `body` (`getPost.response.200.discussion_graph.most_upvoted.replies.body`; string, optional) - `created_at` (`getPost.response.200.discussion_graph.most_upvoted.replies.created_at`; string, optional) - format `date-time` - `depth` (`getPost.response.200.discussion_graph.most_upvoted.replies.depth`; integer, optional) - `is_submitter` (`getPost.response.200.discussion_graph.most_upvoted.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPost.response.200.discussion_graph.most_upvoted.replies.controversy`; integer, optional) - `replies` (`getPost.response.200.discussion_graph.most_upvoted.replies.replies`; array, optional) - `controversial` (`getPost.response.200.discussion_graph.controversial`; array, optional) — Comments with controversiality flag or negative score, excluding OP. - `id` (`getPost.response.200.discussion_graph.controversial.id`; string, optional) - `parent_id` (`getPost.response.200.discussion_graph.controversial.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPost.response.200.discussion_graph.controversial.author`; string, optional) - `score` (`getPost.response.200.discussion_graph.controversial.score`; integer, optional) - `body` (`getPost.response.200.discussion_graph.controversial.body`; string, optional) - `created_at` (`getPost.response.200.discussion_graph.controversial.created_at`; string, optional) - format `date-time` - `depth` (`getPost.response.200.discussion_graph.controversial.depth`; integer, optional) - `is_submitter` (`getPost.response.200.discussion_graph.controversial.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPost.response.200.discussion_graph.controversial.controversy`; integer, optional) - `replies` (`getPost.response.200.discussion_graph.controversial.replies`; array, optional) - `id` (`getPost.response.200.discussion_graph.controversial.replies.id`; string, optional) - `parent_id` (`getPost.response.200.discussion_graph.controversial.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPost.response.200.discussion_graph.controversial.replies.author`; string, optional) - `score` (`getPost.response.200.discussion_graph.controversial.replies.score`; integer, optional) - `body` (`getPost.response.200.discussion_graph.controversial.replies.body`; string, optional) - `created_at` (`getPost.response.200.discussion_graph.controversial.replies.created_at`; string, optional) - format `date-time` - `depth` (`getPost.response.200.discussion_graph.controversial.replies.depth`; integer, optional) - `is_submitter` (`getPost.response.200.discussion_graph.controversial.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPost.response.200.discussion_graph.controversial.replies.controversy`; integer, optional) - `replies` (`getPost.response.200.discussion_graph.controversial.replies.replies`; array, optional) - `total_analyzed` (`getPost.response.200.discussion_graph.total_analyzed`; integer, optional) - `meta` (`getPost.response.200.meta`; object, optional) - `comments_returned` (`getPost.response.200.meta.comments_returned`; integer, optional) — Comments in the response. - `comments_total` (`getPost.response.200.meta.comments_total`; integer, optional) — Reddit's comment count, deleted and hidden comments included. - `has_more` (`getPost.response.200.meta.has_more`; boolean, optional) — A larger max_comments would return more. - `max_comments` (`getPost.response.200.meta.max_comments`; integer, optional) - `credits_used` (`getPost.response.200.meta.credits_used`; integer, optional) - `cache` (`getPost.response.200.meta.cache`; string, optional) - `limited_by_balance` (`getPost.response.200.meta.limited_by_balance`; boolean, optional) - `focus_comment_id` (`getPost.response.200.meta.focus_comment_id`; string, optional) — Comment ID when a comment permalink was requested. ##### Example ```json { "post": { "id": "string", "name": "string", "domain": "string", "is_self": true, "flair": "string", "spoiler": true, "stickied": true, "locked": true, "removed": true, "subreddit": "string", "title": "string", "author": "string", "score": 0, "upvote_ratio": 0, "num_comments": 0, "url": "string", "permalink": "string", "selftext": "string", "created_at": "2019-08-24T14:15:22Z", "is_video": true, "over_18": true, "media": [ { "type": "image", "url": "string", "width": 0, "height": 0, "caption": "string" } ], "poll": { "total_votes": 0, "is_closed": true, "options": [ { "id": "string", "text": "string", "vote_count": 0 } ] }, "crosspost_of": { "id": "string", "subreddit": "string", "title": "string", "author": "string", "permalink": "string" }, "comments": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [] } ] } ] }, "discussion_graph": { "post_id": "string", "title": "string", "author": "string", "author_followups": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [] } ] } ], "most_upvoted": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [] } ] } ], "controversial": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [] } ] } ], "total_analyzed": 0 }, "meta": { "comments_returned": 0, "comments_total": 0, "has_more": true, "max_comments": 0, "credits_used": 0, "cache": "string", "limited_by_balance": true, "focus_comment_id": "string" } } ``` #### Body (text/markdown) ##### Example ```text string ``` ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPost.response.402.error`; object, required) - `code` (`getPost.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getPost.response.402.error.message`; string, required) - `retryable` (`getPost.response.402.error.retryable`; boolean, required) - `retry_after` (`getPost.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 403 Reddit does not show this content to logged-out readers, e.g. a private or quarantined subreddit (`reddit_refused`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPost.response.403.error`; object, required) - `code` (`getPost.response.403.error.code`; string, required) - example `"not_found"` - `message` (`getPost.response.403.error.message`; string, required) - `retryable` (`getPost.response.403.error.retryable`; boolean, required) - `retry_after` (`getPost.response.403.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPost.response.503.error`; object, required) - `code` (`getPost.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getPost.response.503.error.message`; string, required) - `retryable` (`getPost.response.503.error.retryable`; boolean, required) - `retry_after` (`getPost.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Get Duplicate Posts > Retrieves other discussions and crossposts sharing the same external URL across Reddit. Source: https://staging.threadapi.dev/api/Reddit/getPostDuplicates/ · Markdown: https://staging.threadapi.dev/api/Reddit/getPostDuplicates/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/post/duplicates` Retrieves other discussions and crossposts sharing the same external URL across Reddit. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `id` (`getPostDuplicates.query.id`; string, optional) — Reddit post ID (e.g. `1x1ai6v` or `t3_1x1ai6v`). Required if `url` is not provided. - `url` (`getPostDuplicates.query.url`; string, optional) — Reddit post URL. Required if `id` is not provided. - `limit` (`getPostDuplicates.query.limit`; integer, optional) — Number of items per page. - min 1; max 100; default `25` - `after` (`getPostDuplicates.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`getPostDuplicates.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url https://api.threadapi.dev/v1/reddit/post/duplicates \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/post/duplicates'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/post/duplicates" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 Duplicate posts. #### Example ```json { "subreddit": "string", "query": "string", "sort": "string", "count": 0, "items": [ { "id": "string", "name": "string", "domain": "string", "is_self": true, "flair": "string", "spoiler": true, "stickied": true, "locked": true, "removed": true, "subreddit": "string", "title": "string", "author": "string", "score": 0, "upvote_ratio": 0, "num_comments": 0, "url": "string", "permalink": "string", "selftext": "string", "created_at": "2019-08-24T14:15:22Z", "is_video": true, "over_18": true, "media": [ { "type": "image", "url": "string", "width": 0, "height": 0, "caption": "string" } ], "poll": { "total_votes": 0, "is_closed": true, "options": [ { "id": "string", "text": "string", "vote_count": 0 } ] }, "crosspost_of": { "id": "string", "subreddit": "string", "title": "string", "author": "string", "permalink": "string" }, "comments": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [] } ] } ] } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` - `sort` (`getPostDuplicates.response.200.sort`; string, required) - `count` (`getPostDuplicates.response.200.count`; integer, required) - `items` (`getPostDuplicates.response.200.items`; array, required) - `id` (`getPostDuplicates.response.200.items.id`; string, optional) - `name` (`getPostDuplicates.response.200.items.name`; string, optional) - `domain` (`getPostDuplicates.response.200.items.domain`; string, optional) - `is_self` (`getPostDuplicates.response.200.items.is_self`; boolean, optional) - `flair` (`getPostDuplicates.response.200.items.flair`; string, optional) - `spoiler` (`getPostDuplicates.response.200.items.spoiler`; boolean, optional) - `stickied` (`getPostDuplicates.response.200.items.stickied`; boolean, optional) - `locked` (`getPostDuplicates.response.200.items.locked`; boolean, optional) - `removed` (`getPostDuplicates.response.200.items.removed`; boolean, optional) - `subreddit` (`getPostDuplicates.response.200.items.subreddit`; string, optional) - `title` (`getPostDuplicates.response.200.items.title`; string, optional) - `author` (`getPostDuplicates.response.200.items.author`; string, optional) - `score` (`getPostDuplicates.response.200.items.score`; integer, optional) - `upvote_ratio` (`getPostDuplicates.response.200.items.upvote_ratio`; number, optional) - `num_comments` (`getPostDuplicates.response.200.items.num_comments`; integer, optional) - `url` (`getPostDuplicates.response.200.items.url`; string, optional) - `permalink` (`getPostDuplicates.response.200.items.permalink`; string, optional) - `selftext` (`getPostDuplicates.response.200.items.selftext`; string, optional) - `created_at` (`getPostDuplicates.response.200.items.created_at`; string, optional) - format `date-time` - `is_video` (`getPostDuplicates.response.200.items.is_video`; boolean, optional) - `over_18` (`getPostDuplicates.response.200.items.over_18`; boolean, optional) - `media` (`getPostDuplicates.response.200.items.media`; array, optional) - `type` (`getPostDuplicates.response.200.items.media.type`; string, optional) - one of `"image"`, `"video"`, `"gallery"` - `url` (`getPostDuplicates.response.200.items.media.url`; string, optional) - `width` (`getPostDuplicates.response.200.items.media.width`; integer, optional) - `height` (`getPostDuplicates.response.200.items.media.height`; integer, optional) - `caption` (`getPostDuplicates.response.200.items.media.caption`; string, optional) - `poll` (`getPostDuplicates.response.200.items.poll`; object, optional) - `total_votes` (`getPostDuplicates.response.200.items.poll.total_votes`; integer, optional) - `is_closed` (`getPostDuplicates.response.200.items.poll.is_closed`; boolean, optional) - `options` (`getPostDuplicates.response.200.items.poll.options`; array, optional) - `id` (`getPostDuplicates.response.200.items.poll.options.id`; string, optional) - `text` (`getPostDuplicates.response.200.items.poll.options.text`; string, optional) - `vote_count` (`getPostDuplicates.response.200.items.poll.options.vote_count`; integer, optional) - `crosspost_of` (`getPostDuplicates.response.200.items.crosspost_of`; object, optional) - `id` (`getPostDuplicates.response.200.items.crosspost_of.id`; string, optional) - `subreddit` (`getPostDuplicates.response.200.items.crosspost_of.subreddit`; string, optional) - `title` (`getPostDuplicates.response.200.items.crosspost_of.title`; string, optional) - `author` (`getPostDuplicates.response.200.items.crosspost_of.author`; string, optional) - `permalink` (`getPostDuplicates.response.200.items.crosspost_of.permalink`; string, optional) - `comments` (`getPostDuplicates.response.200.items.comments`; array, optional) - `id` (`getPostDuplicates.response.200.items.comments.id`; string, optional) - `parent_id` (`getPostDuplicates.response.200.items.comments.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPostDuplicates.response.200.items.comments.author`; string, optional) - `score` (`getPostDuplicates.response.200.items.comments.score`; integer, optional) - `body` (`getPostDuplicates.response.200.items.comments.body`; string, optional) - `created_at` (`getPostDuplicates.response.200.items.comments.created_at`; string, optional) - format `date-time` - `depth` (`getPostDuplicates.response.200.items.comments.depth`; integer, optional) - `is_submitter` (`getPostDuplicates.response.200.items.comments.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPostDuplicates.response.200.items.comments.controversy`; integer, optional) - `replies` (`getPostDuplicates.response.200.items.comments.replies`; array, optional) - `id` (`getPostDuplicates.response.200.items.comments.replies.id`; string, optional) - `parent_id` (`getPostDuplicates.response.200.items.comments.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPostDuplicates.response.200.items.comments.replies.author`; string, optional) - `score` (`getPostDuplicates.response.200.items.comments.replies.score`; integer, optional) - `body` (`getPostDuplicates.response.200.items.comments.replies.body`; string, optional) - `created_at` (`getPostDuplicates.response.200.items.comments.replies.created_at`; string, optional) - format `date-time` - `depth` (`getPostDuplicates.response.200.items.comments.replies.depth`; integer, optional) - `is_submitter` (`getPostDuplicates.response.200.items.comments.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPostDuplicates.response.200.items.comments.replies.controversy`; integer, optional) - `replies` (`getPostDuplicates.response.200.items.comments.replies.replies`; array, optional) - `filtered_nsfw` (`getPostDuplicates.response.200.filtered_nsfw`; integer, required) - `subreddit` (`getPostDuplicates.response.200.subreddit`; string | null, optional) - `query` (`getPostDuplicates.response.200.query`; string | null, optional) - `after` (`getPostDuplicates.response.200.after`; string | null, optional) - `degraded` (`getPostDuplicates.response.200.degraded`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPostDuplicates.response.402.error`; object, required) - `code` (`getPostDuplicates.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getPostDuplicates.response.402.error.message`; string, required) - `retryable` (`getPostDuplicates.response.402.error.retryable`; boolean, required) - `retry_after` (`getPostDuplicates.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 403 Reddit does not show this content to logged-out readers, e.g. a private or quarantined subreddit (`reddit_refused`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPostDuplicates.response.403.error`; object, required) - `code` (`getPostDuplicates.response.403.error.code`; string, required) - example `"not_found"` - `message` (`getPostDuplicates.response.403.error.message`; string, required) - `retryable` (`getPostDuplicates.response.403.error.retryable`; boolean, required) - `retry_after` (`getPostDuplicates.response.403.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPostDuplicates.response.503.error`; object, required) - `code` (`getPostDuplicates.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getPostDuplicates.response.503.error.message`; string, required) - `retryable` (`getPostDuplicates.response.503.error.retryable`; boolean, required) - `retry_after` (`getPostDuplicates.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Look Up Posts by ID (Official) > Batch look up up to 100 posts via Reddit's official `/by_id/` endpoint. Source: https://staging.threadapi.dev/api/Reddit/getPostsByID/ · Markdown: https://staging.threadapi.dev/api/Reddit/getPostsByID/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/by_id` Batch look up up to 100 posts via Reddit's official `/by_id/` endpoint. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `ids` (`getPostsByID.query.ids`; string, required) — Comma-separated list of up to 100 Reddit post IDs or URLs. ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/by_id?ids=t3_1x1ai6v%2Ct3_1wuyulc' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/by_id?ids=t3_1x1ai6v%2Ct3_1wuyulc'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/by_id?ids=t3_1x1ai6v%2Ct3_1wuyulc" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 The requested posts. #### Example ```json { "items": [ { "kind": "post", "post": { "id": "string", "name": "string", "domain": "string", "is_self": true, "flair": "string", "spoiler": true, "stickied": true, "locked": true, "removed": true, "subreddit": "string", "title": "string", "author": "string", "score": 0, "upvote_ratio": 0, "num_comments": 0, "url": "string", "permalink": "string", "selftext": "string", "created_at": "2019-08-24T14:15:22Z", "is_video": true, "over_18": true, "media": [ { "type": "image", "url": "string", "width": 0, "height": 0, "caption": "string" } ], "poll": { "total_votes": 0, "is_closed": true, "options": [ { "id": "string", "text": "string", "vote_count": 0 } ] }, "crosspost_of": { "id": "string", "subreddit": "string", "title": "string", "author": "string", "permalink": "string" }, "comments": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "replies": [] } ] } ] }, "comment": { "id": "string", "name": "string", "post_id": "string", "post_title": "string", "subreddit": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "permalink": "string", "parent_id": "string", "is_submitter": true, "controversiality": 0 } } ], "missing": [ "string" ] } ``` - `items` (`getPostsByID.response.200.items`; array, required) - `kind` (`getPostsByID.response.200.items.kind`; string, required) - one of `"post"`, `"comment"` - `post` (`getPostsByID.response.200.items.post`; object, optional) - `id` (`getPostsByID.response.200.items.post.id`; string, optional) - `name` (`getPostsByID.response.200.items.post.name`; string, optional) - `domain` (`getPostsByID.response.200.items.post.domain`; string, optional) - `is_self` (`getPostsByID.response.200.items.post.is_self`; boolean, optional) - `flair` (`getPostsByID.response.200.items.post.flair`; string, optional) - `spoiler` (`getPostsByID.response.200.items.post.spoiler`; boolean, optional) - `stickied` (`getPostsByID.response.200.items.post.stickied`; boolean, optional) - `locked` (`getPostsByID.response.200.items.post.locked`; boolean, optional) - `removed` (`getPostsByID.response.200.items.post.removed`; boolean, optional) - `subreddit` (`getPostsByID.response.200.items.post.subreddit`; string, optional) - `title` (`getPostsByID.response.200.items.post.title`; string, optional) - `author` (`getPostsByID.response.200.items.post.author`; string, optional) - `score` (`getPostsByID.response.200.items.post.score`; integer, optional) - `upvote_ratio` (`getPostsByID.response.200.items.post.upvote_ratio`; number, optional) - `num_comments` (`getPostsByID.response.200.items.post.num_comments`; integer, optional) - `url` (`getPostsByID.response.200.items.post.url`; string, optional) - `permalink` (`getPostsByID.response.200.items.post.permalink`; string, optional) - `selftext` (`getPostsByID.response.200.items.post.selftext`; string, optional) - `created_at` (`getPostsByID.response.200.items.post.created_at`; string, optional) - format `date-time` - `is_video` (`getPostsByID.response.200.items.post.is_video`; boolean, optional) - `over_18` (`getPostsByID.response.200.items.post.over_18`; boolean, optional) - `media` (`getPostsByID.response.200.items.post.media`; array, optional) - `type` (`getPostsByID.response.200.items.post.media.type`; string, optional) - one of `"image"`, `"video"`, `"gallery"` - `url` (`getPostsByID.response.200.items.post.media.url`; string, optional) - `width` (`getPostsByID.response.200.items.post.media.width`; integer, optional) - `height` (`getPostsByID.response.200.items.post.media.height`; integer, optional) - `caption` (`getPostsByID.response.200.items.post.media.caption`; string, optional) - `poll` (`getPostsByID.response.200.items.post.poll`; object, optional) - `total_votes` (`getPostsByID.response.200.items.post.poll.total_votes`; integer, optional) - `is_closed` (`getPostsByID.response.200.items.post.poll.is_closed`; boolean, optional) - `options` (`getPostsByID.response.200.items.post.poll.options`; array, optional) - `id` (`getPostsByID.response.200.items.post.poll.options.id`; string, optional) - `text` (`getPostsByID.response.200.items.post.poll.options.text`; string, optional) - `vote_count` (`getPostsByID.response.200.items.post.poll.options.vote_count`; integer, optional) - `crosspost_of` (`getPostsByID.response.200.items.post.crosspost_of`; object, optional) - `id` (`getPostsByID.response.200.items.post.crosspost_of.id`; string, optional) - `subreddit` (`getPostsByID.response.200.items.post.crosspost_of.subreddit`; string, optional) - `title` (`getPostsByID.response.200.items.post.crosspost_of.title`; string, optional) - `author` (`getPostsByID.response.200.items.post.crosspost_of.author`; string, optional) - `permalink` (`getPostsByID.response.200.items.post.crosspost_of.permalink`; string, optional) - `comments` (`getPostsByID.response.200.items.post.comments`; array, optional) - `id` (`getPostsByID.response.200.items.post.comments.id`; string, optional) - `parent_id` (`getPostsByID.response.200.items.post.comments.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPostsByID.response.200.items.post.comments.author`; string, optional) - `score` (`getPostsByID.response.200.items.post.comments.score`; integer, optional) - `body` (`getPostsByID.response.200.items.post.comments.body`; string, optional) - `created_at` (`getPostsByID.response.200.items.post.comments.created_at`; string, optional) - format `date-time` - `depth` (`getPostsByID.response.200.items.post.comments.depth`; integer, optional) - `is_submitter` (`getPostsByID.response.200.items.post.comments.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPostsByID.response.200.items.post.comments.controversy`; integer, optional) - `replies` (`getPostsByID.response.200.items.post.comments.replies`; array, optional) - `id` (`getPostsByID.response.200.items.post.comments.replies.id`; string, optional) - `parent_id` (`getPostsByID.response.200.items.post.comments.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPostsByID.response.200.items.post.comments.replies.author`; string, optional) - `score` (`getPostsByID.response.200.items.post.comments.replies.score`; integer, optional) - `body` (`getPostsByID.response.200.items.post.comments.replies.body`; string, optional) - `created_at` (`getPostsByID.response.200.items.post.comments.replies.created_at`; string, optional) - format `date-time` - `depth` (`getPostsByID.response.200.items.post.comments.replies.depth`; integer, optional) - `is_submitter` (`getPostsByID.response.200.items.post.comments.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPostsByID.response.200.items.post.comments.replies.controversy`; integer, optional) - `replies` (`getPostsByID.response.200.items.post.comments.replies.replies`; array, optional) - `comment` (`getPostsByID.response.200.items.comment`; object, optional) - `id` (`getPostsByID.response.200.items.comment.id`; string, optional) - `name` (`getPostsByID.response.200.items.comment.name`; string, optional) - `post_id` (`getPostsByID.response.200.items.comment.post_id`; string, optional) - `post_title` (`getPostsByID.response.200.items.comment.post_title`; string, optional) - `subreddit` (`getPostsByID.response.200.items.comment.subreddit`; string, optional) - `author` (`getPostsByID.response.200.items.comment.author`; string, optional) - `score` (`getPostsByID.response.200.items.comment.score`; integer, optional) - `body` (`getPostsByID.response.200.items.comment.body`; string, optional) - `created_at` (`getPostsByID.response.200.items.comment.created_at`; string, optional) - format `date-time` - `permalink` (`getPostsByID.response.200.items.comment.permalink`; string, optional) - `parent_id` (`getPostsByID.response.200.items.comment.parent_id`; string, optional) - `is_submitter` (`getPostsByID.response.200.items.comment.is_submitter`; boolean, optional) - `controversiality` (`getPostsByID.response.200.items.comment.controversiality`; integer, optional) - `missing` (`getPostsByID.response.200.missing`; array, required) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPostsByID.response.402.error`; object, required) - `code` (`getPostsByID.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getPostsByID.response.402.error.message`; string, required) - `retryable` (`getPostsByID.response.402.error.retryable`; boolean, required) - `retry_after` (`getPostsByID.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPostsByID.response.503.error`; object, required) - `code` (`getPostsByID.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getPostsByID.response.503.error.message`; string, required) - `retryable` (`getPostsByID.response.503.error.retryable`; boolean, required) - `retry_after` (`getPostsByID.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Look Up Posts by ID (Alias) > Alias for `/v1/reddit/by_id`. Looks up to 100 posts by fullname (`t3_`), bare ID, or URL. Source: https://staging.threadapi.dev/api/Reddit/getPostsByIDAlias/ · Markdown: https://staging.threadapi.dev/api/Reddit/getPostsByIDAlias/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/posts/by_id` Alias for `/v1/reddit/by_id`. Looks up to 100 posts by fullname (`t3_`), bare ID, or URL. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `ids` (`getPostsByIDAlias.query.ids`; string, required) — Comma-separated list of up to 100 Reddit post IDs or URLs. ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/posts/by_id?ids=t3_1x1ai6v%2Ct3_1wuyulc' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/posts/by_id?ids=t3_1x1ai6v%2Ct3_1wuyulc'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/posts/by_id?ids=t3_1x1ai6v%2Ct3_1wuyulc" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 The requested posts. #### Example ```json { "items": [ { "kind": "post", "post": { "id": "string", "name": "string", "domain": "string", "is_self": true, "flair": "string", "spoiler": true, "stickied": true, "locked": true, "removed": true, "subreddit": "string", "title": "string", "author": "string", "score": 0, "upvote_ratio": 0, "num_comments": 0, "url": "string", "permalink": "string", "selftext": "string", "created_at": "2019-08-24T14:15:22Z", "is_video": true, "over_18": true, "media": [ { "type": "image", "url": "string", "width": 0, "height": 0, "caption": "string" } ], "poll": { "total_votes": 0, "is_closed": true, "options": [ { "id": "string", "text": "string", "vote_count": 0 } ] }, "crosspost_of": { "id": "string", "subreddit": "string", "title": "string", "author": "string", "permalink": "string" }, "comments": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "replies": [] } ] } ] }, "comment": { "id": "string", "name": "string", "post_id": "string", "post_title": "string", "subreddit": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "permalink": "string", "parent_id": "string", "is_submitter": true, "controversiality": 0 } } ], "missing": [ "string" ] } ``` - `items` (`getPostsByIDAlias.response.200.items`; array, required) - `kind` (`getPostsByIDAlias.response.200.items.kind`; string, required) - one of `"post"`, `"comment"` - `post` (`getPostsByIDAlias.response.200.items.post`; object, optional) - `id` (`getPostsByIDAlias.response.200.items.post.id`; string, optional) - `name` (`getPostsByIDAlias.response.200.items.post.name`; string, optional) - `domain` (`getPostsByIDAlias.response.200.items.post.domain`; string, optional) - `is_self` (`getPostsByIDAlias.response.200.items.post.is_self`; boolean, optional) - `flair` (`getPostsByIDAlias.response.200.items.post.flair`; string, optional) - `spoiler` (`getPostsByIDAlias.response.200.items.post.spoiler`; boolean, optional) - `stickied` (`getPostsByIDAlias.response.200.items.post.stickied`; boolean, optional) - `locked` (`getPostsByIDAlias.response.200.items.post.locked`; boolean, optional) - `removed` (`getPostsByIDAlias.response.200.items.post.removed`; boolean, optional) - `subreddit` (`getPostsByIDAlias.response.200.items.post.subreddit`; string, optional) - `title` (`getPostsByIDAlias.response.200.items.post.title`; string, optional) - `author` (`getPostsByIDAlias.response.200.items.post.author`; string, optional) - `score` (`getPostsByIDAlias.response.200.items.post.score`; integer, optional) - `upvote_ratio` (`getPostsByIDAlias.response.200.items.post.upvote_ratio`; number, optional) - `num_comments` (`getPostsByIDAlias.response.200.items.post.num_comments`; integer, optional) - `url` (`getPostsByIDAlias.response.200.items.post.url`; string, optional) - `permalink` (`getPostsByIDAlias.response.200.items.post.permalink`; string, optional) - `selftext` (`getPostsByIDAlias.response.200.items.post.selftext`; string, optional) - `created_at` (`getPostsByIDAlias.response.200.items.post.created_at`; string, optional) - format `date-time` - `is_video` (`getPostsByIDAlias.response.200.items.post.is_video`; boolean, optional) - `over_18` (`getPostsByIDAlias.response.200.items.post.over_18`; boolean, optional) - `media` (`getPostsByIDAlias.response.200.items.post.media`; array, optional) - `type` (`getPostsByIDAlias.response.200.items.post.media.type`; string, optional) - one of `"image"`, `"video"`, `"gallery"` - `url` (`getPostsByIDAlias.response.200.items.post.media.url`; string, optional) - `width` (`getPostsByIDAlias.response.200.items.post.media.width`; integer, optional) - `height` (`getPostsByIDAlias.response.200.items.post.media.height`; integer, optional) - `caption` (`getPostsByIDAlias.response.200.items.post.media.caption`; string, optional) - `poll` (`getPostsByIDAlias.response.200.items.post.poll`; object, optional) - `total_votes` (`getPostsByIDAlias.response.200.items.post.poll.total_votes`; integer, optional) - `is_closed` (`getPostsByIDAlias.response.200.items.post.poll.is_closed`; boolean, optional) - `options` (`getPostsByIDAlias.response.200.items.post.poll.options`; array, optional) - `id` (`getPostsByIDAlias.response.200.items.post.poll.options.id`; string, optional) - `text` (`getPostsByIDAlias.response.200.items.post.poll.options.text`; string, optional) - `vote_count` (`getPostsByIDAlias.response.200.items.post.poll.options.vote_count`; integer, optional) - `crosspost_of` (`getPostsByIDAlias.response.200.items.post.crosspost_of`; object, optional) - `id` (`getPostsByIDAlias.response.200.items.post.crosspost_of.id`; string, optional) - `subreddit` (`getPostsByIDAlias.response.200.items.post.crosspost_of.subreddit`; string, optional) - `title` (`getPostsByIDAlias.response.200.items.post.crosspost_of.title`; string, optional) - `author` (`getPostsByIDAlias.response.200.items.post.crosspost_of.author`; string, optional) - `permalink` (`getPostsByIDAlias.response.200.items.post.crosspost_of.permalink`; string, optional) - `comments` (`getPostsByIDAlias.response.200.items.post.comments`; array, optional) - `id` (`getPostsByIDAlias.response.200.items.post.comments.id`; string, optional) - `parent_id` (`getPostsByIDAlias.response.200.items.post.comments.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPostsByIDAlias.response.200.items.post.comments.author`; string, optional) - `score` (`getPostsByIDAlias.response.200.items.post.comments.score`; integer, optional) - `body` (`getPostsByIDAlias.response.200.items.post.comments.body`; string, optional) - `created_at` (`getPostsByIDAlias.response.200.items.post.comments.created_at`; string, optional) - format `date-time` - `depth` (`getPostsByIDAlias.response.200.items.post.comments.depth`; integer, optional) - `is_submitter` (`getPostsByIDAlias.response.200.items.post.comments.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPostsByIDAlias.response.200.items.post.comments.controversy`; integer, optional) - `replies` (`getPostsByIDAlias.response.200.items.post.comments.replies`; array, optional) - `id` (`getPostsByIDAlias.response.200.items.post.comments.replies.id`; string, optional) - `parent_id` (`getPostsByIDAlias.response.200.items.post.comments.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getPostsByIDAlias.response.200.items.post.comments.replies.author`; string, optional) - `score` (`getPostsByIDAlias.response.200.items.post.comments.replies.score`; integer, optional) - `body` (`getPostsByIDAlias.response.200.items.post.comments.replies.body`; string, optional) - `created_at` (`getPostsByIDAlias.response.200.items.post.comments.replies.created_at`; string, optional) - format `date-time` - `depth` (`getPostsByIDAlias.response.200.items.post.comments.replies.depth`; integer, optional) - `is_submitter` (`getPostsByIDAlias.response.200.items.post.comments.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getPostsByIDAlias.response.200.items.post.comments.replies.controversy`; integer, optional) - `replies` (`getPostsByIDAlias.response.200.items.post.comments.replies.replies`; array, optional) - `comment` (`getPostsByIDAlias.response.200.items.comment`; object, optional) - `id` (`getPostsByIDAlias.response.200.items.comment.id`; string, optional) - `name` (`getPostsByIDAlias.response.200.items.comment.name`; string, optional) - `post_id` (`getPostsByIDAlias.response.200.items.comment.post_id`; string, optional) - `post_title` (`getPostsByIDAlias.response.200.items.comment.post_title`; string, optional) - `subreddit` (`getPostsByIDAlias.response.200.items.comment.subreddit`; string, optional) - `author` (`getPostsByIDAlias.response.200.items.comment.author`; string, optional) - `score` (`getPostsByIDAlias.response.200.items.comment.score`; integer, optional) - `body` (`getPostsByIDAlias.response.200.items.comment.body`; string, optional) - `created_at` (`getPostsByIDAlias.response.200.items.comment.created_at`; string, optional) - format `date-time` - `permalink` (`getPostsByIDAlias.response.200.items.comment.permalink`; string, optional) - `parent_id` (`getPostsByIDAlias.response.200.items.comment.parent_id`; string, optional) - `is_submitter` (`getPostsByIDAlias.response.200.items.comment.is_submitter`; boolean, optional) - `controversiality` (`getPostsByIDAlias.response.200.items.comment.controversiality`; integer, optional) - `missing` (`getPostsByIDAlias.response.200.missing`; array, required) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPostsByIDAlias.response.402.error`; object, required) - `code` (`getPostsByIDAlias.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getPostsByIDAlias.response.402.error.message`; string, required) - `retryable` (`getPostsByIDAlias.response.402.error.retryable`; boolean, required) - `retry_after` (`getPostsByIDAlias.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getPostsByIDAlias.response.503.error`; object, required) - `code` (`getPostsByIDAlias.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getPostsByIDAlias.response.503.error.message`; string, required) - `retryable` (`getPostsByIDAlias.response.503.error.retryable`; boolean, required) - `retry_after` (`getPostsByIDAlias.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Get Subreddit Details > Retrieves subreddit metadata, community settings, subscriber stats, and moderation rules. Source: https://staging.threadapi.dev/api/Reddit/getSubredditAbout/ · Markdown: https://staging.threadapi.dev/api/Reddit/getSubredditAbout/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/subreddit/about` Retrieves subreddit metadata, community settings, subscriber stats, and moderation rules. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `sub` (`getSubredditAbout.query.sub`; string, required) — Subreddit name, with or without `r/`. ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/subreddit/about?sub=golang' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/subreddit/about?sub=golang'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/subreddit/about?sub=golang" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 Subreddit metadata and rules. #### Example ```json { "name": "string", "title": "string", "public_description": "string", "description": "string", "subscribers": 0, "created_at": "2019-08-24T14:15:22Z", "over_18": true, "type": "string", "url": "string", "icon": "string", "rules": [ { "kind": "string", "short_name": "string", "description": "string", "violation_reason": "string", "priority": 0, "created_at": "2019-08-24T14:15:22Z" } ] } ``` - `name` (`getSubredditAbout.response.200.name`; string, optional) - `title` (`getSubredditAbout.response.200.title`; string, optional) - `public_description` (`getSubredditAbout.response.200.public_description`; string, optional) - `description` (`getSubredditAbout.response.200.description`; string, optional) - `subscribers` (`getSubredditAbout.response.200.subscribers`; integer, optional) - `created_at` (`getSubredditAbout.response.200.created_at`; string, optional) - format `date-time` - `over_18` (`getSubredditAbout.response.200.over_18`; boolean, optional) - `type` (`getSubredditAbout.response.200.type`; string, optional) - `url` (`getSubredditAbout.response.200.url`; string, optional) - `icon` (`getSubredditAbout.response.200.icon`; string, optional) - `rules` (`getSubredditAbout.response.200.rules`; array, optional) - `kind` (`getSubredditAbout.response.200.rules.kind`; string, optional) - `short_name` (`getSubredditAbout.response.200.rules.short_name`; string, optional) - `description` (`getSubredditAbout.response.200.rules.description`; string, optional) - `violation_reason` (`getSubredditAbout.response.200.rules.violation_reason`; string, optional) - `priority` (`getSubredditAbout.response.200.rules.priority`; integer, optional) - `created_at` (`getSubredditAbout.response.200.rules.created_at`; string, optional) - format `date-time` ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getSubredditAbout.response.402.error`; object, required) - `code` (`getSubredditAbout.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getSubredditAbout.response.402.error.message`; string, required) - `retryable` (`getSubredditAbout.response.402.error.retryable`; boolean, required) - `retry_after` (`getSubredditAbout.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 403 Reddit does not show this content to logged-out readers, e.g. a private or quarantined subreddit (`reddit_refused`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getSubredditAbout.response.403.error`; object, required) - `code` (`getSubredditAbout.response.403.error.code`; string, required) - example `"not_found"` - `message` (`getSubredditAbout.response.403.error.message`; string, required) - `retryable` (`getSubredditAbout.response.403.error.retryable`; boolean, required) - `retry_after` (`getSubredditAbout.response.403.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getSubredditAbout.response.503.error`; object, required) - `code` (`getSubredditAbout.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getSubredditAbout.response.503.error.message`; string, required) - `retryable` (`getSubredditAbout.response.503.error.retryable`; boolean, required) - `retry_after` (`getSubredditAbout.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # List Subreddit Comments > Fetches recent comments posted across an entire subreddit in reverse chronological order. Source: https://staging.threadapi.dev/api/Reddit/getSubredditComments/ · Markdown: https://staging.threadapi.dev/api/Reddit/getSubredditComments/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/subreddit/comments` Fetches recent comments posted across an entire subreddit in reverse chronological order. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `sub` (`getSubredditComments.query.sub`; string, required) — Subreddit name (e.g. `golang` or `r/golang`). - `limit` (`getSubredditComments.query.limit`; integer, optional) — Number of items per page. - min 1; max 100; default `25` - `after` (`getSubredditComments.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`getSubredditComments.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/subreddit/comments?sub=golang' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/subreddit/comments?sub=golang'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/subreddit/comments?sub=golang" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 Subreddit comments. #### Example ```json { "subreddit": "string", "query": "string", "sort": "string", "count": 0, "items": [ { "id": "string", "name": "string", "post_id": "string", "post_title": "string", "subreddit": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "permalink": "string", "parent_id": "string", "is_submitter": true, "controversiality": 0 } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` - `sort` (`getSubredditComments.response.200.sort`; string, required) - `count` (`getSubredditComments.response.200.count`; integer, required) - `items` (`getSubredditComments.response.200.items`; array, required) - `id` (`getSubredditComments.response.200.items.id`; string, optional) - `name` (`getSubredditComments.response.200.items.name`; string, optional) - `post_id` (`getSubredditComments.response.200.items.post_id`; string, optional) - `post_title` (`getSubredditComments.response.200.items.post_title`; string, optional) - `subreddit` (`getSubredditComments.response.200.items.subreddit`; string, optional) - `author` (`getSubredditComments.response.200.items.author`; string, optional) - `score` (`getSubredditComments.response.200.items.score`; integer, optional) - `body` (`getSubredditComments.response.200.items.body`; string, optional) - `created_at` (`getSubredditComments.response.200.items.created_at`; string, optional) - format `date-time` - `permalink` (`getSubredditComments.response.200.items.permalink`; string, optional) - `parent_id` (`getSubredditComments.response.200.items.parent_id`; string, optional) - `is_submitter` (`getSubredditComments.response.200.items.is_submitter`; boolean, optional) - `controversiality` (`getSubredditComments.response.200.items.controversiality`; integer, optional) - `filtered_nsfw` (`getSubredditComments.response.200.filtered_nsfw`; integer, required) - `subreddit` (`getSubredditComments.response.200.subreddit`; string | null, optional) - `query` (`getSubredditComments.response.200.query`; string | null, optional) - `after` (`getSubredditComments.response.200.after`; string | null, optional) - `degraded` (`getSubredditComments.response.200.degraded`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getSubredditComments.response.402.error`; object, required) - `code` (`getSubredditComments.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getSubredditComments.response.402.error.message`; string, required) - `retryable` (`getSubredditComments.response.402.error.retryable`; boolean, required) - `retry_after` (`getSubredditComments.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 403 Insufficient permissions or scope for this endpoint #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getSubredditComments.response.503.error`; object, required) - `code` (`getSubredditComments.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getSubredditComments.response.503.error.message`; string, required) - `retryable` (`getSubredditComments.response.503.error.retryable`; boolean, required) - `retry_after` (`getSubredditComments.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # List Subreddits > Lists popular or newly created subreddits across Reddit. Source: https://staging.threadapi.dev/api/Reddit/getSubreddits/ · Markdown: https://staging.threadapi.dev/api/Reddit/getSubreddits/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/subreddits` Lists popular or newly created subreddits across Reddit. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `sort` (`getSubreddits.query.sort`; string, optional) — Subreddit listing sort. - one of `"popular"`, `"new"`; default `"popular"` - `limit` (`getSubreddits.query.limit`; integer, optional) — Number of items per page. - min 1; max 100; default `25` - `after` (`getSubreddits.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`getSubreddits.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url https://api.threadapi.dev/v1/reddit/subreddits \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/subreddits'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/subreddits" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 Subreddit listing. #### Example ```json { "query": "string", "sort": "string", "count": 0, "items": [ { "name": "string", "title": "string", "public_description": "string", "description": "string", "subscribers": 0, "created_at": "2019-08-24T14:15:22Z", "over_18": true, "type": "string", "url": "string", "icon": "string", "rules": [ { "kind": "string", "short_name": "string", "description": "string", "violation_reason": "string", "priority": 0, "created_at": "2019-08-24T14:15:22Z" } ] } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` - `sort` (`getSubreddits.response.200.sort`; string, required) - `count` (`getSubreddits.response.200.count`; integer, required) - `items` (`getSubreddits.response.200.items`; array, required) - `name` (`getSubreddits.response.200.items.name`; string, optional) - `title` (`getSubreddits.response.200.items.title`; string, optional) - `public_description` (`getSubreddits.response.200.items.public_description`; string, optional) - `description` (`getSubreddits.response.200.items.description`; string, optional) - `subscribers` (`getSubreddits.response.200.items.subscribers`; integer, optional) - `created_at` (`getSubreddits.response.200.items.created_at`; string, optional) - format `date-time` - `over_18` (`getSubreddits.response.200.items.over_18`; boolean, optional) - `type` (`getSubreddits.response.200.items.type`; string, optional) - `url` (`getSubreddits.response.200.items.url`; string, optional) - `icon` (`getSubreddits.response.200.items.icon`; string, optional) - `rules` (`getSubreddits.response.200.items.rules`; array, optional) - `kind` (`getSubreddits.response.200.items.rules.kind`; string, optional) - `short_name` (`getSubreddits.response.200.items.rules.short_name`; string, optional) - `description` (`getSubreddits.response.200.items.rules.description`; string, optional) - `violation_reason` (`getSubreddits.response.200.items.rules.violation_reason`; string, optional) - `priority` (`getSubreddits.response.200.items.rules.priority`; integer, optional) - `created_at` (`getSubreddits.response.200.items.rules.created_at`; string, optional) - format `date-time` - `filtered_nsfw` (`getSubreddits.response.200.filtered_nsfw`; integer, required) - `query` (`getSubreddits.response.200.query`; string | null, optional) - `after` (`getSubreddits.response.200.after`; string | null, optional) - `degraded` (`getSubreddits.response.200.degraded`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getSubreddits.response.402.error`; object, required) - `code` (`getSubreddits.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getSubreddits.response.402.error.message`; string, required) - `retryable` (`getSubreddits.response.402.error.retryable`; boolean, required) - `retry_after` (`getSubreddits.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getSubreddits.response.503.error`; object, required) - `code` (`getSubreddits.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getSubreddits.response.503.error.message`; string, required) - `retryable` (`getSubreddits.response.503.error.retryable`; boolean, required) - `retry_after` (`getSubreddits.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Look Up Posts by ID > Batch look up up to 100 Reddit posts by fullname (`t3_`), bare ID, or URL in requested order. Any missing IDs are recorded under `missing_ids`. Source: https://staging.threadapi.dev/api/Reddit/getThings/ · Markdown: https://staging.threadapi.dev/api/Reddit/getThings/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/things` Batch look up up to 100 Reddit posts by fullname (`t3_`), bare ID, or URL in requested order. Any missing IDs are recorded under `missing_ids`. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `ids` (`getThings.query.ids`; string, required) — Comma-separated list of up to 100 Reddit post IDs or URLs. ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/things?ids=t3_1x1ai6v%2Ct3_1xagllz' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/things?ids=t3_1x1ai6v%2Ct3_1xagllz'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/things?ids=t3_1x1ai6v%2Ct3_1xagllz" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 The requested items. #### Example ```json { "items": [ { "kind": "post", "post": { "id": "string", "name": "string", "domain": "string", "is_self": true, "flair": "string", "spoiler": true, "stickied": true, "locked": true, "removed": true, "subreddit": "string", "title": "string", "author": "string", "score": 0, "upvote_ratio": 0, "num_comments": 0, "url": "string", "permalink": "string", "selftext": "string", "created_at": "2019-08-24T14:15:22Z", "is_video": true, "over_18": true, "media": [ { "type": "image", "url": "string", "width": 0, "height": 0, "caption": "string" } ], "poll": { "total_votes": 0, "is_closed": true, "options": [ { "id": "string", "text": "string", "vote_count": 0 } ] }, "crosspost_of": { "id": "string", "subreddit": "string", "title": "string", "author": "string", "permalink": "string" }, "comments": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "replies": [] } ] } ] }, "comment": { "id": "string", "name": "string", "post_id": "string", "post_title": "string", "subreddit": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "permalink": "string", "parent_id": "string", "is_submitter": true, "controversiality": 0 } } ], "missing": [ "string" ] } ``` - `items` (`getThings.response.200.items`; array, required) - `kind` (`getThings.response.200.items.kind`; string, required) - one of `"post"`, `"comment"` - `post` (`getThings.response.200.items.post`; object, optional) - `id` (`getThings.response.200.items.post.id`; string, optional) - `name` (`getThings.response.200.items.post.name`; string, optional) - `domain` (`getThings.response.200.items.post.domain`; string, optional) - `is_self` (`getThings.response.200.items.post.is_self`; boolean, optional) - `flair` (`getThings.response.200.items.post.flair`; string, optional) - `spoiler` (`getThings.response.200.items.post.spoiler`; boolean, optional) - `stickied` (`getThings.response.200.items.post.stickied`; boolean, optional) - `locked` (`getThings.response.200.items.post.locked`; boolean, optional) - `removed` (`getThings.response.200.items.post.removed`; boolean, optional) - `subreddit` (`getThings.response.200.items.post.subreddit`; string, optional) - `title` (`getThings.response.200.items.post.title`; string, optional) - `author` (`getThings.response.200.items.post.author`; string, optional) - `score` (`getThings.response.200.items.post.score`; integer, optional) - `upvote_ratio` (`getThings.response.200.items.post.upvote_ratio`; number, optional) - `num_comments` (`getThings.response.200.items.post.num_comments`; integer, optional) - `url` (`getThings.response.200.items.post.url`; string, optional) - `permalink` (`getThings.response.200.items.post.permalink`; string, optional) - `selftext` (`getThings.response.200.items.post.selftext`; string, optional) - `created_at` (`getThings.response.200.items.post.created_at`; string, optional) - format `date-time` - `is_video` (`getThings.response.200.items.post.is_video`; boolean, optional) - `over_18` (`getThings.response.200.items.post.over_18`; boolean, optional) - `media` (`getThings.response.200.items.post.media`; array, optional) - `type` (`getThings.response.200.items.post.media.type`; string, optional) - one of `"image"`, `"video"`, `"gallery"` - `url` (`getThings.response.200.items.post.media.url`; string, optional) - `width` (`getThings.response.200.items.post.media.width`; integer, optional) - `height` (`getThings.response.200.items.post.media.height`; integer, optional) - `caption` (`getThings.response.200.items.post.media.caption`; string, optional) - `poll` (`getThings.response.200.items.post.poll`; object, optional) - `total_votes` (`getThings.response.200.items.post.poll.total_votes`; integer, optional) - `is_closed` (`getThings.response.200.items.post.poll.is_closed`; boolean, optional) - `options` (`getThings.response.200.items.post.poll.options`; array, optional) - `id` (`getThings.response.200.items.post.poll.options.id`; string, optional) - `text` (`getThings.response.200.items.post.poll.options.text`; string, optional) - `vote_count` (`getThings.response.200.items.post.poll.options.vote_count`; integer, optional) - `crosspost_of` (`getThings.response.200.items.post.crosspost_of`; object, optional) - `id` (`getThings.response.200.items.post.crosspost_of.id`; string, optional) - `subreddit` (`getThings.response.200.items.post.crosspost_of.subreddit`; string, optional) - `title` (`getThings.response.200.items.post.crosspost_of.title`; string, optional) - `author` (`getThings.response.200.items.post.crosspost_of.author`; string, optional) - `permalink` (`getThings.response.200.items.post.crosspost_of.permalink`; string, optional) - `comments` (`getThings.response.200.items.post.comments`; array, optional) - `id` (`getThings.response.200.items.post.comments.id`; string, optional) - `parent_id` (`getThings.response.200.items.post.comments.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getThings.response.200.items.post.comments.author`; string, optional) - `score` (`getThings.response.200.items.post.comments.score`; integer, optional) - `body` (`getThings.response.200.items.post.comments.body`; string, optional) - `created_at` (`getThings.response.200.items.post.comments.created_at`; string, optional) - format `date-time` - `depth` (`getThings.response.200.items.post.comments.depth`; integer, optional) - `is_submitter` (`getThings.response.200.items.post.comments.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getThings.response.200.items.post.comments.controversy`; integer, optional) - `replies` (`getThings.response.200.items.post.comments.replies`; array, optional) - `id` (`getThings.response.200.items.post.comments.replies.id`; string, optional) - `parent_id` (`getThings.response.200.items.post.comments.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getThings.response.200.items.post.comments.replies.author`; string, optional) - `score` (`getThings.response.200.items.post.comments.replies.score`; integer, optional) - `body` (`getThings.response.200.items.post.comments.replies.body`; string, optional) - `created_at` (`getThings.response.200.items.post.comments.replies.created_at`; string, optional) - format `date-time` - `depth` (`getThings.response.200.items.post.comments.replies.depth`; integer, optional) - `is_submitter` (`getThings.response.200.items.post.comments.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getThings.response.200.items.post.comments.replies.controversy`; integer, optional) - `replies` (`getThings.response.200.items.post.comments.replies.replies`; array, optional) - `comment` (`getThings.response.200.items.comment`; object, optional) - `id` (`getThings.response.200.items.comment.id`; string, optional) - `name` (`getThings.response.200.items.comment.name`; string, optional) - `post_id` (`getThings.response.200.items.comment.post_id`; string, optional) - `post_title` (`getThings.response.200.items.comment.post_title`; string, optional) - `subreddit` (`getThings.response.200.items.comment.subreddit`; string, optional) - `author` (`getThings.response.200.items.comment.author`; string, optional) - `score` (`getThings.response.200.items.comment.score`; integer, optional) - `body` (`getThings.response.200.items.comment.body`; string, optional) - `created_at` (`getThings.response.200.items.comment.created_at`; string, optional) - format `date-time` - `permalink` (`getThings.response.200.items.comment.permalink`; string, optional) - `parent_id` (`getThings.response.200.items.comment.parent_id`; string, optional) - `is_submitter` (`getThings.response.200.items.comment.is_submitter`; boolean, optional) - `controversiality` (`getThings.response.200.items.comment.controversiality`; integer, optional) - `missing` (`getThings.response.200.missing`; array, required) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getThings.response.402.error`; object, required) - `code` (`getThings.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getThings.response.402.error.message`; string, required) - `retryable` (`getThings.response.402.error.retryable`; boolean, required) - `retry_after` (`getThings.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getThings.response.503.error`; object, required) - `code` (`getThings.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getThings.response.503.error.message`; string, required) - `retryable` (`getThings.response.503.error.retryable`; boolean, required) - `retry_after` (`getThings.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Get User Profile > Retrieves a Reddit user's public profile, karma breakdown, creation timestamp, and account flags. Source: https://staging.threadapi.dev/api/Reddit/getUser/ · Markdown: https://staging.threadapi.dev/api/Reddit/getUser/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/user` Retrieves a Reddit user's public profile, karma breakdown, creation timestamp, and account flags. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `name` (`getUser.query.name`; string, required) — Reddit username (e.g. `spez`, with or without `u/`). ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/user?name=spez' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/user?name=spez'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/user?name=spez" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 User profile. #### Example ```json { "name": "string", "created_at": "2019-08-24T14:15:22Z", "link_karma": 0, "comment_karma": 0, "total_karma": 0, "is_employee": true, "is_mod": true, "has_verified_email": true, "icon": "string", "suspended": true } ``` - `name` (`getUser.response.200.name`; string, optional) - `created_at` (`getUser.response.200.created_at`; string, optional) - format `date-time` - `link_karma` (`getUser.response.200.link_karma`; integer, optional) - `comment_karma` (`getUser.response.200.comment_karma`; integer, optional) - `total_karma` (`getUser.response.200.total_karma`; integer, optional) - `is_employee` (`getUser.response.200.is_employee`; boolean, optional) - `is_mod` (`getUser.response.200.is_mod`; boolean, optional) - `has_verified_email` (`getUser.response.200.has_verified_email`; boolean, optional) - `icon` (`getUser.response.200.icon`; string, optional) - `suspended` (`getUser.response.200.suspended`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getUser.response.402.error`; object, required) - `code` (`getUser.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getUser.response.402.error.message`; string, required) - `retryable` (`getUser.response.402.error.retryable`; boolean, required) - `retry_after` (`getUser.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getUser.response.503.error`; object, required) - `code` (`getUser.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getUser.response.503.error.message`; string, required) - `retryable` (`getUser.response.503.error.retryable`; boolean, required) - `retry_after` (`getUser.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # List User Comments > Lists comments posted by a specific Reddit user across all communities. Source: https://staging.threadapi.dev/api/Reddit/getUserComments/ · Markdown: https://staging.threadapi.dev/api/Reddit/getUserComments/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/user/comments` Lists comments posted by a specific Reddit user across all communities. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `name` (`getUserComments.query.name`; string, required) — Reddit username. - `sort` (`getUserComments.query.sort`; string, optional) - one of `"new"`, `"hot"`, `"top"`, `"controversial"`; default `"new"` - `t` (`getUserComments.query.t`; string, optional) — Time window when sorting by `top` or `controversial`. - one of `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`, `"all"` - `limit` (`getUserComments.query.limit`; integer, optional) — Number of items per page. - min 1; max 100; default `25` - `after` (`getUserComments.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`getUserComments.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/user/comments?name=spez' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/user/comments?name=spez'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/user/comments?name=spez" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 Submitted comments. #### Example ```json { "subreddit": "string", "query": "string", "sort": "string", "count": 0, "items": [ { "id": "string", "name": "string", "post_id": "string", "post_title": "string", "subreddit": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "permalink": "string", "parent_id": "string", "is_submitter": true, "controversiality": 0 } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` - `sort` (`getUserComments.response.200.sort`; string, required) - `count` (`getUserComments.response.200.count`; integer, required) - `items` (`getUserComments.response.200.items`; array, required) - `id` (`getUserComments.response.200.items.id`; string, optional) - `name` (`getUserComments.response.200.items.name`; string, optional) - `post_id` (`getUserComments.response.200.items.post_id`; string, optional) - `post_title` (`getUserComments.response.200.items.post_title`; string, optional) - `subreddit` (`getUserComments.response.200.items.subreddit`; string, optional) - `author` (`getUserComments.response.200.items.author`; string, optional) - `score` (`getUserComments.response.200.items.score`; integer, optional) - `body` (`getUserComments.response.200.items.body`; string, optional) - `created_at` (`getUserComments.response.200.items.created_at`; string, optional) - format `date-time` - `permalink` (`getUserComments.response.200.items.permalink`; string, optional) - `parent_id` (`getUserComments.response.200.items.parent_id`; string, optional) - `is_submitter` (`getUserComments.response.200.items.is_submitter`; boolean, optional) - `controversiality` (`getUserComments.response.200.items.controversiality`; integer, optional) - `filtered_nsfw` (`getUserComments.response.200.filtered_nsfw`; integer, required) - `subreddit` (`getUserComments.response.200.subreddit`; string | null, optional) - `query` (`getUserComments.response.200.query`; string | null, optional) - `after` (`getUserComments.response.200.after`; string | null, optional) - `degraded` (`getUserComments.response.200.degraded`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getUserComments.response.402.error`; object, required) - `code` (`getUserComments.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getUserComments.response.402.error.message`; string, required) - `retryable` (`getUserComments.response.402.error.retryable`; boolean, required) - `retry_after` (`getUserComments.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getUserComments.response.503.error`; object, required) - `code` (`getUserComments.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getUserComments.response.503.error.message`; string, required) - `retryable` (`getUserComments.response.503.error.retryable`; boolean, required) - `retry_after` (`getUserComments.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # List User Posts > Lists submissions posted by a specific Reddit user across all communities. Source: https://staging.threadapi.dev/api/Reddit/getUserPosts/ · Markdown: https://staging.threadapi.dev/api/Reddit/getUserPosts/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/user/posts` Lists submissions posted by a specific Reddit user across all communities. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `name` (`getUserPosts.query.name`; string, required) — Reddit username. - `sort` (`getUserPosts.query.sort`; string, optional) - one of `"new"`, `"hot"`, `"top"`, `"controversial"`; default `"new"` - `t` (`getUserPosts.query.t`; string, optional) — Time window when sorting by `top` or `controversial`. - one of `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`, `"all"` - `limit` (`getUserPosts.query.limit`; integer, optional) — Number of items per page. - min 1; max 100; default `25` - `after` (`getUserPosts.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`getUserPosts.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/user/posts?name=spez' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/user/posts?name=spez'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/user/posts?name=spez" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 Submitted posts. #### Example ```json { "subreddit": "string", "query": "string", "sort": "string", "count": 0, "items": [ { "id": "string", "name": "string", "domain": "string", "is_self": true, "flair": "string", "spoiler": true, "stickied": true, "locked": true, "removed": true, "subreddit": "string", "title": "string", "author": "string", "score": 0, "upvote_ratio": 0, "num_comments": 0, "url": "string", "permalink": "string", "selftext": "string", "created_at": "2019-08-24T14:15:22Z", "is_video": true, "over_18": true, "media": [ { "type": "image", "url": "string", "width": 0, "height": 0, "caption": "string" } ], "poll": { "total_votes": 0, "is_closed": true, "options": [ { "id": "string", "text": "string", "vote_count": 0 } ] }, "crosspost_of": { "id": "string", "subreddit": "string", "title": "string", "author": "string", "permalink": "string" }, "comments": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [] } ] } ] } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` - `sort` (`getUserPosts.response.200.sort`; string, required) - `count` (`getUserPosts.response.200.count`; integer, required) - `items` (`getUserPosts.response.200.items`; array, required) - `id` (`getUserPosts.response.200.items.id`; string, optional) - `name` (`getUserPosts.response.200.items.name`; string, optional) - `domain` (`getUserPosts.response.200.items.domain`; string, optional) - `is_self` (`getUserPosts.response.200.items.is_self`; boolean, optional) - `flair` (`getUserPosts.response.200.items.flair`; string, optional) - `spoiler` (`getUserPosts.response.200.items.spoiler`; boolean, optional) - `stickied` (`getUserPosts.response.200.items.stickied`; boolean, optional) - `locked` (`getUserPosts.response.200.items.locked`; boolean, optional) - `removed` (`getUserPosts.response.200.items.removed`; boolean, optional) - `subreddit` (`getUserPosts.response.200.items.subreddit`; string, optional) - `title` (`getUserPosts.response.200.items.title`; string, optional) - `author` (`getUserPosts.response.200.items.author`; string, optional) - `score` (`getUserPosts.response.200.items.score`; integer, optional) - `upvote_ratio` (`getUserPosts.response.200.items.upvote_ratio`; number, optional) - `num_comments` (`getUserPosts.response.200.items.num_comments`; integer, optional) - `url` (`getUserPosts.response.200.items.url`; string, optional) - `permalink` (`getUserPosts.response.200.items.permalink`; string, optional) - `selftext` (`getUserPosts.response.200.items.selftext`; string, optional) - `created_at` (`getUserPosts.response.200.items.created_at`; string, optional) - format `date-time` - `is_video` (`getUserPosts.response.200.items.is_video`; boolean, optional) - `over_18` (`getUserPosts.response.200.items.over_18`; boolean, optional) - `media` (`getUserPosts.response.200.items.media`; array, optional) - `type` (`getUserPosts.response.200.items.media.type`; string, optional) - one of `"image"`, `"video"`, `"gallery"` - `url` (`getUserPosts.response.200.items.media.url`; string, optional) - `width` (`getUserPosts.response.200.items.media.width`; integer, optional) - `height` (`getUserPosts.response.200.items.media.height`; integer, optional) - `caption` (`getUserPosts.response.200.items.media.caption`; string, optional) - `poll` (`getUserPosts.response.200.items.poll`; object, optional) - `total_votes` (`getUserPosts.response.200.items.poll.total_votes`; integer, optional) - `is_closed` (`getUserPosts.response.200.items.poll.is_closed`; boolean, optional) - `options` (`getUserPosts.response.200.items.poll.options`; array, optional) - `id` (`getUserPosts.response.200.items.poll.options.id`; string, optional) - `text` (`getUserPosts.response.200.items.poll.options.text`; string, optional) - `vote_count` (`getUserPosts.response.200.items.poll.options.vote_count`; integer, optional) - `crosspost_of` (`getUserPosts.response.200.items.crosspost_of`; object, optional) - `id` (`getUserPosts.response.200.items.crosspost_of.id`; string, optional) - `subreddit` (`getUserPosts.response.200.items.crosspost_of.subreddit`; string, optional) - `title` (`getUserPosts.response.200.items.crosspost_of.title`; string, optional) - `author` (`getUserPosts.response.200.items.crosspost_of.author`; string, optional) - `permalink` (`getUserPosts.response.200.items.crosspost_of.permalink`; string, optional) - `comments` (`getUserPosts.response.200.items.comments`; array, optional) - `id` (`getUserPosts.response.200.items.comments.id`; string, optional) - `parent_id` (`getUserPosts.response.200.items.comments.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getUserPosts.response.200.items.comments.author`; string, optional) - `score` (`getUserPosts.response.200.items.comments.score`; integer, optional) - `body` (`getUserPosts.response.200.items.comments.body`; string, optional) - `created_at` (`getUserPosts.response.200.items.comments.created_at`; string, optional) - format `date-time` - `depth` (`getUserPosts.response.200.items.comments.depth`; integer, optional) - `is_submitter` (`getUserPosts.response.200.items.comments.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getUserPosts.response.200.items.comments.controversy`; integer, optional) - `replies` (`getUserPosts.response.200.items.comments.replies`; array, optional) - `id` (`getUserPosts.response.200.items.comments.replies.id`; string, optional) - `parent_id` (`getUserPosts.response.200.items.comments.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`getUserPosts.response.200.items.comments.replies.author`; string, optional) - `score` (`getUserPosts.response.200.items.comments.replies.score`; integer, optional) - `body` (`getUserPosts.response.200.items.comments.replies.body`; string, optional) - `created_at` (`getUserPosts.response.200.items.comments.replies.created_at`; string, optional) - format `date-time` - `depth` (`getUserPosts.response.200.items.comments.replies.depth`; integer, optional) - `is_submitter` (`getUserPosts.response.200.items.comments.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`getUserPosts.response.200.items.comments.replies.controversy`; integer, optional) - `replies` (`getUserPosts.response.200.items.comments.replies.replies`; array, optional) - `filtered_nsfw` (`getUserPosts.response.200.filtered_nsfw`; integer, required) - `subreddit` (`getUserPosts.response.200.subreddit`; string | null, optional) - `query` (`getUserPosts.response.200.query`; string | null, optional) - `after` (`getUserPosts.response.200.after`; string | null, optional) - `degraded` (`getUserPosts.response.200.degraded`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getUserPosts.response.402.error`; object, required) - `code` (`getUserPosts.response.402.error.code`; string, required) - example `"not_found"` - `message` (`getUserPosts.response.402.error.message`; string, required) - `retryable` (`getUserPosts.response.402.error.retryable`; boolean, required) - `retry_after` (`getUserPosts.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`getUserPosts.response.503.error`; object, required) - `code` (`getUserPosts.response.503.error.code`; string, required) - example `"not_found"` - `message` (`getUserPosts.response.503.error.message`; string, required) - `retryable` (`getUserPosts.response.503.error.retryable`; boolean, required) - `retry_after` (`getUserPosts.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # List Subreddit Posts > Lists posts from a subreddit sorted by community filters (`hot`, `new`, `top`, `rising`, `controversial`). Returns up to 100 posts per page. Source: https://staging.threadapi.dev/api/Reddit/listSubreddit/ · Markdown: https://staging.threadapi.dev/api/Reddit/listSubreddit/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/subreddit` Lists posts from a subreddit sorted by community filters (`hot`, `new`, `top`, `rising`, `controversial`). Returns up to 100 posts per page. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `sub` (`listSubreddit.query.sub`; string, required) — Subreddit name, with or without `r/`. - `sort` (`listSubreddit.query.sort`; string, optional) - one of `"hot"`, `"new"`, `"top"`, `"rising"`, `"controversial"`; default `"hot"` - `t` (`listSubreddit.query.t`; string, optional) — Time window when sorting by `top` or `controversial`. - one of `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`, `"all"` - `limit` (`listSubreddit.query.limit`; integer, optional) — Number of items per page. - min 1; max 100; default `25` - `after` (`listSubreddit.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`listSubreddit.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/subreddit?sub=golang' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/subreddit?sub=golang'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/subreddit?sub=golang" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 The posts. #### Example ```json { "subreddit": "string", "query": "string", "sort": "string", "count": 0, "items": [ { "id": "string", "name": "string", "domain": "string", "is_self": true, "flair": "string", "spoiler": true, "stickied": true, "locked": true, "removed": true, "subreddit": "string", "title": "string", "author": "string", "score": 0, "upvote_ratio": 0, "num_comments": 0, "url": "string", "permalink": "string", "selftext": "string", "created_at": "2019-08-24T14:15:22Z", "is_video": true, "over_18": true, "media": [ { "type": "image", "url": "string", "width": 0, "height": 0, "caption": "string" } ], "poll": { "total_votes": 0, "is_closed": true, "options": [ { "id": "string", "text": "string", "vote_count": 0 } ] }, "crosspost_of": { "id": "string", "subreddit": "string", "title": "string", "author": "string", "permalink": "string" }, "comments": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [] } ] } ] } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` - `sort` (`listSubreddit.response.200.sort`; string, required) - `count` (`listSubreddit.response.200.count`; integer, required) - `items` (`listSubreddit.response.200.items`; array, required) - `id` (`listSubreddit.response.200.items.id`; string, optional) - `name` (`listSubreddit.response.200.items.name`; string, optional) - `domain` (`listSubreddit.response.200.items.domain`; string, optional) - `is_self` (`listSubreddit.response.200.items.is_self`; boolean, optional) - `flair` (`listSubreddit.response.200.items.flair`; string, optional) - `spoiler` (`listSubreddit.response.200.items.spoiler`; boolean, optional) - `stickied` (`listSubreddit.response.200.items.stickied`; boolean, optional) - `locked` (`listSubreddit.response.200.items.locked`; boolean, optional) - `removed` (`listSubreddit.response.200.items.removed`; boolean, optional) - `subreddit` (`listSubreddit.response.200.items.subreddit`; string, optional) - `title` (`listSubreddit.response.200.items.title`; string, optional) - `author` (`listSubreddit.response.200.items.author`; string, optional) - `score` (`listSubreddit.response.200.items.score`; integer, optional) - `upvote_ratio` (`listSubreddit.response.200.items.upvote_ratio`; number, optional) - `num_comments` (`listSubreddit.response.200.items.num_comments`; integer, optional) - `url` (`listSubreddit.response.200.items.url`; string, optional) - `permalink` (`listSubreddit.response.200.items.permalink`; string, optional) - `selftext` (`listSubreddit.response.200.items.selftext`; string, optional) - `created_at` (`listSubreddit.response.200.items.created_at`; string, optional) - format `date-time` - `is_video` (`listSubreddit.response.200.items.is_video`; boolean, optional) - `over_18` (`listSubreddit.response.200.items.over_18`; boolean, optional) - `media` (`listSubreddit.response.200.items.media`; array, optional) - `type` (`listSubreddit.response.200.items.media.type`; string, optional) - one of `"image"`, `"video"`, `"gallery"` - `url` (`listSubreddit.response.200.items.media.url`; string, optional) - `width` (`listSubreddit.response.200.items.media.width`; integer, optional) - `height` (`listSubreddit.response.200.items.media.height`; integer, optional) - `caption` (`listSubreddit.response.200.items.media.caption`; string, optional) - `poll` (`listSubreddit.response.200.items.poll`; object, optional) - `total_votes` (`listSubreddit.response.200.items.poll.total_votes`; integer, optional) - `is_closed` (`listSubreddit.response.200.items.poll.is_closed`; boolean, optional) - `options` (`listSubreddit.response.200.items.poll.options`; array, optional) - `id` (`listSubreddit.response.200.items.poll.options.id`; string, optional) - `text` (`listSubreddit.response.200.items.poll.options.text`; string, optional) - `vote_count` (`listSubreddit.response.200.items.poll.options.vote_count`; integer, optional) - `crosspost_of` (`listSubreddit.response.200.items.crosspost_of`; object, optional) - `id` (`listSubreddit.response.200.items.crosspost_of.id`; string, optional) - `subreddit` (`listSubreddit.response.200.items.crosspost_of.subreddit`; string, optional) - `title` (`listSubreddit.response.200.items.crosspost_of.title`; string, optional) - `author` (`listSubreddit.response.200.items.crosspost_of.author`; string, optional) - `permalink` (`listSubreddit.response.200.items.crosspost_of.permalink`; string, optional) - `comments` (`listSubreddit.response.200.items.comments`; array, optional) - `id` (`listSubreddit.response.200.items.comments.id`; string, optional) - `parent_id` (`listSubreddit.response.200.items.comments.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`listSubreddit.response.200.items.comments.author`; string, optional) - `score` (`listSubreddit.response.200.items.comments.score`; integer, optional) - `body` (`listSubreddit.response.200.items.comments.body`; string, optional) - `created_at` (`listSubreddit.response.200.items.comments.created_at`; string, optional) - format `date-time` - `depth` (`listSubreddit.response.200.items.comments.depth`; integer, optional) - `is_submitter` (`listSubreddit.response.200.items.comments.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`listSubreddit.response.200.items.comments.controversy`; integer, optional) - `replies` (`listSubreddit.response.200.items.comments.replies`; array, optional) - `id` (`listSubreddit.response.200.items.comments.replies.id`; string, optional) - `parent_id` (`listSubreddit.response.200.items.comments.replies.parent_id`; string, optional) — t3_ for a top-level comment, t1_ for a reply. - `author` (`listSubreddit.response.200.items.comments.replies.author`; string, optional) - `score` (`listSubreddit.response.200.items.comments.replies.score`; integer, optional) - `body` (`listSubreddit.response.200.items.comments.replies.body`; string, optional) - `created_at` (`listSubreddit.response.200.items.comments.replies.created_at`; string, optional) - format `date-time` - `depth` (`listSubreddit.response.200.items.comments.replies.depth`; integer, optional) - `is_submitter` (`listSubreddit.response.200.items.comments.replies.is_submitter`; boolean, optional) — Written by the original poster. - `controversy` (`listSubreddit.response.200.items.comments.replies.controversy`; integer, optional) - `replies` (`listSubreddit.response.200.items.comments.replies.replies`; array, optional) - `filtered_nsfw` (`listSubreddit.response.200.filtered_nsfw`; integer, required) - `subreddit` (`listSubreddit.response.200.subreddit`; string | null, optional) - `query` (`listSubreddit.response.200.query`; string | null, optional) - `after` (`listSubreddit.response.200.after`; string | null, optional) - `degraded` (`listSubreddit.response.200.degraded`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`listSubreddit.response.402.error`; object, required) - `code` (`listSubreddit.response.402.error.code`; string, required) - example `"not_found"` - `message` (`listSubreddit.response.402.error.message`; string, required) - `retryable` (`listSubreddit.response.402.error.retryable`; boolean, required) - `retry_after` (`listSubreddit.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 403 Reddit does not show this content to logged-out readers, e.g. a private or quarantined subreddit (`reddit_refused`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`listSubreddit.response.403.error`; object, required) - `code` (`listSubreddit.response.403.error.code`; string, required) - example `"not_found"` - `message` (`listSubreddit.response.403.error.message`; string, required) - `retryable` (`listSubreddit.response.403.error.retryable`; boolean, required) - `retry_after` (`listSubreddit.response.403.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`listSubreddit.response.503.error`; object, required) - `code` (`listSubreddit.response.503.error.code`; string, required) - example `"not_found"` - `message` (`listSubreddit.response.503.error.message`; string, required) - `retryable` (`listSubreddit.response.503.error.retryable`; boolean, required) - `retry_after` (`listSubreddit.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Search Reddit Posts > Searches Reddit posts, subreddits, or users matching a query string globally or within a specified subreddit. Source: https://staging.threadapi.dev/api/Reddit/search/ · Markdown: https://staging.threadapi.dev/api/Reddit/search/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/search` Searches Reddit posts, subreddits, or users matching a query string globally or within a specified subreddit. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `q` (`search.query.q`; string, required) — Search query, 1 to 256 characters. - maxLength 256 - `type` (`search.query.type`; string, optional) — Content type to search: post, subreddit, or user. - one of `"post"`, `"subreddit"`, `"user"`; default `"post"` - `sub` (`search.query.sub`; string, optional) — Only search this subreddit. - `sort` (`search.query.sort`; string, optional) - one of `"relevance"`, `"new"`, `"top"`, `"comments"`; default `"relevance"` - `t` (`search.query.t`; string, optional) — Time window when sorting by `top` or `controversial`. - one of `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`, `"all"` - `limit` (`search.query.limit`; integer, optional) — Number of items per page. - min 1; max 100; default `25` - `after` (`search.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`search.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/search?q=best%20crm%20for%20small%20agency' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/search?q=best%20crm%20for%20small%20agency'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/search?q=best%20crm%20for%20small%20agency" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 The search results. #### Example ```json { "subreddit": "string", "query": "string", "sort": "string", "count": 0, "items": [ { "id": "string", "name": "string", "domain": "string", "is_self": true, "flair": "string", "spoiler": true, "stickied": true, "locked": true, "removed": true, "subreddit": "string", "title": "string", "author": "string", "score": 0, "upvote_ratio": 0, "num_comments": 0, "url": "string", "permalink": "string", "selftext": "string", "created_at": "2019-08-24T14:15:22Z", "is_video": true, "over_18": true, "media": [ { "type": "image", "url": "string", "width": 0, "height": 0, "caption": "string" } ], "poll": { "total_votes": 0, "is_closed": true, "options": [ { "id": "string", "text": "string", "vote_count": 0 } ] }, "crosspost_of": { "id": "string", "subreddit": "string", "title": "string", "author": "string", "permalink": "string" }, "comments": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [ { "id": "string", "parent_id": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "depth": 0, "is_submitter": true, "controversy": 0, "replies": [] } ] } ] } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` One of: - `Listing` - `SubredditListing` - `UserListing` ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`search.response.402.error`; object, required) - `code` (`search.response.402.error.code`; string, required) - example `"not_found"` - `message` (`search.response.402.error.message`; string, required) - `retryable` (`search.response.402.error.retryable`; boolean, required) - `retry_after` (`search.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`search.response.503.error`; object, required) - `code` (`search.response.503.error.code`; string, required) - example `"not_found"` - `message` (`search.response.503.error.message`; string, required) - `retryable` (`search.response.503.error.retryable`; boolean, required) - `retry_after` (`search.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Search Reddit Comments > Searches Reddit comments globally or scoped to a specific subreddit with pagination support. Source: https://staging.threadapi.dev/api/Reddit/searchComments/ · Markdown: https://staging.threadapi.dev/api/Reddit/searchComments/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/search/comments` Searches Reddit comments globally or scoped to a specific subreddit with pagination support. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `q` (`searchComments.query.q`; string, required) — Search query, 1 to 500 characters. - maxLength 500 - `sub` (`searchComments.query.sub`; string, optional) — Only search this subreddit. - `sort` (`searchComments.query.sort`; string, optional) - one of `"relevance"`, `"new"`, `"top"`; default `"relevance"` - `t` (`searchComments.query.t`; string, optional) — Time window when sorting by `top` or `controversial`. - one of `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`, `"all"` - `after` (`searchComments.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`searchComments.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/search/comments?q=postgres%20replica%20lag' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/search/comments?q=postgres%20replica%20lag'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/search/comments?q=postgres%20replica%20lag" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 The comments. #### Example ```json { "subreddit": "string", "query": "string", "sort": "string", "count": 0, "items": [ { "id": "string", "name": "string", "post_id": "string", "post_title": "string", "subreddit": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "permalink": "string", "parent_id": "string", "is_submitter": true, "controversiality": 0 } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` - `sort` (`searchComments.response.200.sort`; string, required) - `count` (`searchComments.response.200.count`; integer, required) - `items` (`searchComments.response.200.items`; array, required) - `id` (`searchComments.response.200.items.id`; string, optional) - `name` (`searchComments.response.200.items.name`; string, optional) - `post_id` (`searchComments.response.200.items.post_id`; string, optional) - `post_title` (`searchComments.response.200.items.post_title`; string, optional) - `subreddit` (`searchComments.response.200.items.subreddit`; string, optional) - `author` (`searchComments.response.200.items.author`; string, optional) - `score` (`searchComments.response.200.items.score`; integer, optional) - `body` (`searchComments.response.200.items.body`; string, optional) - `created_at` (`searchComments.response.200.items.created_at`; string, optional) - format `date-time` - `permalink` (`searchComments.response.200.items.permalink`; string, optional) - `parent_id` (`searchComments.response.200.items.parent_id`; string, optional) - `is_submitter` (`searchComments.response.200.items.is_submitter`; boolean, optional) - `controversiality` (`searchComments.response.200.items.controversiality`; integer, optional) - `filtered_nsfw` (`searchComments.response.200.filtered_nsfw`; integer, required) - `subreddit` (`searchComments.response.200.subreddit`; string | null, optional) - `query` (`searchComments.response.200.query`; string | null, optional) - `after` (`searchComments.response.200.after`; string | null, optional) - `degraded` (`searchComments.response.200.degraded`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`searchComments.response.402.error`; object, required) - `code` (`searchComments.response.402.error.code`; string, required) - example `"not_found"` - `message` (`searchComments.response.402.error.message`; string, required) - `retryable` (`searchComments.response.402.error.retryable`; boolean, required) - `retry_after` (`searchComments.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 403 Reddit does not show this content to logged-out readers, e.g. a private or quarantined subreddit (`reddit_refused`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`searchComments.response.403.error`; object, required) - `code` (`searchComments.response.403.error.code`; string, required) - example `"not_found"` - `message` (`searchComments.response.403.error.message`; string, required) - `retryable` (`searchComments.response.403.error.retryable`; boolean, required) - `retry_after` (`searchComments.response.403.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`searchComments.response.503.error`; object, required) - `code` (`searchComments.response.503.error.code`; string, required) - example `"not_found"` - `message` (`searchComments.response.503.error.message`; string, required) - `retryable` (`searchComments.response.503.error.retryable`; boolean, required) - `retry_after` (`searchComments.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Search Comments (Direct) > High-speed comment search extracting directly from Shreddit DOM markup, bypassing secondary upstream calls. Source: https://staging.threadapi.dev/api/Reddit/searchCommentsDirect/ · Markdown: https://staging.threadapi.dev/api/Reddit/searchCommentsDirect/index.md Path: ThreadAPI API › Reddit `GET /v1/reddit/search/comments/direct` High-speed comment search extracting directly from Shreddit DOM markup, bypassing secondary upstream calls. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Query parameters - `q` (`searchCommentsDirect.query.q`; string, required) — Search query, 1 to 500 characters. - maxLength 500 - `sub` (`searchCommentsDirect.query.sub`; string, optional) — Only search this subreddit. - `sort` (`searchCommentsDirect.query.sort`; string, optional) - one of `"relevance"`, `"new"`, `"top"`; default `"relevance"` - `t` (`searchCommentsDirect.query.t`; string, optional) — Time window when sorting by `top` or `controversial`. - one of `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`, `"all"` - `after` (`searchCommentsDirect.query.after`; string, optional) — Pagination cursor from the previous page's `after` field. - `nsfw` (`searchCommentsDirect.query.nsfw`; boolean, optional) — Include NSFW content (filtered out by default). - default `false` ## Code samples ### cURL ```bash curl --request GET \ --url 'https://api.threadapi.dev/v1/reddit/search/comments/direct?q=postgres%20replica%20lag' \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/v1/reddit/search/comments/direct?q=postgres%20replica%20lag'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/v1/reddit/search/comments/direct?q=postgres%20replica%20lag" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 The comments. #### Example ```json { "subreddit": "string", "query": "string", "sort": "string", "count": 0, "items": [ { "id": "string", "name": "string", "post_id": "string", "post_title": "string", "subreddit": "string", "author": "string", "score": 0, "body": "string", "created_at": "2019-08-24T14:15:22Z", "permalink": "string", "parent_id": "string", "is_submitter": true, "controversiality": 0 } ], "after": "string", "filtered_nsfw": 0, "degraded": true } ``` - `sort` (`searchCommentsDirect.response.200.sort`; string, required) - `count` (`searchCommentsDirect.response.200.count`; integer, required) - `items` (`searchCommentsDirect.response.200.items`; array, required) - `id` (`searchCommentsDirect.response.200.items.id`; string, optional) - `name` (`searchCommentsDirect.response.200.items.name`; string, optional) - `post_id` (`searchCommentsDirect.response.200.items.post_id`; string, optional) - `post_title` (`searchCommentsDirect.response.200.items.post_title`; string, optional) - `subreddit` (`searchCommentsDirect.response.200.items.subreddit`; string, optional) - `author` (`searchCommentsDirect.response.200.items.author`; string, optional) - `score` (`searchCommentsDirect.response.200.items.score`; integer, optional) - `body` (`searchCommentsDirect.response.200.items.body`; string, optional) - `created_at` (`searchCommentsDirect.response.200.items.created_at`; string, optional) - format `date-time` - `permalink` (`searchCommentsDirect.response.200.items.permalink`; string, optional) - `parent_id` (`searchCommentsDirect.response.200.items.parent_id`; string, optional) - `is_submitter` (`searchCommentsDirect.response.200.items.is_submitter`; boolean, optional) - `controversiality` (`searchCommentsDirect.response.200.items.controversiality`; integer, optional) - `filtered_nsfw` (`searchCommentsDirect.response.200.filtered_nsfw`; integer, required) - `subreddit` (`searchCommentsDirect.response.200.subreddit`; string | null, optional) - `query` (`searchCommentsDirect.response.200.query`; string | null, optional) - `after` (`searchCommentsDirect.response.200.after`; string | null, optional) - `degraded` (`searchCommentsDirect.response.200.degraded`; boolean, optional) ### 400 Bad request (invalid parameter or unknown action) #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 402 The account has no credits left (`insufficient_credits`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`searchCommentsDirect.response.402.error`; object, required) - `code` (`searchCommentsDirect.response.402.error.code`; string, required) - example `"not_found"` - `message` (`searchCommentsDirect.response.402.error.message`; string, required) - `retryable` (`searchCommentsDirect.response.402.error.retryable`; boolean, required) - `retry_after` (`searchCommentsDirect.response.402.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 403 Reddit does not show this content to logged-out readers, e.g. a private or quarantined subreddit (`reddit_refused`). #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`searchCommentsDirect.response.403.error`; object, required) - `code` (`searchCommentsDirect.response.403.error.code`; string, required) - example `"not_found"` - `message` (`searchCommentsDirect.response.403.error.message`; string, required) - `retryable` (`searchCommentsDirect.response.403.error.retryable`; boolean, required) - `retry_after` (`searchCommentsDirect.response.403.error.retry_after`; integer, optional) — Seconds to wait before retrying. ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 503 A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed. #### Example ```json { "error": { "code": "not_found", "message": "string", "retryable": true, "retry_after": 0 } } ``` - `error` (`searchCommentsDirect.response.503.error`; object, required) - `code` (`searchCommentsDirect.response.503.error.code`; string, required) - example `"not_found"` - `message` (`searchCommentsDirect.response.503.error.message`; string, required) - `retryable` (`searchCommentsDirect.response.503.error.retryable`; boolean, required) - `retry_after` (`searchCommentsDirect.response.503.error.retry_after`; integer, optional) — Seconds to wait before retrying. # Health check > Returns service health status, version, commit, and build time. Source: https://staging.threadapi.dev/api/System/getHealth/ · Markdown: https://staging.threadapi.dev/api/System/getHealth/index.md Path: ThreadAPI API › System `GET /api/v1/health` Returns service health status, version, commit, and build time. ## Code samples ### cURL ```bash curl --request GET \ --url https://api.threadapi.dev/api/v1/health ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/api/v1/health'; const options = {method: 'GET'}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/api/v1/health" response = requests.get(url) print(response.text) ``` ## Responses ### 200 Service is healthy #### Example ```json { "status": "ok", "service": "core-go", "timestamp": "2026-10-23T12:00:00Z", "version": "dev", "commit": "dev", "build_time": "dev" } ``` - `status` (`getHealth.response.200.status`; string, required) - example `"ok"` - `service` (`getHealth.response.200.service`; string, required) - example `"core-go"` - `timestamp` (`getHealth.response.200.timestamp`; string, required) - format `date-time`; example `"2026-10-23T12:00:00Z"` - `version` (`getHealth.response.200.version`; string, required) - example `"dev"` - `commit` (`getHealth.response.200.commit`; string, required) - example `"dev"` - `build_time` (`getHealth.response.200.build_time`; string, required) - example `"dev"` # Get user credit balance > Returns the authenticated user's ID and current credit balance. Source: https://staging.threadapi.dev/api/User/getUserBalance/ · Markdown: https://staging.threadapi.dev/api/User/getUserBalance/index.md Path: ThreadAPI API › User `GET /api/v1/user/balance` Returns the authenticated user's ID and current credit balance. ## Authentication Requires one of the following: - `bearerAuth`, http, header `Authorization` - `apiKeyAuth`, apiKey, in header, header `x-api-key` ## Code samples ### cURL ```bash curl --request GET \ --url https://api.threadapi.dev/api/v1/user/balance \ --header 'Authorization: Bearer ' ``` ### TypeScript ```typescript const url = 'https://api.threadapi.dev/api/v1/user/balance'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error(err)); ``` ### Python ```python import requests url = "https://api.threadapi.dev/api/v1/user/balance" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.text) ``` ## Responses ### 200 Current user balance #### Example ```json { "user_id": "usr_12345", "credit_balance": 100 } ``` - `user_id` (`getUserBalance.response.200.user_id`; string, required) - example `"usr_12345"` - `credit_balance` (`getUserBalance.response.200.credit_balance`; integer, required) - example `100` ### 401 Missing or invalid API key or OAuth access token #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 404 Requested user or resource not found #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 429 Rate limit or daily request quota exceeded #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` One of: - `ErrorResponse` - `Error` ### 500 Internal server error #### Example ```json { "error": "unauthorized: missing or invalid credentials", "error_code": "insufficient_credits" } ``` - `error` (`getUserBalance.response.500.error`; string, required) — Human-readable error message - example `"unauthorized: missing or invalid credentials"` - `error_code` (`getUserBalance.response.500.error_code`; string, optional) — Machine-readable error code. Known values include: forbidden_scope, rate_limited, daily_quota_exceeded, insufficient_credits, duplicate_transaction. Additional codes may be introduced in future releases. - one of `"forbidden_scope"`, `"rate_limited"`, `"daily_quota_exceeded"`, `"insufficient_credits"`, `"duplicate_transaction"`; example `"insufficient_credits"` # Jobs > Billable job execution engine Source: https://staging.threadapi.dev/api/tags/Jobs/ · Markdown: https://staging.threadapi.dev/api/tags/Jobs/index.md Path: ThreadAPI API Billable job execution engine ## Operations - [Execute job](/api/Jobs/executeJob/) # Monitors > Keyword monitors across Reddit posts and comments with webhook delivery Source: https://staging.threadapi.dev/api/tags/Monitors/ · Markdown: https://staging.threadapi.dev/api/tags/Monitors/index.md Path: ThreadAPI API Keyword monitors across Reddit posts and comments with webhook delivery ## Operations - [List Monitors](/api/Monitors/listMonitors/) - [Create Monitor](/api/Monitors/createMonitor/) - [Get Monitor](/api/Monitors/getMonitor/) - [Delete Monitor](/api/Monitors/deleteMonitor/) - [Update Monitor](/api/Monitors/updateMonitor/) - [Pause Monitor](/api/Monitors/pauseMonitor/) - [Resume Monitor](/api/Monitors/resumeMonitor/) - [Rotate Webhook Secret](/api/Monitors/rotateMonitorSecret/) - [Test Webhook Delivery](/api/Monitors/testMonitor/) - [Get Monitor Matches](/api/Monitors/getMonitorMatches/) # Reddit > Reddit posts, comment trees, subreddit listings and search Source: https://staging.threadapi.dev/api/tags/Reddit/ · Markdown: https://staging.threadapi.dev/api/tags/Reddit/index.md Path: ThreadAPI API Reddit posts, comment trees, subreddit listings and search ## Operations - [Read Post](/api/Reddit/getPost/) - [Get Duplicate Posts](/api/Reddit/getPostDuplicates/) - [Look Up Posts by ID](/api/Reddit/getThings/) - [Look Up Posts by ID (Official)](/api/Reddit/getPostsByID/) - [Look Up Posts by ID (Alias)](/api/Reddit/getPostsByIDAlias/) - [List Subreddit Posts](/api/Reddit/listSubreddit/) - [Get Subreddit Details](/api/Reddit/getSubredditAbout/) - [List Subreddit Comments](/api/Reddit/getSubredditComments/) - [List Subreddits](/api/Reddit/getSubreddits/) - [Get User Profile](/api/Reddit/getUser/) - [List User Posts](/api/Reddit/getUserPosts/) - [List User Comments](/api/Reddit/getUserComments/) - [Search Reddit Posts](/api/Reddit/search/) - [Search Reddit Comments](/api/Reddit/searchComments/) - [Search Comments (Direct)](/api/Reddit/searchCommentsDirect/) # System > System health and operational endpoints Source: https://staging.threadapi.dev/api/tags/System/ · Markdown: https://staging.threadapi.dev/api/tags/System/index.md Path: ThreadAPI API System health and operational endpoints ## Operations - [Health check](/api/System/getHealth/) # User > User balance and account information Source: https://staging.threadapi.dev/api/tags/User/ · Markdown: https://staging.threadapi.dev/api/tags/User/index.md Path: ThreadAPI API User balance and account information ## Operations - [Get user credit balance](/api/User/getUserBalance/) # Quickstart > Read a Reddit post and its comments with one HTTPS request, as JSON or as Markdown for a model. Source: https://staging.threadapi.dev/docs/ · Markdown: https://staging.threadapi.dev/docs/index.md threadapi reads public Reddit for programs and AI agents. One request returns a post with its comment tree, as JSON or as one Markdown document, with a digest of what the thread agrees and argues about. There are also subreddit listings and search, a [remote MCP server](/docs/mcp), and nothing to run on your side: no Reddit app, no OAuth with Reddit, no proxies. > **Base URL** > > All API requests are made against `https://api.threadapi.dev/v1`. 1. ### Get a key Sign in at [threadapi.dev](https://threadapi.dev/auth/login?utm_source=docs) with Google, GitHub or an email code. New accounts get 100 free credits. Create a key under [API keys](https://threadapi.dev/app/api-keys?utm_source=docs); it starts with `tapi_`. 2. ### Read a thread ### cURL ```bash curl "https://api.threadapi.dev/v1/reddit/post?format=md&url=https://www.reddit.com/r/programming/comments/1x144ok/" \ -H "Authorization: Bearer $THREADAPI_API_KEY" ``` ### Python ```python import os, requests r = requests.get( "https://api.threadapi.dev/v1/reddit/post", params={"url": "https://www.reddit.com/r/programming/comments/1x144ok/"}, headers={"Authorization": f"Bearer {os.environ['THREADAPI_API_KEY']}"}, ) r.raise_for_status() thread = r.json() print(thread["post"]["title"], thread["meta"]["comments_returned"]) ``` ### TypeScript ```ts const params = new URLSearchParams({ url: "https://www.reddit.com/r/programming/comments/1x144ok/", format: "md", }); const res = await fetch(`https://api.threadapi.dev/v1/reddit/post?${params}`, { headers: { Authorization: `Bearer ${process.env.THREADAPI_API_KEY}` }, }); console.log(await res.text()); ``` 3. ### Check what it cost Every successful response has an `X-Credits-Used` header. A post with up to 500 comments costs 1 credit; `max_comments` defaults to 200. See [pricing](/docs/pricing). ## Endpoints - [Post](/api/Reddit/getPost/) — A post, its comments nested as on Reddit, and a discussion digest. - [Subreddit](/api/Reddit/listSubreddit/) — Hot, new, top or rising posts in a subreddit. - [Search](/api/Reddit/search/) — Posts matching a query, across Reddit or in one subreddit. - [MCP Server](/docs/mcp) — The same tools for Claude, Cursor, VS Code and Codex. ## For language models - [llms.txt](/llms.txt) and [llms-full.txt](/llms-full.txt) describe the API in plain text. - The OpenAPI spec is at [/openapi.json](/openapi.json). # Agent Sign-up > Let an AI agent create a threadapi account and API key for a user. The user only reads a 6-digit code from their email back to the agent. Source: https://staging.threadapi.dev/docs/agent-signup/ · Markdown: https://staging.threadapi.dev/docs/agent-signup/index.md An AI agent (a skill, an MCP client, a coding assistant) can create a threadapi account for its user and get an API key without a browser. The user confirms by reading a 6-digit code from their email back to the agent. 1. Ask the user for their email address. 2. `POST https://threadapi.dev/api/agent/signup` with the email. threadapi emails a code and returns a `signup_token`. 3. Ask the user for the code. 4. `POST https://threadapi.dev/api/agent/verify` with the token and the code. The response holds the new `api_key`. 5. Store the key where the user's tools can read it, for example as `THREADAPI_API_KEY`, and use it as a [Bearer token](/docs/authentication). > **Keep the key out of the conversation** > > Write the verify response to a file or a variable instead of printing it, and do not echo `api_key` into the chat. --- ## 1. Request a code ```bash curl -s -X POST https://threadapi.dev/api/agent/signup \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com"}' ``` ```json { "status": "code_sent", "signup_token": "eyJwdXJwb3NlIjoi…", "expires_in": 600, "next": "A 6-digit code was emailed to user@example.com. Ask the user for it, then POST …" } ``` The token and the code are valid for 10 minutes. The answer is the same whether or not the email already has an account. ## 2. Verify the code and get the key ```bash curl -s -X POST https://threadapi.dev/api/agent/verify \ -H "Content-Type: application/json" \ -d '{"signup_token": "", "code": "123456"}' \ -o threadapi-signup.json ``` `201 Created`: ```json { "status": "account_created", "api_key": "tapi_…", "credits": 100, "limits": { "requests_per_second": 1, "requests_per_day": 100 }, "next": "Store api_key where the user's tools can read it …", "example_request": "GET https://api.threadapi.dev/v1/reddit/post?url=https://www.reddit.com/r/programming/comments/1x144ok/&format=md", "docs": "https://docs.threadapi.dev", "notes": "The account has 100 free credits; only successful requests use credits. …" } ``` The user can sign in at [threadapi.dev](https://threadapi.dev/auth/login?utm_source=docs) with the same email to see usage, manage keys, and buy credits. ## Existing accounts If the email already has a threadapi account, `/api/agent/verify` answers `409 account_exists` once the code is correct, and no key is created. The user signs in at [threadapi.dev/auth/login](https://threadapi.dev/auth/login?utm_source=docs) and creates a key at [threadapi.dev/app/api-keys](https://threadapi.dev/app/api-keys?utm_source=docs). ## Free credits and limits New accounts get **100 free credits**, once per email address: a `+tag` or a Gmail address with dots counts as the same mailbox. Outside large email providers, only a few new accounts per email domain get them each day. Until the account buys a pack, its keys can make **1 request per second** and **100 requests per day** (UTC); any [credit pack](/docs/pricing) removes the daily limit. ## Errors Errors use the API's standard envelope: ```json { "error": { "code": "invalid_code", "message": "That code is wrong. Ask the user to check the email and try again. …", "retryable": false } } ``` | Status | Code | What to do | | :--- | :--- | :--- | | 400 | `invalid_email` | Ask the user for a valid email address. | | 400 | `disposable_email` | Temporary inboxes are not accepted. Ask for the user's regular address. | | 400 | `undeliverable_email` | The domain cannot receive mail. Check the address with the user. | | 400 | `invalid_request` | Send `signup_token` and a 6-digit `code`. | | 400 | `invalid_signup_token` | The token is wrong or older than 10 minutes. Start over. | | 400 | `invalid_code` | Ask the user to check the code. After 3 wrong codes, start over. | | 400 | `code_expired` | The code is older than 10 minutes. Start over. | | 400 | `too_many_attempts` | 3 wrong codes. Start over. | | 409 | `account_exists` | The user creates a key on the website (see above). | | 429 | `rate_limited` | Too many sign-ups or codes for this network or email. Try again later. | | 502 | `email_failed` | The code email could not be sent. Retry in a minute. | | 503 | `agent_signup_busy` | Agent sign-up is paused for a while. Try again later, or the user signs up at [threadapi.dev](https://threadapi.dev/auth/login?utm_source=docs). | | 503 | `agent_signup_disabled` | Agent sign-up is off. The user can sign up at [threadapi.dev](https://threadapi.dev/auth/login?utm_source=docs). | "Start over" means calling `/api/agent/signup` again, which sends a new code. # Authentication > Send your API key as a Bearer token, and the rate limits that apply to it. Source: https://staging.threadapi.dev/docs/authentication/ · Markdown: https://staging.threadapi.dev/docs/authentication/index.md Every request needs an API key. Send it as a Bearer token: ```http Authorization: Bearer tapi_… ``` or in the `X-Api-Key` header. Keys start with `tapi_`. Create and revoke them under [API keys](https://threadapi.dev/app/api-keys?utm_source=docs); a revoked key stops working within a minute. > **Keep keys on the server** > > Anyone with your key spends your credits. Keep it in an environment variable, not in browser code or a public repository. A missing or unknown key gets `401`: ```json { "error": { "code": "unauthorized", "message": "Invalid or revoked API key.", "retryable": false } } ``` MCP clients can sign in with OAuth instead of a key; see [MCP server](/docs/mcp). ## Rate limits Limits apply per key and rise with the largest pack the account has bought: | Account | Requests | Burst | | :--- | :--- | ---: | | No pack bought yet | 1 per second, 100 per day (UTC) | 20 | | $9 pack | 300 per minute | 50 | | $29 pack | 600 per minute | 100 | | $79 pack | 1,000 per minute | 150 | Over the limit, the API answers `429` with `rate_limited` and a `Retry-After` header in seconds. A free key that has used its 100 requests for the day gets `429 daily_limit_reached` until 00:00 UTC; any pack removes the daily limit. Need more? [Contact us](https://threadapi.dev/contact?utm_source=docs). # Changelog > What changed in the threadapi API, newest first. Source: https://staging.threadapi.dev/docs/changelog/ · Markdown: https://staging.threadapi.dev/docs/changelog/index.md ## October 11, 2026 The first public version of the API. **Reading Reddit** - [Post](/api/Reddit/getPost/): a post with up to 2,000 comments, nested as on Reddit, as JSON or one Markdown document. Reddit's "load more comments" links are followed for you. A comment permalink, or `comment` with `context`, returns that comment, its parents and its replies. - A digest on every post: the original poster's replies, the most upvoted comments and the controversial ones, as Reddit reports them. - [Things](/api/Reddit/getThings/): up to 100 posts and comments by ID or URL in one call. - [Duplicates](/api/Reddit/getPostDuplicates/): where else a post's link was shared, and its crossposts. - Subreddits: [posts](/api/Reddit/listSubreddit/) by hot, new, top, rising or controversial, [newest comments](/api/Reddit/getSubredditComments/), [description and rules](/api/Reddit/getSubredditAbout/), and [popular or new subreddits](/api/Reddit/getSubreddits/). - [Search](/api/Reddit/search/) for posts, subreddits or users, and [comment search](/api/Reddit/searchComments/). - Users: [profile and karma](/api/Reddit/getUser/), [posts](/api/Reddit/getUserPosts/) and [comments](/api/Reddit/getUserComments/). - Every list pages with `after` and leaves out NSFW items unless you pass `nsfw=true`. See [Listings and pages](/docs/listings). **Keyword monitors** - [Monitors](/docs/monitors) watch every new Reddit post and comment for your keywords and send matches to a webhook, Slack or Discord, or keep them for you to poll. 10 credits a day. **Agents** - An [MCP server](/docs/mcp) with seven tools, billed like the routes they call. **Pricing** - One credit is a post with up to 500 comments, or a page of up to 100 items. Credit packs from $9; credits never expire and failed requests are free. See [Pricing](/docs/pricing). # Errors > The error envelope, every error code, and when to retry. Source: https://staging.threadapi.dev/docs/errors/ · Markdown: https://staging.threadapi.dev/docs/errors/index.md Errors share one shape: ```json { "error": { "code": "not_found", "message": "Reddit has no such post or subreddit.", "retryable": false } } ``` Retry only when `retryable` is `true`, after `Retry-After` when the response has one. Failed requests cost nothing. Every response, error or not, carries an `X-Request-Id`; include it when you write to us. | Status | Code | Meaning | Retry | | :--- | :--- | :--- | :--- | | 400 | `invalid_request` | A parameter is missing or invalid; the message says which. | No | | 401 | `unauthorized` | The key is missing, invalid or revoked. | No | | 402 | `insufficient_credits` | The balance is empty. [Add credits](https://threadapi.dev/app/billing?utm_source=docs). | After a top-up | | 402 | `monitor_limit_reached` | You have as many monitors as your plan allows. The error carries `limit` and `used`; a larger credit pack raises the limit. | After deleting a monitor or buying a pack | | 403 | `forbidden` | The key cannot call this endpoint. | No | | 403 | `nsfw_subreddit` | The subreddit is marked NSFW. Pass `nsfw=true` to read it. | With `nsfw=true` | | 403 | `reddit_refused` | Reddit doesn't show this to logged-out readers: a private, quarantined or age-gated subreddit. | No | | 404 | `not_found` | Reddit has no such post or subreddit, or has banned it. | No | | 429 | `rate_limited` | Too many requests for this key. | After `Retry-After` | | 429 | `daily_limit_reached` | A free key used its 100 requests for the UTC day. | At 00:00 UTC, or buy a pack | | 503 | `upstream_busy` | Reddit is refusing requests or our capacity is momentarily used up. | Yes, in a few seconds | | 503 | `upstream_timeout` | Reddit took too long to answer. | Yes | | 503 | `upstream_error` | Fetching from Reddit failed. | Yes | | 503 | `upstream_changed` | Reddit changed its comment search page, and comment search fails until we update. Other endpoints are unaffected. | No | | 503 | `service_unavailable` | Our billing, key check or monitoring service is briefly unavailable. | Yes | A post deleted on Reddit usually still exists as an empty shell: it returns `200` with `[deleted]` as its author and text. # Getting started > Create an account, get an API key and make your first API call. Source: https://staging.threadapi.dev/docs/getting-started/ · Markdown: https://staging.threadapi.dev/docs/getting-started/index.md This example page shows the shape of a product guide. Replace it with your own. ## 1. Create an account Open the console and sign in with your email address. A one-time code arrives by email; no password is needed. ## 2. Create an API key In the console, go to **API Keys** and create a key. Copy it right away: it is shown only once. ## 3. Make your first call Send the key in the `x-api-key` header (or as `Authorization: Bearer `): ```bash curl -X POST https://api.example.com/api/v1/jobs/execute \ -H "x-api-key: $API_KEY" \ -H "Content-Type: application/json" \ -d '{"action": "dispatch_webhook_event"}' ``` Each call deducts credits from your balance. Failed requests are never charged. ## 4. Top up credits Buy credit packs on the **Billing** page of the console. Payments are handled by Stripe. # Listings and pages > The envelope every list endpoint returns, how to page through it, and how NSFW items are filtered. Source: https://staging.threadapi.dev/docs/listings/ · Markdown: https://staging.threadapi.dev/docs/listings/index.md Every endpoint that returns a list of posts, comments, subreddits or users answers with the same envelope: ```jsonc { "subreddit": "golang", // the subreddit asked for, or null "query": null, // the search query, or null "sort": "top", // the sort Reddit applied "count": 3, // items in this page "items": [ /* posts, comments, subreddits or users */ ], "after": "t3_1x0vbyx", // pass back as after= for the next page; null on the last "filtered_nsfw": 0 // NSFW items left out of this page } ``` The item type depends on the endpoint: [Subreddit](/api/Reddit/listSubreddit/), [Search](/api/Reddit/search/), [Duplicates](/api/Reddit/getPostDuplicates/) and [User posts](/api/Reddit/getUserPosts/) return posts; [Subreddit comments](/api/Reddit/getSubredditComments/), [User comments](/api/Reddit/getUserComments/) and [Comment search](/api/Reddit/searchComments/) return comments; [Subreddits](/api/Reddit/getSubreddits/) and `search?type=subreddit` return subreddits; `search?type=user` returns users. ## Pages Pass the previous page's `after` to get the next one. Each page is one call and 1 credit. ```bash curl "https://api.threadapi.dev/v1/reddit/subreddit?sub=golang&sort=new&limit=100&after=t3_1x0vbyx" \ -H "Authorization: Bearer $THREADAPI_API_KEY" ``` `after` is a Reddit fullname (`t3_…` for posts, `t1_…` for comments, `t5_…` for subreddits, `t2_…` for users) except on comment search, where it is an opaque string. Treat it as opaque everywhere and pass it back unchanged. Reddit stops a listing at about 1,000 items, whatever the sort. To go further back, narrow the request: a shorter `t` window, a search with `sub`, or a different sort. ## NSFW Items Reddit marks NSFW are left out unless you pass `nsfw=true`. `filtered_nsfw` counts how many were left out of the page, so a page can hold fewer than `limit` items while `after` is still set. Reading a subreddit that is itself marked NSFW without `nsfw=true` returns 403 `nsfw_subreddit`: ```json {"error":{"code":"nsfw_subreddit","message":"This subreddit is marked NSFW. Pass nsfw=true to read it.","retryable":false}} ``` ## Caching Listings are cached briefly: 30 seconds for `new` and `rising`, a minute for `hot` and search, and 5 minutes for `top` and `controversial` over a day or longer. The `X-Cache-Tier` header says whether the page came from the cache (`L1_LISTING`) or from Reddit (`MISS`). A cached page costs the same 1 credit. # MCP server > Give Claude, Cursor, VS Code or Codex Reddit posts, subreddits and search through threadapi's remote MCP server. Source: https://staging.threadapi.dev/docs/mcp/ · Markdown: https://staging.threadapi.dev/docs/mcp/index.md threadapi runs a remote MCP server. There's nothing to install: point your client at the URL, then sign in to threadapi when the client asks, or send an API key. | | | | :--- | :--- | | **URL** | `https://api.threadapi.dev/mcp` | | **Transport** | Streamable HTTP | | **Auth** | OAuth sign-in, or `Authorization: Bearer ` | | **Billing** | Tool calls cost the same as the REST routes. Connecting and listing tools is free. | No account yet? An agent can create one for its user: see [Agent sign-up](/docs/agent-signup). ## Tools | Tool | What it does | Credits | | :--- | :--- | :--- | | `get_reddit_post` | A raw Reddit post with its full comment tree as pristine Markdown (default) or raw JSON. Zero AI summarization; delivers full ground-truth content. Arguments: `post` (URL, comment permalink or ID), `comment` and `context` to focus on one comment, `max_comments` (default 200), `format` (`markdown` or `json`), `digest` (boolean, default `false`). | 1 for up to 500 comments, +1 per further 100 | | `get_reddit_items` | Up to 100 raw posts by ID (`t3_` or bare ID) or URL via fast bulk lookup. Arguments: `ids` (comma-separated). | 1 | | `list_subreddit_posts` | Hot, new, top, rising or controversial posts. Arguments: `subreddit`, `sort`, `time`, `limit`, `after`, `nsfw`. | 1 | | `get_subreddit` | A subreddit's description, subscribers and rules. Arguments: `subreddit`. | 1 | | `get_reddit_user` | A user's karma and badges, and with `include` their recent `posts` or `comments`. Arguments: `name`, `include`. | 1, or 2 with `include` | | `search_reddit` | Posts, comments, subreddits or users matching a query. Supports direct comment search without CDN blocks. Arguments: `query`, `type` (`post`, `comment`, `subreddit` or `user`), `subreddit`, `sort`, `time`, `limit`, `after`, `nsfw`. | 1 | | `create_monitor` | Creates a new keyword monitor on public Reddit posts and comments. Scans the real-time Reddit firehose. Arguments: `name`, `keywords` (array of strings, 1-20), `exclude`, `subreddits`, `posts`, `comments`, `nsfw`, `webhook_url`, `webhook_kind`. | 10 credits / day | | `update_monitor` | Updates an existing monitor's settings, keywords, subreddits, or webhook. Pass `webhook_url: ""` to remove an existing webhook. Arguments: `monitor_id`, `name`, `keywords`, `exclude`, `subreddits`, `posts`, `comments`, `nsfw`, `webhook_url`, `webhook_kind`. | 0 | | `pause_monitor` | Pauses an active keyword monitor. Stops scanning and stops daily charges at once. Arguments: `monitor_id`. | 0 | | `resume_monitor` | Resumes a paused keyword monitor and restarts scanning. Charges 10 credits for 1 day. Arguments: `monitor_id`. | 10 credits / day | | `delete_monitor` | Permanently deletes a keyword monitor and stops daily charges at once. Arguments: `monitor_id`. | 0 | | `list_monitors` | Lists all active keyword monitors on your account, with their IDs, status, keywords, subreddits, and match counts. | 0 | | `get_monitor_matches` | Matches detected by one of your [monitors](/docs/monitors) in compact text format. Arguments: `monitor_id`, `order` (`oldest` default or `newest`), `after` (cursor for oldest), `before` (cursor for newest), `limit` (default 100). | 0 | Errors come back as tool errors with a hint for the model, and cost nothing. ## Resources Read-only context providers exposed through MCP URIs: | Resource URI Template | MIME Type | Description | | :--- | :--- | :--- | | `reddit://post/{id}` | `text/markdown` | Direct markdown representation of a raw Reddit post and its full comment tree. | | `reddit://r/{subreddit}/hot` | `text/plain` | Top hot posts from a subreddit in JSON format. | ## Client Setup ### Cursor Add to `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (project-specific): ```json { "mcpServers": { "threadapi": { "url": "https://api.threadapi.dev/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` ### Claude Desktop Add to `claude_desktop_config.json`: ```json { "mcpServers": { "threadapi": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-fetch", "https://api.threadapi.dev/mcp"] } } } ``` ### Claude Code Run in your terminal: ```bash claude mcp add --transport http threadapi https://api.threadapi.dev/mcp ``` ### Windsurf Add to `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "threadapi": { "serverUrl": "https://api.threadapi.dev/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` ### VS Code Install the Model Context Protocol extension, then add to your settings: ```json { "mcp": { "servers": { "threadapi": { "type": "http", "url": "https://api.threadapi.dev/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } } ``` # Monitors > Get new Reddit posts and comments that mention your keywords, by webhook or by polling. Source: https://staging.threadapi.dev/docs/monitors/ · Markdown: https://staging.threadapi.dev/docs/monitors/index.md A monitor watches every new post and comment on Reddit for your keywords. When one matches, threadapi sends it to your webhook (your own endpoint, Slack or Discord) and keeps it for you to read from the API or the [dashboard](https://threadapi.dev/app/monitors?utm_source=docs). A running monitor costs **10 credits per day** (up to 20 keywords). Its matches and deliveries are free. ## How matching works - Keywords match whole words, ignoring case: `rust` matches "Rust" and "RUST" but not "trust" or "rusty". A keyword with several words matches that phrase: `borg backup`. Quotes around a keyword are optional. - Keywords in Chinese, Japanese or Korean match anywhere in the text, since those languages don't separate words with spaces. - A post matches on its title and text, a comment on its text. - An item matches if it contains any keyword and no `exclude` term. - Up to 20 keywords and 20 exclude terms, each 2 to 100 characters. Up to 50 subreddits; leave `subreddits` empty to watch all of Reddit. - Items marked NSFW are skipped unless the monitor has `nsfw: true`. Most matches arrive within 15 seconds of being posted. A post that Reddit is slow to make visible can take about two minutes. If Reddit stops answering threadapi for a while, items posted during that time can be missed. ## Create a monitor ```bash curl https://api.threadapi.dev/v1/monitors \ -H "Authorization: Bearer $THREADAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Backup tools", "keywords": ["restic", "borg backup", "kopia"], "exclude": ["hiring"], "subreddits": ["selfhosted", "DataHoarder", "homelab"], "posts": true, "comments": true, "webhook_url": "https://example.com/threadapi-hook" }' ``` | Field | Type | | | :--- | :--- | :--- | | `name` | string | Required. Your label for the monitor. | | `keywords` | string[] | Required. 1 to 20 terms. | | `exclude` | string[] | Skip items containing any of these. | | `subreddits` | string[] | Only watch these, with or without `r/`. Empty means all of Reddit. | | `posts` | boolean | Watch new posts. Default `true`. | | `comments` | boolean | Watch new comments. Default `true`. | | `nsfw` | boolean | Include NSFW items. Default `false`. | | `webhook_url` | string | An `https://` URL to send matches to. Optional: without one, read matches from the API. | | `webhook_kind` | string | `generic`, `slack`, `discord` or `telegram`. Detected from the URL when left out. | Creating a monitor charges 10 credits for its first 24 hours and answers `201`: ```jsonc { "monitor": { "id": "c8nh5roydywdmhsndzqdd269p", "name": "Backup tools", "keywords": ["restic", "borg backup", "kopia"], "exclude": ["hiring"], "subreddits": ["selfhosted", "datahoarder", "homelab"], "include_posts": true, "include_comments": true, "status": "running", "matches_total": 0, "next_charge_at": "2026-10-21T15:00:00Z", "created_at": "2026-10-20T15:00:00Z" } } ``` ## Polling matches If you omit `webhook_url`, you can poll `/v1/monitors/{id}/matches`: ```bash curl "https://api.threadapi.dev/v1/monitors/c8nh5roydywdmhsndzqdd269p/matches?limit=50" \ -H "Authorization: Bearer $THREADAPI_API_KEY" ``` Matches are ordered by timestamp with pagination via cursor tokens. # Pricing > Credit packs that never expire. One credit is one page of Reddit, and failed requests are free. Source: https://staging.threadapi.dev/docs/pricing/ · Markdown: https://staging.threadapi.dev/docs/pricing/index.md threadapi sells credit packs. There is no subscription: packs add to one balance and never expire. | Pack | Credits | Per 1,000 | Rate limit | | ---: | ---: | ---: | :--- | | Free, on sign-up | 100 | | 1 request per second, 100 per day | | $9 | 2,000 | $4.50 | 300 per minute | | $29 | 10,000 | $2.90 | 600 per minute | | $79 | 50,000 | $1.58 | 1,000 per minute | Buy packs in the [billing dashboard](https://threadapi.dev/app/billing?utm_source=docs). Over 50,000 a month, [ask about volume pricing](https://threadapi.dev/contact?utm_source=docs). ## What a request costs One credit is one page of Reddit: | Request | Credits | | :--- | ---: | | [Post](/api/Reddit/getPost/) with up to 500 comments | 1 | | Each further 100 comments, or part of 100 | 1 | | Any [listing](/docs/listings) page, up to 100 items: subreddit posts or comments, search, user posts or comments, subreddits, duplicates | 1 | | [Comment search](/api/Reddit/searchComments/), one page | 1 | | [Things](/api/Reddit/getThings/), up to 100 posts and comments | 1 | | [Subreddit about](/api/Reddit/getSubredditAbout/) or [User](/api/Reddit/getUser/) | 1 | | A running [monitor](/docs/monitors), per day (up to 20 keywords) | 10 | | Monitor matches, webhook deliveries, and managing monitors | 0 | | Any failed request | 0 | - A post request asks for 200 comments unless you set `max_comments`, so it costs 1 credit. `max_comments=1000` costs at most 6. - You pay for the comments a response returns, not for the requests threadapi makes to produce it. Retries on our side are never billed. - A response served from cache costs the same as a fresh one. - If your balance covers fewer pages than you asked for, you get what it covers and `meta.limited_by_balance` is `true`. The balance never goes below zero. - MCP tool calls cost the same as the routes they call. The playground in the dashboard is billed like a key. - `X-Credits-Used` on every successful response says what it cost; the [logs](https://threadapi.dev/app/logs?utm_source=docs) list each request. ## Monitors A [monitor](/docs/monitors) charges 10 credits when you create or resume it, then 10 credits every 24 hours while it runs (up to 20 keywords, matches free). Pausing or deleting it stops the charges. When a renewal finds insufficient credits, the monitor stops until you add credits and resume it. How many monitors you can run depends on the largest pack you've bought: | | Monitors | Matches per monitor per day | | :--- | ---: | ---: | | Free | 1 | 200 | | $9 pack | 5 | 1,000 | | $29 pack | 20 | 1,000 | | $79 pack | 50 | 1,000 | Low-balance emails say how many days your running monitors have left. ## Refunds Within 14 days of buying a pack, if none of its credits were used. Email [hello@threadapi.dev](mailto:hello@threadapi.dev).