Meta access tokens: Instagram, Facebook Page and Threads
Meta access tokens for Instagram, Facebook Pages and Threads: what Meta's own code and Postman collections show, and the token lifetimes they leave unstated.
An Instagram long-lived access token is the token your app stores to keep calling the API after the person has logged in, but Meta's public GitHub sources (its Postman collections, SDKs and sample apps) contain no Instagram request to get or refresh one, and they state no lifetime for any Instagram token. What they do show in full is the Threads chain: code, short-lived token, long-lived token with an example expires_in of 60 days, then refresh. For Facebook Login they show how a user token becomes a Page access token.
This guide belongs to Meta API use cases: which one your app needs. The sections under the table name the Meta file behind each row, and the gaps are marked as gaps.
What this means for you
A scheduling tool connected to your Instagram, Facebook Page or Threads account holds a token that lets it post for you. Tokens expire or stop working, and then you have to connect the account again. Reconnecting runs the login once more, which gives the tool a new token.
The network pages for Instagram, Facebook and Threads list every API change we track for each.
The details: Instagram long-lived access token and other Meta tokens
Meta access token types, side by side
| Token | How your code gets it in Meta's GitHub | Used on | Lifetime in Meta's GitHub | Refresh in Meta's GitHub |
|---|---|---|---|---|
| Instagram User access token (Instagram Login) | From Business Login for Instagram; no request in the collection | graph.instagram.com | Not stated | None |
| Facebook User access token | POST /oauth/access_token with the login code | graph.facebook.com | Not stated | None |
| Facebook Page access token | GET /me/accounts with the user token | graph.facebook.com | Not stated | None |
| Threads short-lived user token | POST /oauth/access_token, grant_type=authorization_code | Threads host | Not stated | Exchange it for a long-lived one |
| Threads long-lived user token | GET /access_token, grant_type=th_exchange_token | Threads host | expires_in 5,184,000 seconds (60 days) in an example response | GET /refresh_access_token, grant_type=th_refresh_token |
| Threads app access token | GET /oauth/access_token, grant_type=client_credentials | Threads host | Not stated | None |
| System user access token | POST /{business-id}/system_user_access_tokens | graph.facebook.com | An option to expire in 60 days; otherwise not stated | None |
The Instagram token: what Meta's sources show
Meta's Instagram Platform Postman collection lists one token for the Instagram API with Instagram Login: the Instagram User access token. It appears in the requirements for publishing, comments, messaging and insights, each time on graph.instagram.com with Business Login for Instagram. Several sections add that it must be "requested from a person who can manage" messages (or, in one section, comments) on the professional account.
The collection sets that token as a bearer token for every request, and its sample calls send it either as an access_token query parameter or in an Authorization: Bearer header.
What the collection doesn't have, on either login path: a request that exchanges a login code, swaps a short-lived token for a long-lived one, or refreshes a token. We checked the current file and every earlier version of it in the repository's history, plus Meta's Python Business SDK (v26.0.4). None of them has an Instagram exchange or refresh call. So this page can't give you the Instagram refresh endpoint, how soon a token may be refreshed, or how long it lasts. Take those from Meta's Business Login documentation, and store the expires_in your own exchange returns instead of hard-coding a number.
Two things from our changelog matter for older code:
- Guides about the "Instagram Basic Display long-lived token" describe an API that has returned errors since December 4, 2024.
- Instagram Login apps must request the
instagram_business_*scopes; the old values were deprecated on January 27, 2025.
For which login gives which token, see Instagram Login or Facebook Login.
Facebook Page access token
On the Facebook Login path, your app starts with a Facebook User access token and trades it for Page tokens. Meta's Facebook Reels sample shows the whole flow:
- Send the person to the OAuth dialog with
response_type=codeand your scopes. - Exchange the code:
POST https://graph.facebook.com/oauth/access_tokenwithclient_id,redirect_uri,client_secretandcode. The response'saccess_tokenis the user token. - Call
GET /me/accountswith that token. Each Page in the response carries its ownaccess_token. - Publish to the Page with that Page token.
Meta's Instagram collection does step 3 with fields=name,access_token,tasks,instagram_business_account and describes the result as a "Page Access Token, which acts on behalf of a Page that is linked to an Instagram profile". If you already have the Page ID, it requests GET /{page-id}?fields=name,access_token,instagram_business_account instead. Its Facebook Login reels requests then publish with that Page token, while its insights section asks for the Facebook User access token. In the Python Business SDK the same edge is User.get_accounts (/accounts), and access_token is a field on the Page object.
Neither the Reels sample nor the collection swaps the user token for a long-lived one before reading Page tokens, and neither says how long a Page token lasts.
Threads long-lived token: exchange and refresh
The Threads API is the one Meta path where its GitHub shows the whole exchange and refresh sequence. The Postman collection's Authorization folder has all four calls, and the sample app runs the first three:
1. https://www.threads.net/oauth/authorize?response_type=code&client_id=...&redirect_uri=...&scope=...
2. POST /oauth/access_token
client_id, client_secret, code, grant_type=authorization_code, redirect_uri
-> { "access_token": "...", "user_id": "..." } (short-lived)
3. GET /access_token?grant_type=th_exchange_token&client_secret=...&access_token=<short-lived>
-> { "access_token": "...", "token_type": "bearer", "expires_in": 5184000 }
4. GET /refresh_access_token?grant_type=th_refresh_token
(sent with the unexpired long-lived token)
- Step 2: the collection calls the result a short-lived access token and says the
redirect_urimust be the same URI you sent to the authorization window, "or the request will be rejected". - Step 3: 5,184,000 seconds is 60 days, but it's an example response in the collection, not a stated lifetime. The sample app runs this exchange straight after the code exchange and keeps the long-lived token.
- Step 4: the collection says you can "refresh unexpired long-lived Threads User Access tokens", and that
threads_basic"is sufficient for the exchange or refresh process". Its example response for the refresh is empty, so it doesn't show what a refreshed token'sexpires_inis, or how soon after issue you may refresh. - App token:
GET /oauth/access_token?grant_type=client_credentialswith your Threads app ID and secret. The example response isTH|1234567890|abcd1234withtoken_typebearer.
The host is where Meta's own sources disagree: the collection uses graph.threads.net and www.threads.net, while the sample app moved to graph.threads.com and www.threads.com in March 2026. Our entry on the Threads API opening to all developers has the commit. Publishing with the token is covered in Threads API publishing.
System user tokens
For a business's own integrations, Meta's Python Business SDK has Business.create_system_user_access_token: POST /{business-id}/system_user_access_tokens with system_user_id, asset, scope, fetch_only and set_token_expires_in_60_days. The SDK names the 60-day option but doesn't say how long a token lasts without it.
Meta's WhatsApp tech provider sample describes one more kind: its app_only_install option "allows partners to access WABAs via API using a granular token (BISU), without creating a system user access token (SUAT)". The WhatsApp Cloud API basics guide covers why Meta's samples tell you to replace the temporary dashboard token with a system user token.
Debugging a token
Meta's Threads sample has an "Inspect Access Token" page. It calls GET /debug_token?input_token=<token> with the same token and reads application, expires_at, issued_at, scopes and user_id from the response's data. The Threads collection has the same request in its troubleshooting folder. It also points you to Meta's access token debugger to check that the token has the right permissions and "hasn't expired".
If your server sends the app secret, Meta's Python SDK adds an appsecret_proof parameter to every call: an HMAC SHA256 of the access token, keyed with the app secret.
What Meta's GitHub doesn't state
- How long a short-lived token lasts on any Meta API.
- The Instagram long-lived exchange and refresh calls, on either login path.
- When a Threads token may be refreshed, and how long a refreshed token lasts.
- Whether a Facebook Page token expires.
- How long a system user token lasts without the 60-day option.
- What revokes a token before it expires.
For the permissions each token needs before you go live, see Meta App Review: the minimum rules to go live.
What to do next
- Business owners: When a tool says your Instagram, Facebook or Threads connection has expired, reconnect it from the tool's settings. If it happens again and again, ask the vendor how it refreshes tokens.
- Marketers and agencies: Keep a list of which tools hold tokens for which client accounts, and reconnect from the account owner's login when one drops. For WhatsApp, ask whether the tool uses a system user token or a temporary one.
- Developers: Store each token with the
expires_inits exchange returned and check it withdebug_token. On Threads, exchange for a long-lived token at login and refresh before expiry. On Instagram, take the exchange and refresh calls from Meta's Business Login documentation, because Meta's GitHub doesn't include them.
Questions people ask
How long does an Instagram long-lived access token last?
Meta's public GitHub sources don't say. The Instagram Platform Postman collection names the Instagram User access token for every Instagram Login call but gives no lifetime and no long-lived exchange. The only 60-day figure in Meta's GitHub is an example Threads response with expires_in set to 5,184,000 seconds.
How do I refresh an Instagram access token?
Meta's GitHub has no Instagram refresh request on either login path, in the current Postman collection or in its history. The Threads collection has one (GET /refresh_access_token with grant_type=th_refresh_token), but that is the Threads API on its own host, so don't assume its grant type works on graph.instagram.com.
How do I get a Facebook Page access token?
Call /me/accounts with a Facebook User access token and ask for the access_token field. Meta's Instagram collection requests name, access_token, tasks and instagram_business_account, and calls the token it returns a Page Access Token that acts on behalf of the Page. If you know the Page ID, GET /{page-id}?fields=name,access_token,instagram_business_account returns just that Page's token.
How long does a Threads long-lived token last?
The example response in Meta's Threads Postman collection shows expires_in of 5,184,000 seconds, which is 60 days. That is an example response, not a stated lifetime. The collection says you can refresh unexpired long-lived tokens and that threads_basic is enough to exchange or refresh one.
Why did my Meta access token stop working?
Meta's GitHub sources don't list what ends a token early. Check it with debug_token, as Meta's Threads sample does, and read expires_at and scopes. In a unit test in Meta's WhatsApp tech provider sample, a rejected token comes back as an OAuthException with code 190 and the message Invalid access token.
Sources
- Meta on GitHub: Instagram Platform API Postman collection, Token folder and access tokens per login (fbsamples/messenger-platform-samples)
- Meta on GitHub: Threads API Postman collection, Authorization folder (fbsamples/threads_api)
- Meta on GitHub: Threads API sample app, login, token exchange and debug_token (fbsamples/threads_api, src/index.js)
- Meta on GitHub: Facebook Reels publishing sample, code exchange and Page tokens (fbsamples/reels_publishing_apis)
- Meta on GitHub: Python Business SDK, Business object (system user access tokens)
- Meta on GitHub: Python Business SDK, session (appsecret_proof)
- Meta on GitHub: Python Business SDK, User object (/accounts edge)
- Meta on GitHub: WhatsApp tech provider sample, token types in Embedded Signup (fbsamples/business-messaging-sample-tech-provider-app)
- Meta for Developers: Instagram Platform changelog (as recorded in our changelog entries)
Related
- API
LinkedIn Posts API: what you can schedule and how
LinkedIn's Posts API publishes text, images, video, documents, polls and multi-image posts but has no schedule field. How tools schedule, permissions, limits.
- Tools
Open-source social media schedulers you can self-host
Four open-source schedulers you can run yourself: Postiz, TryPost, Mixpost Lite and SkyScheduler. Licences, networks, what self-hosting takes, hosted prices.
- Tools
Free social media schedulers: all 39 free plans, verified
The best free social media scheduler for most people is Zoho Social (6 accounts) or Buffer (any 3 of 11 networks). All 39 free plans compared, with check dates.
- API
Instagram Content Publishing API: posts, reels, carousels
How the Instagram Content Publishing API works on both logins: containers, reels, carousels of up to 10, stories, and why Meta gives 100, 50 or 25 posts a day.