Threads Public Data API | SandBase
Read public Threads profiles, posts, replies, and search with one REST API. No Threads login, no SDK — one SandBase key, built for agent workflows.

Threads is Meta’s fast-growing text conversation network, and its public profiles, posts, and replies map directly onto brand monitoring, creator research, and social listening. Getting at it programmatically usually means reverse-engineering the app, managing tokens, and rebuilding a scraper every time the app changes.
The SandBase Threads public data API removes that setup tax. It reads public Threads profiles, posts, replies, and search through plain REST endpoints — one SandBase API key, no Threads login and no SDK. The endpoint API reference is the source of truth for each parameter and for the response envelope; the business-payload field names shown below are an illustrative shape, not a guaranteed schema, so confirm them against a live response for the endpoint you call.
This is not Meta’s official Threads API. Use Meta’s official APIs when you need authenticated member actions, posting, or a licensed data agreement. Use SandBase when your workflow needs public, read-only data for research and monitoring. Ready to try it? Get a SandBase API key and browse the Threads endpoints.
Key takeaway
- One API reads public Threads profiles, posts, replies, reposts, and search.
- The Model API endpoints documented here are called with
POST /v1/api/threads/<path>— pass only that endpoint’s params, no SDK, oneSANDBASE_API_KEY.- Endpoints key off natural identifiers: a
usernameresolves a profile, then itsuser_id(thepk/idfromuser-info) drives post and reply reads, and apost_iddrives comment reads.- It returns public, read-only data only. There is no posting, no platform login on your side, and no private data; authenticate with a SandBase API key.
Which Threads API do you need?
| Your need | Choose | Why |
|---|---|---|
| Post, act as a member, or use account-authorized data | Meta’s official Threads API | Member and account operations run through Meta directly. |
| Read public profiles, posts, replies, or search | SandBase Threads public-data API | Plain REST, one SandBase key, structured JSON for read-only workflows. |
| Private or account-only data | Neither public workflow | That data is out of scope for this public-data guide. |
What you can get from the Threads API
The catalog is organized on a web surface. Grouped by job:
- Profiles — public profile info by
username(or by id), including bio, follower count, and verified status. - Posts & replies — a user’s posts, replies, and reposts, plus a single post’s detail and its comments.
- Search — profile search, plus top and recent post search by keyword.
Availability differs by endpoint, and some upstream reads can be intermittent — treat each endpoint’s live API reference as the source of truth and confirm availability before you build on a specific one.
The Threads API page on SandBase — a tagged overview and the endpoint list, each with its path.
What Threads provides vs. what SandBase adds
Public data comes from Threads. SandBase does not own or operate Threads; it provides a uniform API layer for eligible public-data workflows. Each capability becomes one documented endpoint, auth collapses to a single key, and responses come back as predictable JSON — so an agent can chain “read a profile → read its posts → pull a post’s comments” along one convention instead of maintaining a scraper.
Quick start: your first call
SandBase exposes more than one API surface. The catalog may show GET paths under /apis/v1/...; this guide uses the vendor-qualified Model API path on each endpoint’s API reference. Do not swap the HTTP method or URL — follow the reference for the endpoint you choose.
Read a public profile by username:
import os
import requests
resp = requests.post(
"https://api.sandbase.ai/v1/api/threads/web/user-info",
headers={
"Authorization": f"Bearer {os.environ['SANDBASE_API_KEY']}",
"Content-Type": "application/json",
},
json={"username": "zuck"},
)
resp.raise_for_status()
body = resp.json()
if body.get("status") != "completed":
error = body.get("error", {})
raise RuntimeError(error.get("message", "Threads request did not complete"))
# The reference guarantees the envelope (id/status/model/outputs[0].data);
# business fields vary by endpoint, so read defensively and confirm
# the exact paths against a live response.
data = body["outputs"][0]["data"]
user = data.get("user", {})
print(user.get("full_name"), user.get("follower_count"), user.get("is_verified"))
curl -X POST https://api.sandbase.ai/v1/api/threads/web/user-info \
-H "Authorization: Bearer $SANDBASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"username": "zuck"}'
Responses share the same envelope: an id, a status, the model name, and — for a completed run — an outputs array whose single item carries the payload under data. A completed run carries outputs; a failed or timeout run carries error and no outputs. That envelope is what the endpoint reference guarantees; here the profile object nests under a user key, and the operation-specific fields inside are documented per endpoint. Branch on status before reading outputs[0].data, and check each endpoint’s reference for its run mode. The block below is my tested response, tested on 2026-09-27 (UTC) — field names and values can change over time, so confirm them against a live response:
{
"id": "77059cb9-8616-4be1-abfe-96e82a12b54f",
"status": "completed",
"model": "threads/web/user-info",
"outputs": [
{
"data": {
"user": {
"full_name": "Mark Zuckerberg",
"biography": "Mostly superintelligence and MMA takes",
"follower_count": 5744972,
"is_verified": true,
"bio_links": [],
"id": "63055343223",
"pk": "63055343223"
}
}
}
]
}
A failed or timeout run carries error and never outputs. Response shapes differ by endpoint — inspect one real response and map the exact path per endpoint.
The endpoint API reference is the source of truth for each parameter name and response path.
Capability map
| Capability cluster | Representative endpoint | Typical use |
|---|---|---|
| Profile | threads/web/user-info | Public profile signals by username |
| Posts | threads/web/user-posts | Read a user’s posts by user_id (optional end_cursor) |
| Replies | threads/web/user-replies | Read a user’s replies by user_id (optional end_cursor) |
| Post comments | threads/web/post-comments | Engagement and sentiment inputs by post_id (optional end_cursor) |
| Search | threads/web/search-profiles | Creator and topic discovery by query |
Paging differs by endpoint — several endpoints accept a per-endpoint cursor request parameter. Read each endpoint’s schema, and confirm the endpoint is available before you build on it.
A slice of the Threads endpoint list on the web surface.
Chaining calls in an agent workflow
Because the endpoints documented here share the same auth and the same response envelope, an agent can walk from a profile to a post’s comments without special-casing each surface. A common social-listening pattern looks like this:
- Read the profile. Call
threads/web/user-infowith ausernameto get bio, follower count, verified status, and the profile’spk/id. - Read the posts. Take the
pk/idfrom step 1 and callthreads/web/user-postswith it asuser_id(optionalend_cursorfor paging) to read the user’s recent posts. Confirm availability against the reference first — this upstream read can be intermittent. - Read the comments. Call
threads/web/post-commentswith apost_id(optionalend_cursor) to gather a post’s replies as engagement inputs.
Each step returns the same envelope, so your agent branches on status once and reuses the same JSON-reading code across every step. A completed run carries outputs; a failed or timeout run carries error and no outputs.
Common use cases
Threads profile API for creator research
Call threads/web/user-info with a username to read bio, follower count, verified status, and bio links. Input: a username. Output: a profile record under user. Endpoint: user-info.
Threads posts API for content monitoring
First resolve the profile with threads/web/user-info (a username) to get its pk/id, then read threads/web/user-posts for the user’s recent posts. Input: a user_id (the pk/id from user-info), plus an optional end_cursor for paging. Output: a list of posts. Endpoint: user-posts. Confirm availability against the reference before building on it — this upstream read can be intermittent.
Threads search API for discovery
Run threads/web/search-profiles with a keyword to surface creators around a niche. Input: a keyword. Output: matching profiles. Endpoint: search-profiles.
Why run this at the API layer
You could point a headless browser at Threads and parse the app’s payloads, but that path is fragile: the app changes, tokens rotate, and you maintain a scraper instead of shipping features. Reading through one uniform API means your code depends on named JSON fields and a single response envelope rather than an app internal. Auth is one key, and because the endpoints documented here return the same envelope — a completed run carries outputs, while a failed or timeout run carries error and no outputs — retries, logging, and error handling live in one helper you write once and reuse everywhere.
That uniformity is what makes the workflow composable for an agent. Swap one username for another, and the code path is identical. Add a second read — a user’s replies, say — and it slots in behind the same status-checking helper. The practical payoff is that your time goes to what the data means for your research, not to keeping a scraper alive against a moving target. When you need more than single reads, check the live listing for the endpoint that fits and confirm its parameters — and its current availability — before wiring it in.
Limitations and boundaries
- Public, read-only data only. No posting, following, or private/account-only data.
- Rate and volume. Treat responses as best-effort reads; as a client-side resilience measure, retry with backoff on transient errors such as HTTP 429 or an intermittent upstream error.
- Parameters and shapes follow the upstream surface. Identifiers vary:
user-infotakes ausername,user-posts/user-repliestake auser_id(thepk/idfromuser-info),post-commentstakes apost_id, andsearch-profilestakes aquery; paging is a per-endpointend_cursor. The profile payload nests underuser. Inspect a real response and read the schema first. - Verify endpoints against the live reference. Availability and fields can change, and some post/search reads can be intermittent; confirm before building on a specific endpoint.
- This is not an official Meta partnership. SandBase provides uniform access to public data; respect Threads’ terms and applicable rules for your use case.
FAQ
Do I need a Threads or Meta login?
No. You authenticate to SandBase with your SANDBASE_API_KEY. These read endpoints do not require a Threads account or OAuth on your side.
What identifies a profile or a post?
A username identifies a profile for user-info, which returns the profile’s pk/id. Use that value as the user_id for user-posts and user-replies. A post_id identifies a single post’s comments for post-comments, and search-profiles takes a query.
Why does the profile nest under user?
The user-info payload wraps the profile in a user object, with fields such as full_name, biography, follower_count, and is_verified. Read data["user"] defensively and confirm the fields against a live response.
Can I read private or account-only data? No. The API returns public data only. Private and account-authorized content are out of scope.
Start with a profile read
Create a SandBase API key, call user-info, and inspect the returned schema before you expand to posts, replies, or search. When you are ready: