Meta Marketing API Long-Lived Access Token: Step by Step
Get a Meta Marketing API access token that doesn't expire: create the app, set up Facebook Login for Business, generate a config ID and exchange the code.
Create a Business-type app on developers.facebook.com, add Facebook Login for Business, and create a configuration that issues a system-user access token set to never expire, with ads_management and ads_read. Then send the user through the OAuth dialog with your config_id and exchange the returned code for a token server-side. The token doesn't expire, so you can use it in scripts, n8n or your own app.
If you want a Meta access token that doesn't expire, here's the short version. Create a Business app, add Facebook Login for Business, and create a configuration that issues a system-user access token with expiration set to never. Give it ads_management and ads_read. Then you need three values: the app ID, the app secret and the config ID. With those, send yourself through the OAuth dialog and exchange the code for a token.
I split this into two videos. Part 1 creates the app and the configuration. Part 2 uses a small playground tool we built to run the OAuth flow and email the token back. This post covers both, plus the code to do the exchange yourself, so you don't depend on anyone's tool.
What you need before you start
- A Facebook account with access to the ad accounts you want to reach.
- A Business portfolio (Business Manager) that owns or has access to those ad accounts.
- An HTTPS redirect URL. For a one-off token this can be any page you control. For a real app it's your backend callback.
- About 15 minutes.
My advice from the video still applies: follow the steps exactly. The Meta developer dashboard has a lot of options, and clicking around is how people end up with an app type that can't do what they need.
Why tokens expire, and which one you want
Meta has several kinds of tokens. The two that matter here:
- User access token. The token you get from Graph API Explorer lasts about an hour. You can swap it for a long-lived one that lasts about 60 days. Then you have to refresh it, and your automation breaks on day 61 if you forget.
- Business integration system-user token. You get it through Facebook Login for Business with a configuration. When the configuration sets expiration to never, the token doesn't expire. That's the one I use for scripts, n8n and reporting tools.
A system-user token still stops working if the person who granted it removes the app or loses access to the business assets. "Never expires" doesn't mean it can't be revoked.
Part 1: Create the app and get the config ID
Step 1: Create the app
- Go to
developers.facebook.com→ My Apps → Create app. - Give it a name, like "Agency reporting".
- Use case: choose Other.
- App type: choose Business.
- Pick your Business portfolio if you have one, and create the app. Meta asks for your password again.
Step 2: Add Facebook Login for Business
- On the app dashboard, find Facebook Login for Business and click Set up.
- Go to Configurations → Create configuration.
- Give it any name.
- Login variation: General.
- Access token: System-user access token.
- Token expiration: Never.
- Assets: choose Ad accounts. You don't need Pages unless your tool posts to them.
- Permissions:
ads_managementandads_read. Nothing else for a reporting or ads tool. - Create it and copy the configuration ID.
Step 3: Collect the three values
- App ID and App secret: App settings → Basic. Click Show to reveal the secret.
- Config ID: from the configuration you just created.
Keep the secret out of client-side code and out of shared docs.
Step 4: Whitelist your redirect URI
Go to Facebook Login for Business → Settings and add your callback URL under Valid OAuth Redirect URIs. Save changes. If you skip this, the dialog fails with a URL-blocked error.
Part 2: Turn the three values into a token
In the video I use a playground tool we built. You paste the app ID, app secret and config ID, add its redirect URI to your Valid OAuth Redirect URIs, and enter an email. Then you click connect, pick the business portfolio and the ad accounts, and approve. The tool emails the token back. It doesn't store the token in a database. The email showed the token "expires in unknown seconds", meaning it doesn't expire.
Here's how to do the same exchange yourself.
Step 5: Send the user to the OAuth dialog
Build this URL and open it in a browser while logged in to the Facebook account that has access to the ad accounts:
https://www.facebook.com/v26.0/dialog/oauth
?client_id=YOUR_APP_ID
&redirect_uri=https://yourapp.com/meta/callback
&config_id=YOUR_CONFIG_ID
&response_type=code
&override_default_response_type=true
&state=RANDOM_STRING
(Put it on one line. I split it for reading.) config_id replaces the scope parameter. Meta reads the permissions and token type from the configuration. override_default_response_type=true makes Meta honour response_type=code.
The user picks the business and ad accounts, approves, and Meta redirects to your URL with ?code=...&state=.... Check that state matches what you sent.
Step 6: Exchange the code server-side
# exchange_code.py
import os
import requests
GRAPH = "https://graph.facebook.com/v26.0"
def exchange_code(code: str) -> str:
resp = requests.get(
f"{GRAPH}/oauth/access_token",
params={
"client_id": os.environ["META_APP_ID"],
"client_secret": os.environ["META_APP_SECRET"],
"redirect_uri": "https://yourapp.com/meta/callback", # same as in the dialog
"code": code,
},
timeout=30,
)
resp.raise_for_status()
return resp.json()["access_token"]
The code is single-use and short-lived. Exchange it right away.
Step 7: Check what you got
Meta's debug_token endpoint tells you the token type, scopes and expiry:
def debug_token(token: str) -> dict:
app_token = f'{os.environ["META_APP_ID"]}|{os.environ["META_APP_SECRET"]}'
resp = requests.get(
f"{GRAPH}/debug_token",
params={"input_token": token, "access_token": app_token},
timeout=30,
)
return resp.json()["data"]
info = debug_token(token)
print(info["type"], info["scopes"], info.get("expires_at"))
expires_at of 0 means it doesn't expire.
Step 8: Use it
List the ad accounts the token can reach:
curl -G "https://graph.facebook.com/v26.0/me/adaccounts" \
-d fields=name,account_id,currency \
-d access_token="$META_TOKEN"
Pull last week's spend for one account:
curl -G "https://graph.facebook.com/v26.0/act_1234567890/insights" \
-d fields=campaign_name,spend,impressions,clicks \
-d level=campaign \
-d date_preset=last_7d \
-d access_token="$META_TOKEN"
In n8n, the same calls go in an HTTP Request node. Store the token as a credential, not as plain text in the workflow.
Other ways to get a long-lived token
The 60-day exchange. If you already have a short-lived user token, swap it:
curl -G "https://graph.facebook.com/v26.0/oauth/access_token" \
-d grant_type=fb_exchange_token \
-d client_id="$META_APP_ID" \
-d client_secret="$META_APP_SECRET" \
-d fb_exchange_token="$SHORT_LIVED_TOKEN"
This works, but you have to redo it before it expires.
A system user in Business Settings. If the ad accounts belong to your own business, you can create a system user under Business Settings → Users → System users, assign it the ad accounts, and generate a token there. That's fine for internal tools. It doesn't help when a client needs to connect their own business, which is where the Login for Business flow is the right tool.
Common errors and how to fix them
"URL blocked: This redirect failed because the redirect URI is not whitelisted". Add the exact URL to Valid OAuth Redirect URIs under Facebook Login for Business settings.
"Error validating verification code" or a redirect_uri error on exchange. The redirect_uri in the exchange call must exactly match the one you used in the dialog.
The token works but /me/adaccounts is empty. The user didn't select any ad accounts in the dialog, or the configuration didn't include ad accounts as an asset. Run the flow again and select them.
(#200) permission errors on a client's account. Your app has standard access to ads_management. That only covers accounts where people with a role on your app have access. To manage other businesses' accounts at scale, you need advanced access through App Review and business verification.
(#17) or 80004 rate-limit errors. You're calling an ad account too often. Back off, batch your insights requests, and use async insights jobs for large date ranges.
Security notes
A token that never expires is a credential that never expires. Treat it like one:
- Keep it in an environment variable or secrets manager.
- Don't paste it into chat tools or tickets.
- If it leaks, remove the app from the business integrations in the Facebook account settings, or reset the app secret.
How Scalvo can help
If you need clients to connect their own Meta ad accounts, you'll need advanced access, business verification and App Review. Our app approval and launch service covers that end to end. If you just want the reporting or automation built on top of the token, look at the AI automation sprint or book a call.
Related videos
Frequently asked questions
How long does a Meta long-lived access token last?
A long-lived user access token lasts about 60 days. A business integration system-user token created through a Facebook Login for Business configuration with expiration set to never does not expire, though it stops working if the user removes the app or loses access.
What permissions do I need to read and manage Meta ads?
ads_read to read reporting data and ads_management to create or edit campaigns. Add business_management only if you need to work with Business Manager assets.
What is a config ID in Meta's API?
It's the ID of a Facebook Login for Business configuration. It tells the OAuth dialog which token type, expiration, assets and permissions to request, instead of passing a scope list.
Can I use this token in n8n or Make?
Yes. Paste it into an HTTP Request node as a Bearer token or access_token parameter and call graph.facebook.com. Store it as a credential, not inside the workflow.




