Threads API 自動發文教學 2026:從申請 App、拿 Token 到排程發文(附 Node.js 程式碼)
目錄
一句話先回答:Threads API 自動發文分五步:①在 Meta 開發者平台建一個 Threads 用途的 App;②讓你的 Threads 帳號接受「測試者」邀請;③走 OAuth 拿短效 Token,立刻換成 60 天長效 Token;④發文是兩段式,先 POST /{user-id}/threads 建立容器,再 POST /{user-id}/threads_publish 發布;⑤API 沒有排程功能,要自己用 cron 或排程工具在指定時間呼叫。每個帳號 24 小時最多 250 篇 API 發文、文字上限 500 字。
下面每一段程式碼都來自 MindThread 線上正在跑的版本,不是照文件抄的範例。MindThread 用這套 API 幫上百個 Threads 帳號自動發文,踩過的坑我會直接寫出來。
如果你不想寫程式、只想要「排程好就自動發」,可以直接跳到文末的「不想自己架」一節。這篇是給想自己接 API 的人。
先搞懂 Threads API 的三個基本事實
1. 它是 Meta 的官方 API,網域是 graph.threads.net。跟 Instagram Graph API 是兩套,App ID 和 App Secret 也是分開的。建 App 的時候會看到兩組 ID,Threads API 要用標的是 Threads 的那組。
2. 發文是「兩段式」。你不能一個請求就把文發出去,要先建立一個「媒體容器」(media container)拿到 creation_id,再用這個 id 去發布。文字文中間等幾秒就夠,影片要輪詢容器狀態等它處理完。
3. 限額是滾動 24 小時。官方數字:每個 Threads 帳號在 24 小時滾動區間內最多 250 篇 API 發文、1,000 則回覆。文字上限 500 字。這個限額是按帳號算,不是按 App 算。
第一步:在 Meta 開發者平台建 Threads App
- 到 developers.facebook.com 建立新 App,用途選 Threads(Meta 官方叫 Threads Use Case)。
- 建好後到 App Dashboard,找 Threads 的設定頁,記下 Threads App ID 與 Threads App Secret。再說一次:這是 Threads 專用的那組,不是 Facebook App 那組。
- 設定 Redirect URI(OAuth 回呼網址)。本機開發可以先填
https://localhost:3000/callback之類的,正式環境要填真實網址,而且必須是 HTTPS。
權限(scope)要哪些
自動發文最少需要兩個:
threads_basic:讀取自己的基本資料與貼文threads_content_publish:發文
這兩個是自動核發的,不用送 App Review。如果你還要自動回覆、讀留言、看洞察數據,才需要 threads_manage_replies、threads_read_replies、threads_manage_insights 等,這些要送審才能對一般使用者生效。
MindThread 的做法是把所有用到的 scope 集中寫在一個常數裡,並加註「這是 App Review 送審的唯一來源」。原因是曾經在程式裡多用了一個權限卻忘了加進授權清單,結果使用者授權完、新功能靜默回 401。
// 自動核發(不用送審):threads_basic, threads_content_publish
// 其餘都要送審
const SCOPES = 'threads_basic,threads_content_publish'
第二步:讓你的 Threads 帳號接受「測試者」邀請
這一步是最多人卡住的地方。App 還在開發模式時,只有被加為 Threads 測試者 的帳號能用 API。
- App Dashboard → App roles → Roles → Add People → 選 Threads Tester,填你的 Threads 帳號。
- 用那個 Threads 帳號登入 Threads(網頁或 App 都可以),到 帳號設定 → 網站權限(Website permissions),會看到一個待接受的邀請,按接受。
沒做第 2 步,後面 OAuth 流程會一路看起來正常,到真正發文時才回「沒有權限」。
第三步:OAuth 授權,拿 Token
3a. 把使用者導去授權頁
https://www.threads.net/oauth/authorize
?client_id={THREADS_APP_ID}
&redirect_uri={REDIRECT_URI}
&scope=threads_basic,threads_content_publish
&response_type=code
&state={隨機字串,防 CSRF}
state 一定要帶,而且回來時要驗。MindThread 用 HMAC 簽過的字串,回呼時驗簽名與時效。我們曾把時效設成 10 分鐘,結果在授權頁猶豫太久的使用者回來就被當成攻擊擋掉,後來放寬到 45 分鐘。
3b. 用 code 換短效 Token(1 小時)
const res = await fetch('https://graph.threads.net/oauth/access_token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: THREADS_APP_ID,
client_secret: THREADS_APP_SECRET,
grant_type: 'authorization_code',
redirect_uri: REDIRECT_URI,
code,
}),
})
const { access_token: shortToken, user_id } = await res.json()
3c. 立刻換成 60 天長效 Token
短效 Token 只活 1 小時,拿到就要換,別存短效的。
const params = new URLSearchParams({
grant_type: 'th_exchange_token',
client_secret: THREADS_APP_SECRET,
access_token: shortToken,
})
const res = await fetch(`https://graph.threads.net/access_token?${params}`)
const { access_token: longToken, expires_in } = await res.json()
// expires_in 是秒數,約 60 天;把到期時間存起來,後面要續期
3d. 到期前續期
const params = new URLSearchParams({
grant_type: 'th_refresh_token',
access_token: currentLongToken,
})
const res = await fetch(`https://graph.threads.net/refresh_access_token?${params}`)
const { access_token: newToken, expires_in } = await res.json()
自動發文中斷最常見的原因就是忘了續期。MindThread 的做法是每天跑一支排程,把 7 天內要到期的 Token 全部續一輪,而且續期失敗要寫回資料庫標記,不然你會以為帳號還活著,其實它已經發不出文了。
第四步:發文(兩段式)
這是 MindThread 線上發文字文的函式,幾乎原樣貼上:
const THREADS_API = 'https://graph.threads.net/v1.0'
async function publishTextPost(threadsUserId: string, accessToken: string, text: string) {
// 第一段:建立媒體容器(草稿)
const createRes = await fetch(`${THREADS_API}/${threadsUserId}/threads`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
media_type: 'TEXT',
text,
access_token: accessToken,
}),
})
if (!createRes.ok) {
const err = await createRes.json().catch(() => ({}))
throw new Error(`建立容器失敗 ${createRes.status}: ${err?.error?.message}`)
}
const { id: creationId } = await createRes.json()
// 等幾秒讓伺服器把容器處理好(文字文 3 秒足夠)
await new Promise(r => setTimeout(r, 3000))
// 第二段:發布
const publishRes = await fetch(`${THREADS_API}/${threadsUserId}/threads_publish`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
creation_id: creationId,
access_token: accessToken,
}),
})
if (!publishRes.ok) {
const err = await publishRes.json().catch(() => ({}))
throw new Error(`發布失敗 ${publishRes.status}: ${err?.error?.message}`)
}
return publishRes.json() // { id: 貼文 id }
}
幾個細節:
threadsUserId是你在 3b 拿到的user_id,也可以用me代替。- 兩個請求都用
application/x-www-form-urlencoded,不是 JSON。 - 錯誤訊息在
error.message,一定要印出來,Meta 的錯誤碼本身沒什麼資訊量。
圖片文
把 media_type 改成 IMAGE,多帶 image_url(必須是公開可抓的 HTTPS 網址),其餘一樣,等 3 秒再發布就行。
body: new URLSearchParams({
media_type: 'IMAGE',
image_url: imageUrl,
text,
access_token: accessToken,
})
影片文:不能固定等幾秒,要輪詢
影片上傳後 Meta 要轉檔,時間不固定。固定等 3 秒會間歇性失敗,這是我們實際踩過的。正確做法是輪詢容器狀態直到 FINISHED:
async function waitForContainerReady(creationId: string, accessToken: string) {
const deadline = Date.now() + 120_000
await new Promise(r => setTimeout(r, 5000))
while (Date.now() < deadline) {
const res = await fetch(
`${THREADS_API}/${creationId}?fields=status,error_message&access_token=${encodeURIComponent(accessToken)}`
)
const { status, error_message } = await res.json()
if (status === 'FINISHED') return
if (status === 'ERROR' || status === 'EXPIRED') {
throw new Error(`影片容器 ${status}: ${error_message || '無細節'}`)
}
await new Promise(r => setTimeout(r, 3000)) // IN_PROGRESS,繼續等
}
throw new Error('影片容器 120 秒內未完成')
}
容器狀態有五種:IN_PROGRESS、FINISHED、ERROR、EXPIRED、PUBLISHED。建立容器時 media_type 用 VIDEO、參數帶 video_url。
第五步:排程。API 沒有,要自己做
Threads API 沒有「預約在某個時間發」的功能,官方文件只提醒你「如果你的 App 允許使用者排程,請自己遵守發文限額」。所以排程是你的事:
| 做法 | 適合誰 | 要注意 |
|---|---|---|
| 系統 cron / systemd timer | 自己的一兩個帳號 | 機器要一直開著;Token 續期也要排進去 |
| Vercel Cron / Cloudflare Cron Triggers | 已經在用 serverless 的人 | 函式有執行時間上限,影片輪詢要小心 |
| n8n / Make | 不想寫程式但能拉流程的人 | 一樣要自己處理去重與 Token |
| MindThread 這類現成工具 | 多帳號、要穩定 | 排程、去重、續期、失敗重試都做好了 |
不管用哪種,有三件事一定要做:
- 記錄已發過的內容。排程器重跑或重試時,沒有去重就會重複發文,這在 Threads 上很傷帳號。
- 自己數每日發文數,別等 API 回你限額錯誤。
- 失敗分兩類處理:網路逾時、5xx 這種暫時性錯誤可以退避重試;權限錯誤、Token 失效這種要停下來通知人,重試只會一直錯。
常見錯誤速查
| 症狀 | 多半是 |
|---|---|
| 授權流程正常,發文時回沒有權限 | Threads 帳號沒接受測試者邀請 |
| 一小時後全部失敗 | 存了短效 Token,沒換長效 |
| 60 天左右突然失敗 | 長效 Token 沒續期 |
| 影片文間歇性失敗、文字文正常 | 用固定等待秒數,要改成輪詢容器狀態 |
| 圖片文失敗 | image_url 不是公開 HTTPS,或圖片太大、格式不支援 |
| 一天發到一半開始全錯 | 撞到 250 篇滾動限額 |
不想自己架?
上面這套 MindThread 已經做成產品:接上 Threads 帳號、設好時段、把內容丟進去,排程、去重、Token 續期、失敗重試、多帳號管理都在裡面,而且有免費方案可以先用。懶人路線看這篇:脆自動發文與排程完整攻略;想比較市面工具看這篇:Threads 自動發文工具比較。
如果你要的是「自動在別人貼文下留言、按讚」那種互動,那不是 Threads API 能做的(留言要送審的權限,而且 API 不提供瀏覽動態),請看 Threads 自動回覆與留言巡邏。
本文程式碼來自 MindThread 線上版本,截至 2026 年 8 月有效。Meta 改 API 時我們會更新這篇;限額與權限名稱請以 Meta 官方 Threads API 文件 為準。
常見問題
Threads API 可以免費用嗎?
可以。Threads API 本身不收費,只要到 Meta 開發者平台建一個 Threads 用途的 App 就能開始。自己的帳號走「Threads 測試者」流程,不用送審就能發文。限制是每個帳號 24 小時內最多 250 篇 API 發文、1,000 則回覆。
Threads API 有排程發文功能嗎?
沒有。API 只提供「現在發」,排程要自己做:用 cron、n8n、Vercel Cron 之類的排程器在指定時間呼叫發文端點,並自己記錄已發過的內容避免重複。不想自己架的話,MindThread 這類工具已經把排程、去重、Token 續期做好了。
Threads 的 Access Token 多久過期?
OAuth 換到的短效 Token 只有 1 小時,要立刻用 th_exchange_token 換成 60 天的長效 Token,之後每隔不到 60 天用 th_refresh_token 續期一次。忘記續期是自動發文中斷最常見的原因。
為什麼我呼叫 Threads API 回傳沒有權限?
最常見是你的 Threads 帳號還沒接受測試者邀請。在 Meta App 後台加了測試者之後,必須用那個 Threads 帳號登入 Threads,到「帳號設定」裡的「網站權限」接受邀請,API 才會放行。