Getting a long-lived Threads access token sounds like a 10-minute job. It took me an evening, and every wall I hit turned out to be a known one. Here they all are, in the order you'll probably meet them — same error codes and wording you'll see on screen.
1. You're on the wrong Meta site (it wants a credit card)
If you land on a console called "Meta Model API" saying "No payment method on file. Add one to make API requests" — close it. That's Meta's paid Llama inference service, not the Threads API. The Threads API is free and lives at developers.facebook.com → My Apps → Create App → Threads API access use case.
2. "Cannot parse access token" (code 190)
{"error":{"message":"Invalid OAuth access token - Cannot parse access token","code":190}}
The token string reaching Meta isn't what you think you sent. Usual suspects:
- Template braces left in the URL:
access_token={YOUR_TOKEN}— the{ }must go - Drag-selected the token and missed characters (they're hundreds of chars — use the copy button)
- A line break from pasting through a notes app
Paste the token into a plain-text editor first. One unbroken line, no braces.
3. "Session key invalid" (code 452) on token exchange
{"error":{"message":"Session key invalid...","code":452,"error_subcode":4279019}}
The trap: your app's Basic Settings page shows two ID/secret pairs — the regular App ID/Secret on top, and Threads App ID / Threads App Secret below. Threads endpoints only accept the Threads pair. A Threads token + the regular app secret = error 452 forever, no matter how many fresh tokens you generate.
Sanity-check the token itself with a call that needs no secret:
curl "https://graph.threads.net/v1.0/me?fields=id,username&access_token=YOUR_TOKEN"
If that returns your username, the token is fine — your secret was the problem.
4. You may not need the token exchange at all
Every guide says: short-lived token → exchange via th_exchange_token → 60-day token. True for full OAuth apps. But if you're automating your own account: the User Token Generator in your app's use-case settings issues long-lived tokens directly for accounts added as Threads testers. No exchange, no secret needed. (Trying to exchange an already-long-lived generator token is another way to get error 452.)
5. "Object with ID does not exist" when posting
The API doesn't know your @handle. Every endpoint wants your numeric user ID:
curl "https://graph.threads.net/v1.0/me?fields=id,username&access_token=YOUR_TOKEN"
# → {"id":"1784xxxxxxxxxxx","username":"yourhandle"}
Use that id everywhere. It never changes.
6. Token generator missing your account
Until an app passes review, only accounts added as Threads testers can authorize it — and the invite must be accepted from inside Threads: Settings → Account → Website permissions. For a bot posting to your own account, tester mode is all you'll ever need; the app can stay unpublished forever.
7. Everything works — for exactly 60 days
Long-lived tokens expire after 60 days, and your bot dies quietly on day 61. Either set a calendar reminder (~55 days, regenerate, replace the secret — 5 minutes), or automate the refresh (works on tokens older than 24h):
curl "https://graph.threads.net/refresh_access_token?grant_type=th_refresh_token&access_token=CURRENT_TOKEN"
Bonus: log the body, not the status code
Python's requests (and most HTTP libs) raise "400 Bad Request" and discard the response body — where Meta puts the actual reason:
if not resp.ok:
print(resp.text) # ← the actual error lives here
resp.raise_for_status()
Every error above was diagnosed from that body.
I hit all of these building a bot that runs my own Threads account end to end — a GitHub Action writes one post a day, a second model pass reviews the draft, and it publishes through this API. The account is public if you want to judge the output: threads.com/@hyoj.unlim. The whole pipeline is packaged as a $39 self-hosted kit here, and this article is also a free PDF on Gumroad.
Top comments (0)