One long-lived Page access token runs Facebook posting, Instagram publishing, and Reels — all three off the same credential. This is the whole routine, done in a browser logged in as the person who admins the Page. About five minutes once you know the steps. The golden rule: the token never gets pasted into a chat, a log, or a commit — it goes browser → credential field, nothing in between. Want the long version with the raw curl calls? That’s the token that dies quietly. This is the cheat sheet.

The two tools

ToolWhat it’s for
Graph API ExplorerGenerates tokens, runs queries. Your main tool.
Access Token DebuggerRead-only inspection of a token — Type, Scopes, Expiry. Use it to verify, not to query.

Your App ID and App Secret live at developers.facebook.com → your app → Settings → Basic.

Step 1 — generate a short-lived user token

Open the Graph API Explorer:

  • Pick the right Meta app (top right).
  • In the token dropdown pick User Token — not a Page token. The Page token comes later, via the exchange.
  • Add these permissions: pages_show_list, pages_manage_posts, pages_read_engagement, instagram_basic, instagram_content_publish, read_insights.
  • Click Generate Access Token and approve the popup. Don’t untick the Page in that popup.

Step 2 — exchange it for a long-lived token (the step people skip)

Paste this into the browser address bar, swapping in your values:

https://graph.facebook.com/v19.0/oauth/access_token?grant_type=fb_exchange_token&client_id={app-id}&client_secret={app-secret}&fb_exchange_token={short-token}

The JSON response gives you a long-lived user token (~60 days). Skip this and here’s the classic failure: the short-lived token gets saved, works for the test post, then dies within the hour — and posting stops silently.

Step 3 — get the Page token from the long-lived user token

Back in the Graph API Explorer, paste the long-lived user token into the token field and run:

me/accounts?fields=name,access_token
  • Copy the access_token sitting next to your Page’s name. The id in that same object is the real Page ID — hardcode it in your workflow, never use me.
  • A Page token derived from a long-lived user token is effectively non-expiring while you stay admin and the app stays active.

Verify before you trust it. Paste it into the Access Token Debugger:

  • Type must say Page (not User).
  • Scopes must include pages_manage_posts + pages_read_engagement.
  • Expires must say Never or ~2 months. If it says 1 hour, Step 2 didn’t take — do it again. Note the real expiry date down.

Step 4 — drop it into the credential store

In your automation tool, open the Facebook Graph credential (keep one per client, clearly named), paste the token into the Access Token field, and save.

  • Ignore a red “Bad request” on the credential self-test — the only proof that counts is a real post landing (Step 5).
  • The same credential serves Facebook posts, Instagram publishing, and video/Reel workflows — one token, all three.

Step 5 — verify with a real post (done = you saw it)

Fire the workflow once — test webhook or manual run — then open the actual Page and profile and confirm the post is there. If the workflow writes back to a sheet (Posted / timestamps), check that too. Saved is not the same as working. A post you can see is.

The gotcha list (each one cost real time)

  • User vs Page dropdown. Graph Explorer defaults to User Token. The error (#200) … requires … as an admin means you queried with a user token when you needed a Page one.
  • The profile.php ID trap. The number in a facebook.com/profile.php?id=… URL is not the Page ID. The real Page ID comes from me/accounts.
  • The Instagram decoy. The real IG business account ID comes from {page-id}?fields=instagram_business_account — not from the simpler-looking page_backed_instagram_accounts field.
  • me/accounts dumps every Page you admin. Copy only the one you need, straight into the credential store. Never paste the whole response anywhere that persists.
  • “Never” still isn’t immortal. The token dies on a password change, a security checkpoint, an admin being removed, or the app being switched off — and it dies silently. Posts just stop; nothing errors on screen. So every machine needs two things: failure-alert emails, and a daily check that the newest post timestamp isn’t stale.

Why we give this away

None of this is hard once you’ve met it. It’s expensive exactly once — the first time a lying error message sends you debugging the wrong thing. We’ve paid for every gotcha already, which is why the next build is boring. If you’ve got a workflow that should be posting itself and quietly isn’t, it’s almost always a token that died without saying so. If you’d rather never run this dance yourself, that’s the part we take off your plate.