Get Threads posting credentials¶
Let keryx auth threads capture a token so keryx publish can post a
text-and-image announcement to a Threads account (spec 0060 D15). Threads
lives on the same Meta app as Instagram and Facebook but, like Instagram
Login, its use case mints an app id and secret of its own; the Meta app's
id and the Instagram pair are both rejected. Ten minutes.
1. Add the Threads use case¶
In the app dashboard: Use cases → Add use cases → Access the Threads API (the name varies slightly). Once added, open it and:
- Under its Settings, note the Threads app ID and Threads app
secret.
platforms.threads.app_id(config, non-secret) andTHREADS_APP_SECRET(environment, never committed). - Add the loopback redirects keryx uses, the same six as Instagram:
https://localhost:3764/…https://localhost:3769/. - Under its Permissions, make
threads_basicandthreads_content_publishavailable. - Under Roles, add the Threads account as a Threads Tester while the app is in development, and accept the invitation in the Threads app (Settings → Account → Website permissions → Invites).
2. Sign keryx in¶
It opens the consent window (or prints the URL), captures the code on the
https loopback, swaps it for a short-lived token, that for a 60-day one,
and stores the token (keychain, else the accounts file) with its expiry and
platforms.threads.{user_id,enabled,redirect_uri}. In CI,
THREADS_ACCESS_TOKEN in the environment is the token.
3. What a post looks like there¶
- Text, with the hashtags on a new line, held to 500 characters together.
- Without an image: a text post with the link as a link attachment, which Threads renders as a card; the URL does not count against the 500.
- With an image: an image post. Threads fetches the JPEG or PNG (under 8
MB) from its public URL, so the article must be live and
announce.public_base_urlset. A link attachment is not allowed with media, so the link is written into the text and counts. - Alt text is sent when the post has it. No video.
Refresh¶
The 60-day token refreshes in place: keryx auth refresh exchanges it once
it is within 20 days of expiry and records the new expiry; a token under 24
hours old cannot be refreshed, which is why it waits.