You can often publish to a Facebook Page with the facebook graph api for page posting without app review when you are posting as the admin of that Page. The rule most people miss is that app review gates other people’s data, not your own Page and your own token. This post walks the whole path: what review actually controls, how to get a Page token in Graph API Explorer, a working curl call, how to turn a short-lived token into a long-lived one, and the errors you will hit along the way.
You (admin) ---- app in Developer mode
|
v
User token --GET /me/accounts--> Page token + Page id
| |
| v
| POST /{page-id}/feed
| (works while you are admin)
v
Extend token: /oauth/access_token
grant_type=fb_exchange_token
What app review actually gates in the Facebook Graph API
App review is a permission check. When your Meta app asks for permissions like pages_manage_posts or pages_read_engagement, those permissions come with an access level. In development mode, the app can only use them against people who hold a role on the app: admins, developers, testers. That is why your own test Page posts fine on day one.
Review matters when you want the app to act for users you have never met. A scheduling dashboard that connects a stranger’s Page needs review, because the stranger has no role on your app. That is the gate. It is not a gate on posting to a Page you control.
There is also a second gate that people confuse with review: Business Verification. It applies to advanced access to certain permissions, usually when you serve businesses at scale. If you are posting to your own Page from your own machine, neither gate applies yet.
Why Page posting often works without app review
Three things have to line up:
- You are an admin of the Page, and your app is in Development mode with you added as an admin or developer of that app.
- You are using a Page access token, not your personal user token. Page tokens carry the Page’s own identity.
- You only touch the Page you administer. Comments on your own posts, replies, and basic feed publishing sit in that same bucket.
The failure mode is always the same. Someone grabs a user token, calls the feed endpoint, gets an error, and concludes review is required. The token was the problem. A user token can read the list of Pages you manage, but the write call belongs to the Page token.
If you want to see how far the same idea goes on other networks, the pattern in one social media API for every platform is the same: your own credentials, your own accounts, no marketplace listing step.
Get a Page access token and Page ID in Graph API Explorer
Graph API Explorer is the fastest place to test this before you write any code.
- Open Graph API Explorer and pick your app from the dropdown. If you have no app, create one as a Business type app.
- Under permissions, add
pages_show_list,pages_manage_postsandpages_read_engagement. Addpages_manage_metadataif you plan to read comments. - Click Generate Access Token. Approve the dialog while logged in as the Page admin.
- Call
GET /me/accounts. The response is a list of Pages, each with aname, anidand anaccess_token. - Copy the
idand theaccess_tokenfor the Page you want. That token is the Page token.
Two checks worth doing right away. Call GET /{page-id}?fields=name,id to confirm the token belongs to that Page. Then call GET /debug_token with the Page token to see its expiry and scopes. If expiry looks like an hour, you are holding a short-lived token and the next section is for you.
Post to your Page with a curl request
The feed endpoint takes a message and optional link. Keep the token out of your shell history by exporting it.
export PAGE_ID="1234567890"
export PAGE_TOKEN="EAAG..."
curl -s -X POST \
"https://graph.facebook.com/v21.0/${PAGE_ID}/feed" \
-d "message=First post from the Graph API" \
-d "link=https://example.com/blog" \
-d "access_token=${PAGE_TOKEN}"
A good response is a JSON object with an id shaped like {page-id}_{post-id}. Save that composite id. You need it for edits, comments and metrics.
To schedule instead of publishing now, add published=false and scheduled_publish_time as a Unix timestamp between 10 minutes and 75 days out. To attach an image, upload it to /{page-id}/photos first with published=false, take the returned id, and pass it as attached_media in the feed call.
To read the post back:
curl -s "https://graph.facebook.com/v21.0/${PAGE_ID}_${POST_ID}\
?fields=message,created_time,permalink_url,shares,reactions.summary(true)\
&access_token=${PAGE_TOKEN}"
If you are publishing Reels or Stories rather than plain feed posts, the payload changes; the Facebook Reels API notes cover the video path, and scheduling Instagram Stories shows how the same account structure works on the Instagram side.
Extend the short-lived token to a long-lived Page token
Tokens from Explorer die fast. Do this once and stop babysitting them.
- Exchange the short-lived user token for a long-lived user token (about 60 days):
curl -s "https://graph.facebook.com/v21.0/oauth/access_token\ ?grant_type=fb_exchange_token\ &client_id=${APP_ID}\ &client_secret=${APP_SECRET}\ &fb_exchange_token=${SHORT_USER_TOKEN}" - Call
GET /me/accountsagain, but this time with the long-lived user token. The Page tokens in that response inherit the longer lifetime. - Store the Page token in a secret manager. Never commit it, never put it in a client-side bundle.
Page tokens derived from a long-lived user token last about 50 to 60 days, and they can be refreshed by repeating the exchange before they expire. A common pattern is a small job that runs weekly, re-derives the Page token, and writes it back to your secret store.
One warning that costs people a weekend: if you change your Facebook password, or revoke the app, tokens die immediately. Build your code to detect an OAuthException and re-authenticate rather than crash.
Known limits, errors and rate limits to expect
You will meet a small set of errors. Learn their shapes.
| Error | What it means | Fix |
|---|---|---|
| Code 190, OAuthException | Token expired, revoked, or wrong type | Re-run the exchange, confirm you are using the Page token |
| Code 200, permission error | Scope missing or the user has no role on the app | Add the permission, re-generate the token |
| Code 4 or 17, rate limit | Too many calls in a window | Back off, batch reads, cache results |
| Code 100, invalid parameter | Scheduled time out of range, or missing field | Keep schedule between 10 minutes and 75 days |
Rate limits are per app and per Page together. The practical number for a single Page is generous for normal posting, but loops that read comments every second will trip it. Cache Page metadata such as the Page id and name; you rarely need to fetch them again.
Other limits worth knowing before you build:
- Development mode tokens only work for users with a role on the app. A teammate without a role will get a permission error even for your own Page.
- Edits are possible on some fields after publishing, but the window is limited. Do not plan a workflow around rewriting old posts.
- Stories on Facebook Pages accept no caption through the API. Design around that rather than fighting it.
The same token discipline applies elsewhere. read-only API keys for AI agents explains why you should scope a key so a mistake cannot publish or delete, and that thinking starts here with the scopes you tick in Explorer.
When you do need app review or a third-party API
You need review the moment your app stops being personal. If you are building a product where someone else connects their Page to your app, you need review plus Business Verification, and Meta will want to see the exact use case for each permission. There is no shortcut, and trying to route around it by asking users for tokens directly breaks Meta’s platform terms.
You also outgrow the manual path when the work gets repetitive. Refreshing tokens, retrying failed posts, mirroring the same caption to five networks, and pulling analytics each day is a lot of code to own. That is the problem a hosted API solves. Creator OS runs publishing, scheduling, replies and analytics across Instagram, TikTok, YouTube, X, LinkedIn, Facebook and Threads from one account layer, and it ships a Facebook MCP server plus a CLI so an AI agent can act on your accounts instead of you hand-crafting curl calls.
If you would rather keep the manual route and add comment automation yourself, automating Instagram and TikTok replies shows the same token and webhook mechanics applied to comment funnels, and Creator OS compared with Zapier covers when a workflow builder is enough and when you want an API that speaks social natively.
Get started with Creator OS
If you want Page posting and the rest of the stack without maintaining token refresh jobs, connect a Facebook Page to Creator OS and publish from the web app, the iOS app, the API, the CLI or an MCP-capable AI app. API keys, the MCP server, the CLI and the agent skills are included in every plan.
The Creator plan is $19.99/month or $59.99/year and covers up to 8 connected accounts: 7 socials plus Skool. If you run several brands, Agency plans cover 5 sets of socials for $49/month or $399/year, and 10 sets for $99/month or $599/year. Ads are an add-on at $19.99/month on any plan, with no percentage of ad spend.
Read the request shapes and platform options at https://www.creatoros.ca/docs, then sign up. For walkthroughs of the API, the CLI and the open-source agents, watch the KevBuildsApps YouTube channel, and if you want to see the open-source agent harness and video editing skills in action, start with the launch video.