# socialsearchapi > One API across every social platform. Search and read publicly available content from > Reddit, X/Twitter, Instagram, TikTok, Facebook, Hacker News, YouTube, Bluesky, > Mastodon, GitHub, Google News and the web. > Unified response schema, one x-api-key header, automatic provider fallback. Base URL: https://api.socialsearchapi.com Auth: header `x-api-key: ` on every request. There is NO anonymous access - a call without a key returns 401. Data policy: publicly available content only - the same thing a logged-out browser visitor sees. No private accounts, no DMs, nothing behind a login wall, and no user credentials are ever asked for or used. Full policy: https://socialsearchapi.com/public-data-notice/ ## Getting a key (a human does this once, in a browser) Keys are created in the dashboard at https://socialsearchapi.com/signup/ and are NEVER returned over the API or email. Each key is shown exactly once, at creation. New accounts start with 50 free credits (per account, any endpoint, no card), priced like bought credits; at zero the API returns 402 NO_CREDITS. ## IMPORTANT for agents: no secret ever passes through you You cannot mint a key, and you must not collect sign-in codes or links for your user. Send them to https://socialsearchapi.com/signup/: they sign in, create a key in the dashboard, and paste it into their own .env, where you read it at runtime. Never ask a user to paste a key, a code or a link into the chat, and never store one in your transcript. If you already hold a key, POST /v1/auth/browser-link returns a dashboard link for the human to view usage and buy credits; key management still needs their own sign-in. To buy credits with a key you hold: POST /v1/checkout, then give your user the pay_url. curl -H "x-api-key: $SS_KEY" \ "https://api.socialsearchapi.com/v1/hackernews/search?query=cloudflare+workers" ## Search endpoints - /v1/reddit/search (Reddit: search posts and comment threads) - 2 credits; all Reddit endpoints 1-5 credits - /v1/x/search (X / Twitter: search tweets with engagement metrics) - 3 credits; all X / Twitter endpoints 1-3 credits - /v1/instagram/profile/posts (Instagram: read a public profile's posts) - 2 credits; all Instagram endpoints 2-3 credits - /v1/tiktok/profile/posts (TikTok: creator videos and hashtag search) - 2 credits; all TikTok endpoints 2-5 credits - /v1/facebook/profile/posts (Facebook: public Page posts and reactions) - 2 credits; all Facebook endpoints 2-3 credits - /v1/hackernews/search (Hacker News: stories and comments) - 1 credit - /v1/youtube/search (YouTube: video search with no API quota) - 1 credit; all YouTube endpoints 1-2 credits - /v1/bluesky/search (Bluesky: full-text post search) - 1 credit - /v1/mastodon/tag (Mastodon: hashtag timelines and search) - 1 credit - /v1/github/search (GitHub: repos, issues, code and users) - 1 credit - /v1/google_news/search (Google News: news headlines by query) - 1 credit - /v1/web/search (Web / News: web and news search) - 1 credit ## Platform-specific query behavior ### GET /v1/x/search query behavior Queries are passed through to X's search index, whose operator and exact-phrase enforcement is best-effort. The sort parameter selects Latest or Top ranking; neither is a correctness mode. socialsearchapi does not offer a guaranteed retweet exclusion: negative retweet operators can still return reposts. To remove clear reposts, filter items whose text matches /^\s*RT\s+@/i. This signal is not complete, and the normalized response has no guaranteed is_retweet field. metrics.reposts is the number of reposts an item received, not whether the item is itself a repost, and quote posts are distinct. Parenthesize OR groups when combining them with other terms, for example ("hate prospecting" OR "no time to prospect") lang:en. JavaScript client-side filtering: ```javascript const withoutClearReposts = data.items.filter((item) => !/^\s*RT\s+@/i.test(item.text ?? "")); ``` Python client-side filtering: ```python import re without_clear_reposts = [item for item in data["items"] if not re.match(r"^\s*RT\s+@", item.get("text") or "", re.IGNORECASE)] ``` ## Accounts & billing (all free: none of these spends credits) Free operations: POST /v1/auth/request-code, POST /v1/auth/verify, POST /v1/auth/browser-link, POST /v1/auth/signout, GET /v1/keys, POST /v1/keys, DELETE /v1/keys/{kid}, POST /v1/keys/{kid}/rotate, GET /v1/me, GET /v1/credits/balance, GET /v1/plans, POST /v1/checkout, POST /v1/checkout/confirm, POST /v1/orders/{id}/checkout, GET /v1/orders/{id}, GET /v1/status. Only the search endpoints above are priced. - POST /v1/auth/request-code {email} -> emails a 6-digit code (login IS signup) - POST /v1/auth/verify {email, otp} -> signs in; returns dashboard_url (never a key) - POST /v1/auth/browser-link -> a fresh one-time dashboard link for the user's browser - Keys: created/listed/rotated/deleted in the dashboard only (browser session), up to 10 per account, shown once at creation - GET /v1/me -> credit balance + 7-day usage per endpoint + recent calls. Never returns a key. - GET /v1/credits/balance -> {"ok": true, "balance": N} (credits). Free and bought credits are one balance per account; every key draws from it. Pre-flight check, or while waiting for a purchase. - Between calls, read credits_remaining from every success envelope (also in the 402 body) instead of polling. Both ways are supported; neither will be removed. - GET /v1/plans -> the three credit packs + checkout instructions - POST /v1/checkout {"plan": "starter" | "growth" | "pro"} (x-api-key works) -> order_id + pay_url. Three packs only: a "credits" field or any other amount is refused (422). You cannot pay. Hand pay_url to your user: a plain payment page on https://socialsearchapi.com, no sign-in, no key. Credits land within seconds of payment; poll GET /v1/credits/balance if you need to wait. - Policy: all sales final, unused credits never expire and are not refundable, failed API calls are never charged - List price $0.004/credit. Packs: - starter: 5,000 credits, $19.00 ($0.00380/credit, 5% off list) - growth: 25,000 credits, $65.00 ($0.00260/credit, 35% off list) - pro: 150,000 credits, $315.00 ($0.00210/credit, 48% off list) ## Response shape - identical on every platform { "success": true, "platform": "...", "data": { "total": N, "items": [...] }, "credits_used": N, "credits_remaining": N, "request_id": "req-..." } Every item has exactly these keys, whatever the platform: id, platform, type, title, text, url, author, author_name, created_at (ISO-8601 UTC "YYYY-MM-DDTHH:MM:SSZ" when the source gives a date, otherwise null. Never a unix integer.), metrics ({score, comments, likes, views, shares, reposts, quotes, rating, rating_count} - only the ones that platform reports), extra (platform-specific leftovers) Errors: { "success": false, "endpoint", "error": { "type", "message", "status", "docs_url", "fix"? }, "credits_used": 0, "request_id" }. fix is present when there is a specific step to take. Credits are charged on success only. Every error type the API sends, with its status: - 400 BAD_REQUEST: The request was understood but rejected; the message says why (a bad Content-Length, a refused email address). - 400 CODE_EXPIRED: Sign-in: the code is older than its lifetime. Request a new one. - 400 EMAIL_NOT_ACCEPTED: Disposable email domains cannot sign up. Use a real mailbox; the free credits are the same. - 400 INVALID_CODE: Sign-in: wrong code. The body carries attempts_left; the same code stays valid until it expires or the guesses run out. - 400 NO_PENDING_CODE: Sign-in: no code was requested for this address, or it was already used. Request a new one. - 400 TOO_MANY_ATTEMPTS: Sign-in: too many wrong guesses for this code or from this address. Request the code again after the cooldown, or wait for it to expire. - 401 MISSING_API_KEY: No x-api-key header on a platform endpoint. There is no anonymous tier: send your key on every request. - 401 UNAUTHORIZED: The credential for this operation is missing, unknown, expired or revoked: a key on account and billing operations, a browser session on key management, the owner key on admin routes. - 402 NO_CREDITS: The account's credits are used up. Top up; nothing is queued and nothing is deleted, and the same key keeps working after payment. - 403 INVALID_API_KEY: The key is unknown, rotated away or revoked. Create or rotate one in the dashboard. - 403 OTP_SIGNIN_REQUIRED: This browser session came from an API key (browser-link) and cannot create, rotate or revoke keys. Sign in with the emailed code. - 404 NOT_FOUND: No such key or order on this account. - 404 UNKNOWN_ENDPOINT: No such route. GET /v1/status lists the platforms; the reference lists every path. - 409 KEY_LIMIT: The account already holds the maximum number of keys. Delete one first. - 409 ORDER_MISMATCH: The payment did not match the order. Nothing was credited; operators are alerted and will sort it out. - 411 LENGTH_REQUIRED: Send a Content-Length header; chunked request bodies are not accepted. - 413 PAYLOAD_TOO_LARGE: The request body is over the limit the message states. - 422 VALIDATION_ERROR: A parameter or body field is missing, malformed or out of range. The message names it; fix, when present, shows a working example. - 424 ALL_SOURCES_FAILED: Every source for that platform failed on this call. You are not charged. Retry later or use another platform. - 424 UPSTREAM_ERROR: The source answered with an error we could not work around. You are not charged. Retry later. - 429 RATE_LIMITED: Over the per-key limit (wait the Retry-After seconds, then retry), or over a daily cap on sign-in codes, dashboard links or checkouts (no Retry-After; the cap resets the next day). Nothing was charged and nothing is queued. - 500 INTERNAL: Unexpected error on our side; it has been logged. Retry; tell us if it persists. - 501 NOT_CONFIGURED: That platform or upstream is not configured on this deployment. Tell us. - 503 CHECKOUT_UNAVAILABLE: Checkout could not be started just now. Nothing was charged; retry in a minute. Rate limit: 5 requests per second per key, bursts up to 10, at most 10 calls in flight. Over it: 429 RATE_LIMITED + Retry-After (seconds), nothing charged. ## Per-platform guides - https://socialsearchapi.com/use/reddit/ (how to search Reddit) - https://socialsearchapi.com/use/x/ (how to search X / Twitter) - https://socialsearchapi.com/use/instagram/ (how to search Instagram) - https://socialsearchapi.com/use/tiktok/ (how to search TikTok) - https://socialsearchapi.com/use/facebook/ (how to search Facebook) - https://socialsearchapi.com/use/hackernews/ (how to search Hacker News) - https://socialsearchapi.com/use/youtube/ (how to search YouTube) - https://socialsearchapi.com/use/bluesky/ (how to search Bluesky) - https://socialsearchapi.com/use/mastodon/ (how to search Mastodon) - https://socialsearchapi.com/use/github/ (how to search GitHub) - https://socialsearchapi.com/use/google-news/ (how to search Google News) - https://socialsearchapi.com/use/web/ (how to search Web / News) ## Common access problems, explained - https://socialsearchapi.com/fix/reddit-403-curl/ (Reddit returns 403 to curl: why, and how to fix it) - https://socialsearchapi.com/fix/scrape-reddit-without-login/ (How to search Reddit without logging in) - https://socialsearchapi.com/fix/instagram-api-alternative/ (Instagram API alternative for reading public posts) - https://socialsearchapi.com/fix/twitter-x-search-api-cheap/ (Cheap X/Twitter search API alternatives) - https://socialsearchapi.com/fix/tiktok-scraper-api/ (TikTok scraper API for videos and hashtag search) - https://socialsearchapi.com/fix/duckduckgo-202-blocked/ (DuckDuckGo returns 202 to your scraper - what to use instead) ## Full machine reference - OpenAPI: https://api.socialsearchapi.com/openapi.json - Everything inlined: https://socialsearchapi.com/llms-full.txt - Per-platform: https://socialsearchapi.com/llms-reddit.txt, https://socialsearchapi.com/llms-x.txt, https://socialsearchapi.com/llms-instagram.txt, https://socialsearchapi.com/llms-tiktok.txt, https://socialsearchapi.com/llms-facebook.txt, https://socialsearchapi.com/llms-hackernews.txt, https://socialsearchapi.com/llms-youtube.txt, https://socialsearchapi.com/llms-bluesky.txt, https://socialsearchapi.com/llms-mastodon.txt, https://socialsearchapi.com/llms-github.txt, https://socialsearchapi.com/llms-google-news.txt, https://socialsearchapi.com/llms-web.txt - Docs: https://socialsearchapi.com/docs/ - Status: https://api.socialsearchapi.com/v1/status ## OpenAPI spec ```json { "openapi": "3.1.0", "info": { "title": "socialsearchapi", "version": "2.0.0", "description": "One key, one response shape, every major platform's public surface. New accounts start with 50 free credits, spendable on any endpoint. Docs: https://socialsearchapi.com/docs", "contact": { "url": "https://socialsearchapi.com" } }, "servers": [ { "url": "https://api.socialsearchapi.com" } ], "security": [ { "apiKey": [] } ], "paths": { "/v1/hackernews/search": { "get": { "operationId": "hackernews_search", "tags": [ "Hacker News" ], "summary": "Search Hacker News stories and comments", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Search keyword or phrase", "schema": { "type": "string", "maxLength": 512 } }, { "name": "type", "in": "query", "required": false, "description": "Result type", "schema": { "type": "string", "enum": [ "story", "comment" ], "default": "story", "maxLength": 512 } }, { "name": "sort", "in": "query", "required": false, "description": "Ranking", "schema": { "type": "string", "enum": [ "relevance", "new" ], "default": "relevance", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "30", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "cloudflare workers" } } }, "/v1/hackernews/story": { "get": { "operationId": "hackernews_story", "tags": [ "Hacker News" ], "summary": "Get one Hacker News story with metadata", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "HN item id", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "38865518" } } }, "/v1/hackernews/story/comments": { "get": { "operationId": "hackernews_story_comments", "tags": [ "Hacker News" ], "summary": "List all comments on a Hacker News story, replies flattened with depth", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "HN story id", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max comments", "schema": { "type": "string", "default": "100", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "38865518" } } }, "/v1/hackernews/profile": { "get": { "operationId": "hackernews_profile", "tags": [ "Hacker News" ], "summary": "Get a Hacker News user profile", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "HN username", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "dang" } } }, "/v1/github/search": { "get": { "operationId": "github_search", "tags": [ "GitHub" ], "summary": "Search GitHub repositories, issues/PRs, code, or users", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "GitHub search query (qualifiers supported)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "type", "in": "query", "required": false, "description": "What to search. Note: issues includes pull requests (GitHub search behavior) - item.type distinguishes issue vs pull_request", "schema": { "type": "string", "enum": [ "repositories", "issues", "users", "code" ], "default": "repositories", "maxLength": 512 } }, { "name": "sort", "in": "query", "required": false, "description": "GitHub sort field (stars, updated, ...)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "20", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "social media api", "type": "repositories" } } }, "/v1/github/profile": { "get": { "operationId": "github_profile", "tags": [ "GitHub" ], "summary": "Get a GitHub user or organization profile", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "GitHub login", "schema": { "type": "string", "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "cloudflare" } } }, "/v1/github/profile/repos": { "get": { "operationId": "github_profile_repos", "tags": [ "GitHub" ], "summary": "List a GitHub user's repositories", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "GitHub login", "schema": { "type": "string", "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})$", "maxLength": 512 } }, { "name": "sort", "in": "query", "required": false, "description": "Sort order", "schema": { "type": "string", "enum": [ "updated", "created", "pushed", "full_name" ], "default": "updated", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max repos (1-100)", "schema": { "type": "string", "default": "30", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "honojs" } } }, "/v1/github/repo": { "get": { "operationId": "github_repo", "tags": [ "GitHub" ], "summary": "Get one GitHub repository", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "owner/name, e.g. honojs/hono", "schema": { "type": "string", "pattern": "^(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+\\/(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "honojs/hono" } } }, "/v1/github/repo/readme": { "get": { "operationId": "github_repo_readme", "tags": [ "GitHub" ], "summary": "Get a repository's README as text", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "owner/name", "schema": { "type": "string", "pattern": "^(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+\\/(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "honojs/hono" } } }, "/v1/github/repo/releases": { "get": { "operationId": "github_repo_releases", "tags": [ "GitHub" ], "summary": "List a repository's releases", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "owner/name", "schema": { "type": "string", "pattern": "^(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+\\/(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+$", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max releases", "schema": { "type": "string", "default": "20", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "honojs/hono" } } }, "/v1/github/repo/issues": { "get": { "operationId": "github_repo_issues", "tags": [ "GitHub" ], "summary": "List a repository's issues and pull requests", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "owner/name", "schema": { "type": "string", "pattern": "^(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+\\/(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+$", "maxLength": 512 } }, { "name": "state", "in": "query", "required": false, "description": "Issue state", "schema": { "type": "string", "enum": [ "open", "closed", "all" ], "default": "open", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "30", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "honojs/hono", "state": "open" } } }, "/v1/github/issue": { "get": { "operationId": "github_issue", "tags": [ "GitHub" ], "summary": "Get one issue or pull request", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "owner/name/number, e.g. honojs/hono/1", "schema": { "type": "string", "pattern": "^(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+\\/(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+\\/\\d+$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "honojs/hono/1" } } }, "/v1/github/issue/comments": { "get": { "operationId": "github_issue_comments", "tags": [ "GitHub" ], "summary": "List comments on an issue or pull request", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "owner/name/number", "schema": { "type": "string", "pattern": "^(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+\\/(?!\\.{1,2}(?:\\/|$))[A-Za-z0-9_.-]+\\/\\d+$", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max comments (1-100)", "schema": { "type": "string", "default": "50", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "facebook/react/13991" } } }, "/v1/reddit/search": { "get": { "operationId": "reddit_search", "tags": [ "Reddit" ], "summary": "Search Reddit posts across all subreddits by keyword, or find every post linking to a URL", "parameters": [ { "name": "query", "in": "query", "required": false, "description": "Search keyword or phrase (this or url is required) (one of query / url is required)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "url", "in": "query", "required": false, "description": "Find posts whose link starts with this URL (brand/domain mention tracking) (one of query / url is required)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "sort", "in": "query", "required": false, "description": "Ranking (keyword search)", "schema": { "type": "string", "enum": [ "relevance", "new", "top", "comments" ], "default": "relevance", "maxLength": 512 } }, { "name": "timeframe", "in": "query", "required": false, "description": "Time window (keyword search)", "schema": { "type": "string", "enum": [ "all", "day", "week", "month", "year" ], "default": "all", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "25", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor from a previous response", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "query": "cloudflare workers" }, "x-require-one-of": [ "query", "url" ] } }, "/v1/reddit/subreddit/search": { "get": { "operationId": "reddit_subreddit_search", "tags": [ "Reddit" ], "summary": "Search posts within one subreddit, optionally date-windowed years back", "parameters": [ { "name": "subreddit", "in": "query", "required": true, "description": "Subreddit name without r/", "schema": { "type": "string", "pattern": "^(r\\/)?[A-Za-z0-9_]{2,21}$", "maxLength": 512 } }, { "name": "query", "in": "query", "required": true, "description": "Search keyword or phrase", "schema": { "type": "string", "maxLength": 512 } }, { "name": "sort", "in": "query", "required": false, "description": "Order: new is served from the free archive; relevance, top and comments are live rankings", "schema": { "type": "string", "enum": [ "new", "relevance", "top", "comments" ], "default": "new", "maxLength": 512 } }, { "name": "timeframe", "in": "query", "required": false, "description": "Time window", "schema": { "type": "string", "enum": [ "all", "day", "week", "month", "year" ], "default": "all", "maxLength": 512 } }, { "name": "after", "in": "query", "required": false, "description": "Only content on/after this date (YYYY-MM-DD or relative like 7d, 1year) - served from the historical archive", "schema": { "type": "string", "maxLength": 512 } }, { "name": "before", "in": "query", "required": false, "description": "Only content before this date (YYYY-MM-DD or relative) - served from the historical archive", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "25", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "subreddit": "webdev", "query": "api" } } }, "/v1/reddit/subreddit/posts": { "get": { "operationId": "reddit_subreddit_posts", "tags": [ "Reddit" ], "summary": "List a subreddit's posts by sort order, or by date window from the archive", "parameters": [ { "name": "subreddit", "in": "query", "required": true, "description": "Subreddit name without r/", "schema": { "type": "string", "pattern": "^(r\\/)?[A-Za-z0-9_]{2,21}$", "maxLength": 512 } }, { "name": "sort", "in": "query", "required": false, "description": "Order: new is served from the free archive and is the only order that combines with after/before; hot, top and rising are live rankings", "schema": { "type": "string", "enum": [ "new", "hot", "top", "rising" ], "default": "new", "maxLength": 512 } }, { "name": "timeframe", "in": "query", "required": false, "description": "Time window (top only)", "schema": { "type": "string", "enum": [ "all", "day", "week", "month", "year" ], "default": "week", "maxLength": 512 } }, { "name": "after", "in": "query", "required": false, "description": "Only content on/after this date (YYYY-MM-DD or relative like 7d, 1year) - served from the historical archive", "schema": { "type": "string", "maxLength": 512 } }, { "name": "before", "in": "query", "required": false, "description": "Only content before this date (YYYY-MM-DD or relative) - served from the historical archive", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "25", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "subreddit": "programming", "sort": "hot" } } }, "/v1/reddit/subreddit": { "get": { "operationId": "reddit_subreddit", "tags": [ "Reddit" ], "summary": "Get subreddit details (subscribers, description)", "parameters": [ { "name": "subreddit", "in": "query", "required": true, "description": "Subreddit name without r/", "schema": { "type": "string", "pattern": "^(r\\/)?[A-Za-z0-9_]{2,21}$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "subreddit": "programming" } } }, "/v1/reddit/subreddits": { "get": { "operationId": "reddit_subreddits", "tags": [ "Reddit" ], "summary": "Discover subreddits by name prefix, ranked by subscribers", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Subreddit name prefix, e.g. 'ask'", "schema": { "type": "string", "maxLength": 512 } }, { "name": "min_followers", "in": "query", "required": false, "description": "Only subreddits with at least this many subscribers", "schema": { "type": "string", "pattern": "^\\d{1,9}$", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "25", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "cloud" } } }, "/v1/reddit/profile": { "get": { "operationId": "reddit_profile", "tags": [ "Reddit" ], "summary": "Get a Reddit user profile (karma, account age, activity volume)", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "Reddit username without u/", "schema": { "type": "string", "pattern": "^(u\\/)?[A-Za-z0-9_-]{3,20}$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "spez" } } }, "/v1/reddit/profile/posts": { "get": { "operationId": "reddit_profile_posts", "tags": [ "Reddit" ], "summary": "A Reddit user's post history, optionally date-windowed years back", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "Reddit username without u/", "schema": { "type": "string", "pattern": "^(u\\/)?[A-Za-z0-9_-]{3,20}$", "maxLength": 512 } }, { "name": "after", "in": "query", "required": false, "description": "Only content on/after this date (YYYY-MM-DD or relative like 7d, 1year) - served from the historical archive", "schema": { "type": "string", "maxLength": 512 } }, { "name": "before", "in": "query", "required": false, "description": "Only content before this date (YYYY-MM-DD or relative) - served from the historical archive", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "25", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "spez" } } }, "/v1/reddit/profile/comments": { "get": { "operationId": "reddit_profile_comments", "tags": [ "Reddit" ], "summary": "A Reddit user's comment history, optionally date-windowed years back", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "Reddit username without u/", "schema": { "type": "string", "pattern": "^(u\\/)?[A-Za-z0-9_-]{3,20}$", "maxLength": 512 } }, { "name": "after", "in": "query", "required": false, "description": "Only content on/after this date (YYYY-MM-DD or relative like 7d, 1year) - served from the historical archive", "schema": { "type": "string", "maxLength": 512 } }, { "name": "before", "in": "query", "required": false, "description": "Only content before this date (YYYY-MM-DD or relative) - served from the historical archive", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "25", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "spez" } } }, "/v1/reddit/comments/search": { "get": { "operationId": "reddit_comments_search", "tags": [ "Reddit" ], "summary": "Search Reddit comment text within a subreddit or a user's history, date-windowed", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Text to find in comment bodies (supports \"exact phrase\", OR, -exclude)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "subreddit", "in": "query", "required": false, "description": "Subreddit to search in (this or handle is required) (one of subreddit / handle is required)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "handle", "in": "query", "required": false, "description": "Username whose comments to search (one of subreddit / handle is required)", "schema": { "type": "string", "pattern": "^(u\\/)?[A-Za-z0-9_-]{3,20}$", "maxLength": 512 } }, { "name": "after", "in": "query", "required": false, "description": "Only comments on/after this date (YYYY-MM-DD or relative like 30d). Narrow windows keep large subreddits fast", "schema": { "type": "string", "default": "30d", "maxLength": 512 } }, { "name": "before", "in": "query", "required": false, "description": "Only comments before this date", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-10 - text search is capped to keep large subreddits fast)", "schema": { "type": "string", "default": "10", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "subreddit": "webdev", "query": "api", "after": "7d" }, "x-require-one-of": [ "subreddit", "handle" ] } }, "/v1/reddit/post": { "get": { "operationId": "reddit_post", "tags": [ "Reddit" ], "summary": "Get one Reddit post by URL or id", "parameters": [ { "name": "url", "in": "query", "required": false, "description": "Full Reddit post URL (one of url / id is required)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "id", "in": "query", "required": false, "description": "Post id (t3_ prefix optional) (one of url / id is required)", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "url": "https://www.reddit.com/r/programming/comments/144sn8r/apollo_dev_posts_backend_code_to_git_to_disprove/" }, "x-require-one-of": [ "url", "id" ] } }, "/v1/reddit/post/comments": { "get": { "operationId": "reddit_post_comments", "tags": [ "Reddit" ], "summary": "List comments on a Reddit post, replies nested via depth", "parameters": [ { "name": "url", "in": "query", "required": false, "description": "Full Reddit post URL (one of url / id is required)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "id", "in": "query", "required": false, "description": "Post id (one of url / id is required)", "schema": { "type": "string", "maxLength": 512 } }, { "name": "sort", "in": "query", "required": false, "description": "Sibling order at every depth: top by score, new or old by time", "schema": { "type": "string", "enum": [ "top", "new", "old" ], "default": "top", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max comments", "schema": { "type": "string", "default": "50", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "url": "https://www.reddit.com/r/programming/comments/144sn8r/apollo_dev_posts_backend_code_to_git_to_disprove/", "sort": "top" }, "x-require-one-of": [ "url", "id" ] } }, "/v1/reddit/post/transcript": { "get": { "operationId": "reddit_post_transcript", "tags": [ "Reddit" ], "summary": "Transcript of a Reddit video post", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full Reddit video post URL", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 5, "x-example": { "url": "https://www.reddit.com/r/youseeingthisshit/comments/1oiu9xm/football_nostalgiasaints_punter_head_coach_cant/" } } }, "/v1/youtube/search": { "get": { "operationId": "youtube_search", "tags": [ "YouTube" ], "summary": "Search YouTube videos", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Search keyword or phrase", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-50)", "schema": { "type": "string", "default": "20", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "cloudflare workers tutorial" } } }, "/v1/youtube/video": { "get": { "operationId": "youtube_video", "tags": [ "YouTube" ], "summary": "Get one YouTube video's details", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "Video id or full watch URL", "schema": { "type": "string", "pattern": "^([A-Za-z0-9_-]{11}|https?:\\/\\/(www\\.|m\\.)?youtube\\.com\\/watch\\?([^\\s]*&)?v=[A-Za-z0-9_-]{11}(&[^\\s]*)?|https?:\\/\\/youtu\\.be\\/[A-Za-z0-9_-]{11}(\\?[^\\s]*)?)$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "dQw4w9WgXcQ" } } }, "/v1/youtube/channel/videos": { "get": { "operationId": "youtube_channel_videos", "tags": [ "YouTube" ], "summary": "List a YouTube channel's recent videos", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "Channel id (UC...)", "schema": { "type": "string", "pattern": "^UC[A-Za-z0-9_-]{22}$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "UCsBjURrPoezykLs9EqgamOA" } } }, "/v1/youtube/channel": { "get": { "operationId": "youtube_channel", "tags": [ "YouTube" ], "summary": "Get a YouTube channel's details", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "Channel id (UC...) or @handle", "schema": { "type": "string", "pattern": "^(UC[A-Za-z0-9_-]{22}|@[A-Za-z0-9._-]{3,30})$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "id": "@cloudflare" } } }, "/v1/youtube/video/comments": { "get": { "operationId": "youtube_video_comments", "tags": [ "YouTube" ], "summary": "List comments on a YouTube video", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "Video id or full watch URL", "schema": { "type": "string", "pattern": "^([A-Za-z0-9_-]{11}|https?:\\/\\/(www\\.|m\\.)?youtube\\.com\\/watch\\?([^\\s]*&)?v=[A-Za-z0-9_-]{11}(&[^\\s]*)?|https?:\\/\\/youtu\\.be\\/[A-Za-z0-9_-]{11}(\\?[^\\s]*)?)$", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "id": "dQw4w9WgXcQ" } } }, "/v1/youtube/video/transcript": { "get": { "operationId": "youtube_video_transcript", "tags": [ "YouTube" ], "summary": "Get a YouTube video's transcript", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "Video id or full watch URL", "schema": { "type": "string", "pattern": "^([A-Za-z0-9_-]{11}|https?:\\/\\/(www\\.|m\\.)?youtube\\.com\\/watch\\?([^\\s]*&)?v=[A-Za-z0-9_-]{11}(&[^\\s]*)?|https?:\\/\\/youtu\\.be\\/[A-Za-z0-9_-]{11}(\\?[^\\s]*)?)$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "id": "dQw4w9WgXcQ" } } }, "/v1/bluesky/search": { "get": { "operationId": "bluesky_search", "tags": [ "Bluesky" ], "summary": "Full-text search of Bluesky posts", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Search keyword or phrase", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "25", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "cloudflare" } } }, "/v1/bluesky/profile": { "get": { "operationId": "bluesky_profile", "tags": [ "Bluesky" ], "summary": "Get a Bluesky profile", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "Bluesky handle or DID", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "bsky.app" } } }, "/v1/bluesky/profile/posts": { "get": { "operationId": "bluesky_profile_posts", "tags": [ "Bluesky" ], "summary": "List a Bluesky account's recent posts", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "Bluesky handle or DID", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "25", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "bsky.app" } } }, "/v1/bluesky/profile/search": { "get": { "operationId": "bluesky_profile_search", "tags": [ "Bluesky" ], "summary": "Search Bluesky accounts", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Keyword or name", "schema": { "type": "string", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "15", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "nasa" } } }, "/v1/bluesky/post": { "get": { "operationId": "bluesky_post", "tags": [ "Bluesky" ], "summary": "Get one Bluesky post (with thread context counts)", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full bsky.app post URL or at:// URI", "schema": { "type": "string", "pattern": "^(https:\\/\\/bsky\\.app\\/profile\\/[^/\\s]+\\/post\\/[^/\\s]+|at:\\/\\/[^\\s]+)$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "url": "https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l" } } }, "/v1/web/search": { "get": { "operationId": "web_search", "tags": [ "Web & News" ], "summary": "Search the web (general or news)", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Search keyword or phrase", "schema": { "type": "string", "maxLength": 512 } }, { "name": "topic", "in": "query", "required": false, "description": "Search vertical", "schema": { "type": "string", "enum": [ "general", "news" ], "default": "general", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-20)", "schema": { "type": "string", "default": "10", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "cloudflare workers pricing" } } }, "/v1/google_news/search": { "get": { "operationId": "google_news_search", "tags": [ "Web & News" ], "summary": "Search Google News articles", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Search keyword or phrase", "schema": { "type": "string", "maxLength": 512 } }, { "name": "lang", "in": "query", "required": false, "description": "hl language code", "schema": { "type": "string", "default": "en-US", "maxLength": 512 } }, { "name": "country", "in": "query", "required": false, "description": "gl country code", "schema": { "type": "string", "default": "US", "maxLength": 512 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-100)", "schema": { "type": "string", "default": "30", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "artificial intelligence" } } }, "/v1/mastodon/tag": { "get": { "operationId": "mastodon_tag", "tags": [ "Mastodon" ], "summary": "Public timeline for a Mastodon hashtag on any instance", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Hashtag without #", "schema": { "type": "string", "maxLength": 512 } }, { "name": "instance", "in": "query", "required": false, "description": "Instance domain (default mastodon.social)", "schema": { "type": "string", "maxLength": 253 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-40)", "schema": { "type": "string", "default": "20", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "opensource" } } }, "/v1/mastodon/search": { "get": { "operationId": "mastodon_search", "tags": [ "Mastodon" ], "summary": "Full-text search of Mastodon posts (instance-scoped, needs server token)", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Search keyword or phrase", "schema": { "type": "string", "maxLength": 512 } }, { "name": "instance", "in": "query", "required": false, "description": "Instance domain (default mastodon.social)", "schema": { "type": "string", "maxLength": 253 } }, { "name": "limit", "in": "query", "required": false, "description": "Max results (1-40)", "schema": { "type": "string", "default": "20", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "query": "cloudflare" } } }, "/v1/x/search": { "get": { "operationId": "x_search", "tags": [ "X / Twitter" ], "summary": "Search X (Twitter) posts with pass-through query syntax", "description": "Queries are passed through to X's search index, whose operator and exact-phrase enforcement is best-effort. The sort parameter selects Latest or Top ranking; neither is a correctness mode. socialsearchapi does not offer a guaranteed retweet exclusion: negative retweet operators can still return reposts. To remove clear reposts, filter items whose text matches /^\\s*RT\\s+@/i. This signal is not complete, and the normalized response has no guaranteed is_retweet field. metrics.reposts is the number of reposts an item received, not whether the item is itself a repost, and quote posts are distinct. Parenthesize OR groups when combining them with other terms, for example (\"hate prospecting\" OR \"no time to prospect\") lang:en.", "x-client-postprocessing": { "javascript": "const withoutClearReposts = data.items.filter((item) => !/^\\s*RT\\s+@/i.test(item.text ?? \"\"));", "python": "import re\nwithout_clear_reposts = [item for item in data[\"items\"] if not re.match(r\"^\\s*RT\\s+@\", item.get(\"text\") or \"\", re.IGNORECASE)]" }, "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Query passed through to X search; operator enforcement is best-effort", "schema": { "type": "string", "maxLength": 512 } }, { "name": "sort", "in": "query", "required": false, "description": "Latest or Top ranking; not a correctness mode", "schema": { "type": "string", "enum": [ "latest", "top" ], "default": "latest", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 3, "x-example": { "query": "cloudflare workers" } } }, "/v1/x/profile": { "get": { "operationId": "x_profile", "tags": [ "X / Twitter" ], "summary": "Get an X (Twitter) profile", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "X handle without @", "schema": { "type": "string", "pattern": "^[A-Za-z0-9_]{1,15}$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "handle": "cloudflare" } } }, "/v1/x/profile/posts": { "get": { "operationId": "x_profile_posts", "tags": [ "X / Twitter" ], "summary": "List an X (Twitter) account's recent posts", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "X handle without @", "schema": { "type": "string", "pattern": "^[A-Za-z0-9_]{1,15}$", "maxLength": 512 } }, { "name": "replies", "in": "query", "required": false, "description": "Include replies", "schema": { "type": "string", "enum": [ "true", "false" ], "default": "false", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 3, "x-example": { "handle": "cloudflare" } } }, "/v1/x/post": { "get": { "operationId": "x_post", "tags": [ "X / Twitter" ], "summary": "Get one or more X (Twitter) posts by id (comma-separated, up to 5)", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "Tweet id, or up to 5 comma-separated ids", "schema": { "type": "string", "pattern": "^\\d{1,25}(,\\d{1,25}){0,4}$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 1, "x-example": { "id": "1585841080431321088" } } }, "/v1/x/post/comments": { "get": { "operationId": "x_post_comments", "tags": [ "X / Twitter" ], "summary": "List replies to an X (Twitter) post", "parameters": [ { "name": "id", "in": "query", "required": true, "description": "Tweet id", "schema": { "type": "string", "pattern": "^\\d{1,25}$", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 3, "x-example": { "id": "1585841080431321088" } } }, "/v1/instagram/profile": { "get": { "operationId": "instagram_profile", "tags": [ "Instagram" ], "summary": "Get an Instagram profile (followers, bio, verification)", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "Instagram handle without @", "schema": { "type": "string", "pattern": "^(?=.*[A-Za-z0-9])[A-Za-z0-9._]{1,30}$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "handle": "instagram" } } }, "/v1/instagram/profile/posts": { "get": { "operationId": "instagram_profile_posts", "tags": [ "Instagram" ], "summary": "List an Instagram account's recent posts", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "Instagram handle without @", "schema": { "type": "string", "pattern": "^(?=.*[A-Za-z0-9])[A-Za-z0-9._]{1,30}$", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "handle": "instagram" } } }, "/v1/instagram/profile/search": { "get": { "operationId": "instagram_profile_search", "tags": [ "Instagram" ], "summary": "Search Instagram profiles by keyword", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Keyword or name", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "query": "nasa" } } }, "/v1/instagram/post": { "get": { "operationId": "instagram_post", "tags": [ "Instagram" ], "summary": "Get one Instagram post or reel by URL", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full Instagram post/reel URL", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "url": "https://www.instagram.com/p/BsOGulcndj-/" } } }, "/v1/instagram/post/comments": { "get": { "operationId": "instagram_post_comments", "tags": [ "Instagram" ], "summary": "List comments on an Instagram post", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full Instagram post URL", "schema": { "type": "string", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 3, "x-example": { "url": "https://www.instagram.com/p/BsOGulcndj-/" } } }, "/v1/tiktok/profile": { "get": { "operationId": "tiktok_profile", "tags": [ "TikTok" ], "summary": "Get a TikTok profile (followers, likes, bio)", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "TikTok handle without @", "schema": { "type": "string", "pattern": "^(?=.*[A-Za-z0-9])[A-Za-z0-9._]{1,24}$", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "handle": "tiktok" } } }, "/v1/tiktok/profile/posts": { "get": { "operationId": "tiktok_profile_posts", "tags": [ "TikTok" ], "summary": "List a TikTok account's recent videos", "parameters": [ { "name": "handle", "in": "query", "required": true, "description": "TikTok handle without @", "schema": { "type": "string", "pattern": "^(?=.*[A-Za-z0-9])[A-Za-z0-9._]{1,24}$", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "handle": "tiktok" } } }, "/v1/tiktok/search": { "get": { "operationId": "tiktok_search", "tags": [ "TikTok" ], "summary": "Search TikTok videos by keyword", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Search keyword or phrase", "schema": { "type": "string", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "query": "cooking" } } }, "/v1/tiktok/hashtag": { "get": { "operationId": "tiktok_hashtag", "tags": [ "TikTok" ], "summary": "List TikTok videos for a hashtag", "parameters": [ { "name": "query", "in": "query", "required": true, "description": "Hashtag without #", "schema": { "type": "string", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "query": "fyp" } } }, "/v1/tiktok/post": { "get": { "operationId": "tiktok_post", "tags": [ "TikTok" ], "summary": "Get one TikTok video by URL", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full TikTok video URL", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "url": "https://www.tiktok.com/@tiktok/video/7231338487075638570" } } }, "/v1/tiktok/post/comments": { "get": { "operationId": "tiktok_post_comments", "tags": [ "TikTok" ], "summary": "List comments on a TikTok video", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full TikTok video URL", "schema": { "type": "string", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 3, "x-example": { "url": "https://www.tiktok.com/@tiktok/video/7231338487075638570" } } }, "/v1/tiktok/post/transcript": { "get": { "operationId": "tiktok_post_transcript", "tags": [ "TikTok" ], "summary": "Get a TikTok video's transcript", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full TikTok video URL", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 5, "x-example": { "url": "https://www.tiktok.com/@tiktok/video/7231338487075638570" } } }, "/v1/facebook/profile": { "get": { "operationId": "facebook_profile", "tags": [ "Facebook" ], "summary": "Get a public Facebook Page profile", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full Facebook Page URL", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "url": "https://www.facebook.com/nasa" } } }, "/v1/facebook/profile/posts": { "get": { "operationId": "facebook_profile_posts", "tags": [ "Facebook" ], "summary": "List a public Facebook Page's posts", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full Facebook Page URL", "schema": { "type": "string", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "url": "https://www.facebook.com/nasa" } } }, "/v1/facebook/post": { "get": { "operationId": "facebook_post", "tags": [ "Facebook" ], "summary": "Get one public Facebook post by URL", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full Facebook post URL", "schema": { "type": "string", "maxLength": 512 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "url": "https://www.facebook.com/NASA/posts/pfbid0atjZuuxzCyiMeds9SaqJmsViLEs95GaCUumno1mVPAXo2xeWziEnWN3cYQ6bnR9pl" } } }, "/v1/facebook/post/comments": { "get": { "operationId": "facebook_post_comments", "tags": [ "Facebook" ], "summary": "List comments on a public Facebook post", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full Facebook post URL", "schema": { "type": "string", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 3, "x-example": { "url": "https://www.facebook.com/NASA/posts/pfbid0atjZuuxzCyiMeds9SaqJmsViLEs95GaCUumno1mVPAXo2xeWziEnWN3cYQ6bnR9pl" } } }, "/v1/facebook/group/posts": { "get": { "operationId": "facebook_group_posts", "tags": [ "Facebook" ], "summary": "List posts in a public Facebook group", "parameters": [ { "name": "url", "in": "query", "required": true, "description": "Full Facebook group URL", "schema": { "type": "string", "maxLength": 512 } }, { "name": "cursor", "in": "query", "required": false, "description": "Pagination cursor", "schema": { "type": "string", "maxLength": 4096 } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "x-credits": 2, "x-example": { "url": "https://www.facebook.com/groups/programmerhumor" } } }, "/v1/auth/request-code": { "post": { "tags": [ "Account" ], "summary": "Email a 6-digit sign-in code", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "email": { "type": "string", "description": "Address to verify" } }, "required": [ "email" ] } } } }, "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [], "operationId": "post_auth_request_code" } }, "/v1/auth/verify": { "post": { "tags": [ "Account" ], "summary": "Exchange the emailed code to sign in (returns a dashboard link, never a key)", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "email": { "type": "string", "description": "Address the code was sent to" }, "otp": { "type": "string", "description": "The 6-digit code" } }, "required": [ "email", "otp" ] } } } }, "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [], "operationId": "post_auth_verify" } }, "/v1/auth/browser-link": { "post": { "tags": [ "Account" ], "summary": "Get a one-time dashboard sign-in link for the key's owner", "description": "Send the x-api-key you already hold; answers {dashboard_url} for the key's owner to open in their browser to see usage and buy credits. A session minted this way cannot create, rotate or revoke keys: that needs the owner's own sign-in with the emailed code. With no key there is nothing to call: send your user to https://socialsearchapi.com/signup/ instead.", "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "operationId": "post_auth_browser_link" } }, "/v1/auth/signout": { "post": { "tags": [ "Account" ], "summary": "Revoke the current browser session server-side", "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [ { "sessionToken": [] } ], "operationId": "post_auth_signout" } }, "/v1/keys": { "get": { "tags": [ "Account" ], "summary": "List the account's API keys (browser session only; prefixes, never plaintext)", "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [ { "sessionToken": [] } ], "operationId": "get_keys" }, "post": { "tags": [ "Account" ], "summary": "Create an API key (browser session only; shown once, max 10 per account)", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "description": "Optional label, max 60 chars" } }, "required": [] } } } }, "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [ { "sessionToken": [] } ], "operationId": "post_keys" } }, "/v1/keys/{kid}": { "delete": { "tags": [ "Account" ], "summary": "Revoke an API key (browser session only)", "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [ { "sessionToken": [] } ], "operationId": "delete_keys_kid" } }, "/v1/keys/{kid}/rotate": { "post": { "tags": [ "Account" ], "summary": "Rotate an API key (browser session only; new key shown once)", "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [ { "sessionToken": [] } ], "operationId": "post_keys_kid_rotate" } }, "/v1/me": { "get": { "tags": [ "Account" ], "summary": "Who am I: credit balance, 7-day usage per endpoint and the last calls", "description": "Balance plus usage for the account behind the key. Never returns a key. For the balance alone, GET /v1/credits/balance is lighter; between calls, read credits_remaining from the envelope you already have.", "responses": { "200": { "description": "Account balance and usage", "content": { "application/json": { "schema": { "type": "object", "required": [ "ok", "balance", "usage_7d", "recent_calls", "purchases" ], "properties": { "ok": { "type": "boolean", "enum": [ true ] }, "email": { "type": "string", "description": "Masked (t***@example.com) when called with an API key; the full address over a browser session" }, "verified": { "type": "boolean", "description": "Always true for a key or session that reached this endpoint" }, "balance": { "type": "integer", "description": "Credits remaining on the account" }, "trial_credits": { "type": "integer", "description": "Free credits every new account starts with" }, "unmetered": { "type": "boolean", "description": "Always false: every call is metered in credits" }, "usage": { "type": "object", "description": "Same as usage_7d (kept for the dashboard)", "additionalProperties": true }, "usage_7d": { "type": "object", "description": "Per endpoint, last 7 days, every endpoint the account called (no cap): calls, credits, errors, last_at (unix seconds)", "additionalProperties": true }, "burn_7d_credits": { "type": "integer", "description": "Credits spent in the last 7 days across every endpoint (summed independently of usage_7d)" }, "burn_per_day": { "type": "number", "description": "burn_7d_credits divided by 7, two decimals" }, "recent_calls": { "type": "array", "description": "Newest 15 calls: endpoint, status, ok, credits, request_id, at (unix seconds)", "items": { "type": "object", "additionalProperties": true } }, "purchases": { "type": "array", "description": "The account's newest 10 orders (owner top-ups excluded), newest first; always present (empty when nothing was bought)", "items": { "type": "object", "required": [ "order_id", "plan", "credits", "amount_usd", "paid_usd", "status", "provider", "pending", "needs_attention", "payment_reference", "created_at", "completed_at" ], "properties": { "order_id": { "type": "string", "description": "Order id; /pay?order= is its pay link while it is payable" }, "plan": { "type": "string", "nullable": true, "description": "starter, growth or pro" }, "credits": { "type": "integer" }, "amount_usd": { "type": "number", "description": "The order's price" }, "paid_usd": { "type": "number", "nullable": true, "description": "What was actually collected; null until paid" }, "status": { "type": "string", "enum": [ "created", "failed", "completed", "refunded", "reversed", "canceled", "mismatch" ], "description": "created and failed are still payable (failed: a declined attempt); completed is paid; refunded and reversed had their credits removed; canceled expired unpaid; mismatch could not be verified" }, "provider": { "type": "string", "description": "The gateway that collected the money: paypal for every current order; rows from before the PayPal cutover keep their previous gateway's name" }, "pending": { "type": "string", "nullable": true, "description": "Why PayPal is still confirming a capture (bank transfer, review); null otherwise" }, "needs_attention": { "type": "string", "nullable": true, "enum": [ "review", null ], "description": "review: a human must look at this order (PayPal shows the capture refunded before it was confirmed); it is not payable and nothing lands automatically" }, "payment_reference": { "type": "string", "nullable": true, "description": "The PayPal capture id, the reference on the buyer's PayPal receipt; null until paid" }, "created_at": { "type": "string" }, "completed_at": { "type": "string", "nullable": true } } } } } } } } } }, "operationId": "get_me" } }, "/v1/credits/balance": { "get": { "tags": [ "Billing" ], "summary": "Current credit balance: {ok, balance}", "description": "Answers {\"ok\": true, \"balance\": N} in credits for the account behind the key. Free credits and bought credits are one balance. Use it before a run or while waiting for a purchase to land; while you are making calls, credits_remaining in every success envelope (and in the 402 NO_CREDITS body) is the same number without an extra request. Both ways are supported.", "responses": { "200": { "description": "Current balance", "content": { "application/json": { "schema": { "type": "object", "required": [ "ok", "balance" ], "properties": { "ok": { "type": "boolean", "enum": [ true ] }, "balance": { "type": "integer", "description": "Credits remaining on the account (free credits and bought credits are one balance; every key on the account draws from it)" } } } } } } }, "operationId": "get_credits_balance" } }, "/v1/plans": { "get": { "tags": [ "Billing" ], "summary": "Credit packs, per-credit pricing, checkout instructions", "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [], "operationId": "get_plans" } }, "/v1/checkout": { "post": { "tags": [ "Billing" ], "summary": "Start a credit purchase: returns a pay_url for a human to open (agents cannot pay)", "description": "Body: {\"plan\": \"starter\"|\"growth\"|\"pro\"}. Three packs only: a credits field or any other amount is refused (422). Authenticate with x-api-key or a browser x-session. The response carries order_id and pay_url (valid 7 days). Hand pay_url to your user; credits land within seconds of payment. All sales are final; failed API calls are never charged.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "plan" ], "additionalProperties": false, "properties": { "plan": { "type": "string", "enum": [ "starter", "growth", "pro" ] } } } } } }, "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "operationId": "post_checkout" } }, "/v1/checkout/confirm": { "post": { "tags": [ "Billing" ], "summary": "Return-page confirmation: reads the order at PayPal, captures an approved payment and credits it once (idempotent)", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "order_id" ], "properties": { "order_id": { "type": "string" } } } } } }, "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } }, "202": { "description": "Not credited (yet). `status` says what to do: `pending` (detail `pending_capture`: PayPal is still confirming a bank transfer or a review; `settling`: a transient, poll again) credits land automatically, no action; `action_required` (detail `payer_action_required`): the buyer must return to the pay page and continue with PayPal; `unpaid` (detail `not_approved`, `order_expired`, `voided`, `resource_not_found` or `no_provider_order`): nothing was charged, the pay page prepares a fresh PayPal checkout; `declined`: the funding source was refused, try again from the pay page; `review`: a human must look at this order (PayPal shows the capture refunded before it was confirmed), it is not payable and nothing lands automatically.", "content": { "application/json": { "schema": { "type": "object", "required": [ "ok", "status", "order_id" ], "properties": { "ok": { "type": "boolean", "enum": [ false ] }, "status": { "type": "string", "enum": [ "pending", "action_required", "unpaid", "declined", "review" ] }, "order_id": { "type": "string" }, "detail": { "type": "string", "nullable": true }, "message": { "type": "string" } } } } } }, "409": { "description": "The payment did not match the order; nothing credited, operators alerted" } }, "security": [], "operationId": "post_checkout_confirm" } }, "/v1/orders/{id}/checkout": { "post": { "tags": [ "Billing" ], "summary": "Pay page only: mints (or reuses) the PayPal order behind a pay link and returns its approve_url", "description": "Called by the pay page and the dashboard when the PayPal buttons render (the JS SDK createOrder callback) and by the redirect fallback. PayPal orders expire 3 hours after creation, so one is minted when a buyer opens the page, not at checkout. Not for agents: hand pay_url to a human.", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^ord_[a-f0-9]{32}$" } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } }, "409": { "description": "The order is already paid or can no longer be paid" }, "429": { "description": "Checkout is being prepared for this order; retry in a moment" } }, "security": [], "operationId": "post_orders_id_checkout" } }, "/v1/orders/{id}": { "get": { "tags": [ "Billing" ], "summary": "Order status by id (what the pay page reads; never the account's email or balance)", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^ord_[a-f0-9]{32}$" } } ], "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [], "operationId": "get_orders_id" } }, "/v1/status": { "get": { "tags": [ "Status" ], "summary": "Service status, platforms and endpoint count", "responses": { "200": { "description": "Success envelope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }, "security": [], "operationId": "get_status" } } }, "components": { "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "x-api-key" }, "sessionToken": { "type": "apiKey", "in": "header", "name": "x-session", "description": "Browser session minted by POST /v1/auth/verify (the dashboard sign-in) or a browser-link. Key management never accepts x-api-key." } }, "schemas": { "Item": { "type": "object", "description": "Unified item - every endpoint returns data.items of exactly this shape.", "properties": { "id": { "type": [ "string", "null" ] }, "platform": { "type": "string" }, "type": { "type": "string", "description": "post | profile | comment | video | story | repo | article | issue | pull_request | code" }, "title": { "type": [ "string", "null" ] }, "text": { "type": [ "string", "null" ] }, "url": { "type": [ "string", "null" ] }, "author": { "type": [ "string", "null" ] }, "author_name": { "type": [ "string", "null" ] }, "created_at": { "type": [ "string", "null" ], "description": "ISO-8601 UTC \"YYYY-MM-DDTHH:MM:SSZ\" when the source gives a date, otherwise null. Never a unix integer." }, "metrics": { "type": "object" }, "extra": { "type": "object" } } }, "Envelope": { "type": "object", "properties": { "success": { "type": "boolean" }, "platform": { "type": "string" }, "endpoint": { "type": "string" }, "data": { "type": "object", "properties": { "total": { "type": "integer" }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/Item" } }, "cursor": { "type": [ "string", "null" ] } } }, "credits_used": { "type": "integer" }, "credits_remaining": { "type": "integer" }, "request_id": { "type": "string" } } }, "ErrorEnvelope": { "type": "object", "x-error-types": [ { "type": "BAD_REQUEST", "status": 400, "what": "The request was understood but rejected; the message says why (a bad Content-Length, a refused email address)." }, { "type": "EMAIL_NOT_ACCEPTED", "status": 400, "what": "Disposable email domains cannot sign up. Use a real mailbox; the free credits are the same." }, { "type": "NO_PENDING_CODE", "status": 400, "what": "Sign-in: no code was requested for this address, or it was already used. Request a new one." }, { "type": "CODE_EXPIRED", "status": 400, "what": "Sign-in: the code is older than its lifetime. Request a new one." }, { "type": "INVALID_CODE", "status": 400, "what": "Sign-in: wrong code. The body carries attempts_left; the same code stays valid until it expires or the guesses run out." }, { "type": "TOO_MANY_ATTEMPTS", "status": 400, "what": "Sign-in: too many wrong guesses for this code or from this address. Request the code again after the cooldown, or wait for it to expire." }, { "type": "MISSING_API_KEY", "status": 401, "what": "No x-api-key header on a platform endpoint. There is no anonymous tier: send your key on every request." }, { "type": "UNAUTHORIZED", "status": 401, "what": "The credential for this operation is missing, unknown, expired or revoked: a key on account and billing operations, a browser session on key management, the owner key on admin routes." }, { "type": "NO_CREDITS", "status": 402, "what": "The account's credits are used up. Top up; nothing is queued and nothing is deleted, and the same key keeps working after payment." }, { "type": "INVALID_API_KEY", "status": 403, "what": "The key is unknown, rotated away or revoked. Create or rotate one in the dashboard." }, { "type": "OTP_SIGNIN_REQUIRED", "status": 403, "what": "This browser session came from an API key (browser-link) and cannot create, rotate or revoke keys. Sign in with the emailed code." }, { "type": "UNKNOWN_ENDPOINT", "status": 404, "what": "No such route. GET /v1/status lists the platforms; the reference lists every path." }, { "type": "NOT_FOUND", "status": 404, "what": "No such key or order on this account." }, { "type": "ORDER_MISMATCH", "status": 409, "what": "The payment did not match the order. Nothing was credited; operators are alerted and will sort it out." }, { "type": "KEY_LIMIT", "status": 409, "what": "The account already holds the maximum number of keys. Delete one first." }, { "type": "LENGTH_REQUIRED", "status": 411, "what": "Send a Content-Length header; chunked request bodies are not accepted." }, { "type": "PAYLOAD_TOO_LARGE", "status": 413, "what": "The request body is over the limit the message states." }, { "type": "VALIDATION_ERROR", "status": 422, "what": "A parameter or body field is missing, malformed or out of range. The message names it; fix, when present, shows a working example." }, { "type": "ALL_SOURCES_FAILED", "status": 424, "what": "Every source for that platform failed on this call. You are not charged. Retry later or use another platform." }, { "type": "UPSTREAM_ERROR", "status": 424, "what": "The source answered with an error we could not work around. You are not charged. Retry later." }, { "type": "RATE_LIMITED", "status": 429, "what": "Over the per-key limit (wait the Retry-After seconds, then retry), or over a daily cap on sign-in codes, dashboard links or checkouts (no Retry-After; the cap resets the next day). Nothing was charged and nothing is queued." }, { "type": "INTERNAL", "status": 500, "what": "Unexpected error on our side; it has been logged. Retry; tell us if it persists." }, { "type": "NOT_CONFIGURED", "status": 501, "what": "That platform or upstream is not configured on this deployment. Tell us." }, { "type": "CHECKOUT_UNAVAILABLE", "status": 503, "what": "Checkout could not be started just now. Nothing was charged; retry in a minute." } ], "properties": { "success": { "type": "boolean", "const": false }, "endpoint": { "type": "string" }, "error": { "type": "object", "required": [ "type", "message", "status", "docs_url" ], "properties": { "type": { "type": "string", "enum": [ "BAD_REQUEST", "EMAIL_NOT_ACCEPTED", "NO_PENDING_CODE", "CODE_EXPIRED", "INVALID_CODE", "TOO_MANY_ATTEMPTS", "MISSING_API_KEY", "UNAUTHORIZED", "NO_CREDITS", "INVALID_API_KEY", "OTP_SIGNIN_REQUIRED", "UNKNOWN_ENDPOINT", "NOT_FOUND", "ORDER_MISMATCH", "KEY_LIMIT", "LENGTH_REQUIRED", "PAYLOAD_TOO_LARGE", "VALIDATION_ERROR", "ALL_SOURCES_FAILED", "UPSTREAM_ERROR", "RATE_LIMITED", "INTERNAL", "NOT_CONFIGURED", "CHECKOUT_UNAVAILABLE" ], "description": "Stable machine code; the complete list is x-error-types on this schema" }, "message": { "type": "string" }, "status": { "type": "integer" }, "fix": { "type": "string", "description": "What to do about it, present when there is a specific step to take (a working example, a top-up link, a retry delay); absent otherwise" }, "docs_url": { "type": "string" } } }, "credits_used": { "type": "integer", "const": 0 }, "request_id": { "type": "string" } } } } } } ```