Threads
Threads User Replies API
Read what a Threads account replies to, as JSON - the reply text and engagement plus the post it answers, cursor-paginated. Costs 2 credits per page addressed by user_id and 4 addressed by username, and that surcharge repeats on EVERY page. Every reply arrives with its parent thread in the same array, so filter on user.user_id to separate the account's own words from the posts it was answering.
Authorizations
AuthorizationstringheaderrequiredBearer authentication header of the form Bearer <token>, where <token> is your Scavio API key (e.g. Bearer sk_live_your_key).
Body
application/jsonuser_idstringNumeric Threads user id. The cheap path: 2 credits per page. Get one from Threads User Search, from Threads Profile, or from the user block on any post you already hold. Keep it - it is also the value you filter the response on.
Example: 63269174602
usernamestringThreads handle without the leading @, 1 to 60 characters. Costs 4 credits per page instead of 2, because the upstream handle lookup is dead and the id has to be resolved through people search on every single call. Provide user_id or username; sending neither is rejected. Sending both bills the cheap rate and ignores the handle.
Example: natgeo
cursorstringOpaque pagination cursor. Omit it for the first page, then pass back the next_cursor value from the previous response. Stop when next_cursor is null - do not loop on has_more.
Request
from scavio import ScavioClient
client = ScavioClient(api_key="sk_live_your_key")
USER_ID = "63269174602" # 2 credits a page; a handle costs 4
cursor = None
while True:
page = client.threads.user_replies(user_id=USER_ID, cursor=cursor)
rows = page["data"]["posts"]
for i, row in enumerate(rows):
if row["user"]["user_id"] != USER_ID:
continue # a thread they answered, not their reply
parent = rows[i - 1] if i else None
print(row["text"], "->", parent["text"] if parent else None)
cursor = page["data"]["next_cursor"]
if not cursor: # null means no further page exists
breakResponse