Facebook

Facebook Graph API Posting Guide

A practical guide to posting on Facebook Pages via the Graph API — authentication, media, and publishing.

Quick answer

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.

01

1. Get a Page access token — or let PostGate get one

Every write to a Page is authorized by 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 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.
Connect a PagePostGate API
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"
  }'
02

2. Publish — one request, routed to the right endpoint

Raw Graph API publishing branches by media type: /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.
Publish nowPostGate 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"]
  }'
03

3. Media limits, and where video gets specific

A Page post allows up to 63,206 characters, up to 10 media items, images up to 10 MB, and video up to roughly 4 GB and 4 hours. Meta's Graph API itself offers a resumable, chunked upload for large video files — PostGate drives that for you when you create media from a URL or a large multipart upload; see Facebook Graph API video upload. A short vertical video is a Reels question rather than a different endpoint — Meta's dedicated Reels API has its own spec (MP4, 9:16, roughly 3–90 seconds, minimum 540×960px) and its own 30-Reels-per-day cap; see Facebook Reels API.
04

4. Two rate-limit systems apply, not one

An app-level Platform Rate Limit runs roughly 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.
05

5. Publishing is asynchronous — confirm it, don't assume it

The create response is acceptance. 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. A stable Idempotency-Key keeps a network retry from posting the same content twice.
Inspect a postPostGate API
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.

Build it with PostGate

One API for every social platform your customers care about — sandboxed, documented, and ready today.

Start building Read the docs