Facebook Graph API Posting Guide
A practical guide to posting on Facebook Pages via the Graph API — authentication, media, and publishing.
Five things have to line up: a Page access token (derived via GET /me/accounts after a long-lived User-token exchange, or through PostGate's hosted connect flow), the right endpoint per media type — collapsed into one POST /api/posts — Meta's two rate-limit systems, the Reels format spec for vertical video, and per-target delivery confirmation via webhooks or polling with backoff.
Posting to a Facebook Page through Meta's Graph API touches five things you have to get right independently: a Page access token with the right scope and App Review status, the correct endpoint for whatever media you're attaching, Meta's own rate limits, the format requirements for anything vertical, and a way to find out whether delivery actually happened. This guide walks through all five as they work through PostGate, and links out to a dedicated page wherever there's more to say.
If you already know exactly what you're looking for, the more specific guides are faster: the single post request, scheduling, Reels, video upload, the access token, and rate limits.
1. Get a Page access token — or let PostGate get one
GET /me/accounts to derive a Page token that Meta documents as not carrying a fixed expiry. Through PostGate, a hosted connection URL does this exchange for you and stores the result — your product only ever sees a profile_id. See Facebook Page access token for the full mechanics, including what still invalidates a token that has no expiry date.curl -X POST https://postgate.studio/api/profiles/connect \
-H "Authorization: Bearer $POSTGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "facebook",
"profile_group_id": "grp_acme123",
"return_url": "https://app.example.com/settings/social"
}'2. Publish — one request, routed to the right endpoint
/feed for text, /photos for a single image, /videos for a single video, and an unpublished-photo-then-attach dance for multiple images — never a video and photos together, since Meta has no combined endpoint for that. PostGate's POST /api/posts picks the right branch based on what you send. Add draft: true, an ISO 8601 scheduled_at, or scheduled_at: "queue" to change when it fires rather than changing the shape of the request. See Facebook API: Post to a Page and Facebook Scheduling API.curl -X POST "https://postgate.studio/api/posts?profile_group_id=grp_acme123" \
-H "Authorization: Bearer $POSTGATE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: launch-post-001" \
-d '{
"post": { "body": "Launch day. 🚀" },
"profiles": ["pro_facebook789"],
"media": ["https://cdn.example.com/launch.jpg"]
}'3. Media limits, and where video gets specific
4. Two rate-limit systems apply, not one
200 × active users per hour, tracked on X-App-Usage. A separate, Page-scoped limit runs roughly 4,800 × engaged users per rolling 24 hours, tracked on X-Page-Usage — this is usually the one that matters for a lower-traffic Page. PostGate surfaces either as a retryable rate_limited or platform_transient error. See Facebook API rate limit for the full breakdown, including the separate Reels cap.5. Publishing is asynchronous — confirm it, don't assume it
targets array progresses independently through pending, publishing, and a terminal published, failed, or skipped. Subscribe to webhooks for normal operation, or poll with backoff and stop once every target is terminal. A stable Idempotency-Key keeps a network retry from posting the same content twice.curl https://postgate.studio/api/posts/post_01JXYZ \
-H "Authorization: Bearer $POSTGATE_API_KEY"Frequently asked questions
What token do I need to post to a Facebook Page?
A Page access token — not the User token of the person who authorized your app. Getting one directly means exchanging a short-lived User token for a long-lived one (about 60 days), then calling GET /me/accounts to derive a Page token that Meta documents as not carrying a fixed expiry. Through PostGate, a hosted connection URL does the exchange and stores the result; your product only ever sees a profile_id.
How do I schedule or draft a Facebook post instead of publishing immediately?
Change when the post fires without changing the shape of the request: add draft: true to hold it for manual publishing, an ISO 8601 scheduled_at for a fixed time, or scheduled_at: "queue" to take the next open slot on a recurring schedule. The rest of the POST /api/posts envelope stays identical.
What are the specs for Facebook Reels through the API?
Meta’s dedicated Reels API has its own spec: MP4, 9:16 vertical, roughly 3–90 seconds, minimum 540×960px — and its own cap of 30 API-published Reels per Page per day. A short vertical video is a Reels question rather than a different generic video endpoint.
Which Facebook rate limit actually matters for posting?
Two systems apply at once: an app-level Platform Rate Limit of roughly 200 × active users per hour, tracked on X-App-Usage, and a separate Page-scoped limit of roughly 4,800 × engaged users per rolling 24 hours, tracked on X-Page-Usage. The Page-scoped one is usually what matters for a lower-traffic Page. PostGate surfaces either as a retryable rate_limited or platform_transient error.
How do I confirm a Facebook post actually delivered?
The create response is acceptance only. Each destination in the post’s targets array progresses independently through pending, publishing, and a terminal published, failed, or skipped. Subscribe to webhooks for normal operation, or poll with backoff and stop once every target is terminal — and use a stable Idempotency-Key so a network retry never posts the same content twice.
