Documentation Index
Fetch the complete documentation index at: https://docs.social-api.ai/llms.txt
Use this file to discover all available pages before exploring further.
1. Overview
Facebook publishing uses the Meta Graph API directly against your connected Facebook Page. SocialAPI selects the correct Graph API endpoint based on the content type: text and link posts go to /{page-id}/feed, single-photo posts to /{page-id}/photos, single-video posts to /{page-id}/videos, and multi-photo albums use a two-step upload-then-feed flow described below.
| Field | Value |
|---|
| Platform slug | facebook |
| Auth type | OAuth 2.0 (Meta) |
| API | Meta Graph API (Facebook Pages) |
| Create post | Yes |
| Update post | Yes (message text only) |
| Delete post | Yes |
| Schedule | Yes (deferred publish via scheduled_at) |
| First comment | No |
| Carousel (multi-photo) | Yes (2 to 10 photos; images only) |
| Content type | How to trigger | Notes |
|---|
| Text only | No media_ids; no link in platform_data | Publishes a plain text status update |
| Link preview | No media_ids; include link in the target’s platform_data | Facebook generates an Open Graph preview card |
| Single photo | One image entry in media_ids | Routes to /{page-id}/photos; platform_data is ignored |
| Single video | One video entry in media_ids (.mp4, .mov, .avi, .mkv, .webm) | Routes to /{page-id}/videos; platform_data is ignored |
| Reel | One vertical video entry in media_ids plus content_type: "reel" in the target’s platform_data | Routes to the Reels API (/{page-id}/video_reels). Unlike standard videos, platform_data IS honored (content_type, share_to_feed). |
| Multi-photo album | 2 to 10 image entries in media_ids | Each photo is uploaded with published=false, then a single /{page-id}/feed call attaches all media_fbid values via attached_media[]. The target’s platform_data fields (link, CTA, age targeting) are forwarded to the feed call. |
Route selection is automatic:
media_ids is empty → text or link post on /{page-id}/feed
media_ids has one entry → photo or video endpoint based on the file extension
media_ids has 2 to 10 entries → multi-photo album
Caption limit: Follows Facebook’s standard post message limit (approximately 63,206 characters, though shorter posts perform better).
Multi-photo album rules:
- 2 to 10 photos per post. Passing more than 10 entries returns a validation error.
- Images only. Mixing images and videos in the same album is rejected with a validation error. Facebook’s Graph API does not support mixed-media albums; publish separate posts or use a single Reel with image overlays.
- Each photo is uploaded as an unpublished photo, which Facebook retains for approximately 24 hours. The follow-up feed call happens immediately, so this expiry only matters if the feed call fails. In that case the uploaded photos are abandoned and you can safely retry the post.
- For best rendering, use consistent 1,080 by 1,080 px (1:1) images.
3. Create post
Use POST /v1/posts with targets targeting a Facebook Page account. The text field becomes the post message.
curl -X POST https://api.social-api.ai/v1/posts \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Exciting news from our team. Read the full announcement on our website.",
"targets": [{
"account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J",
"platform_data": {
"link": "https://example.com/announcement"
}
}]
}'
Pass these inside the target’s platform_data object (keys are read directly, not nested under a facebook key). These fields apply to text and link posts only. Photo and video posts ignore platform_data entirely.
| Field | Type | Description |
|---|
link | string | URL to attach as a link preview card. Facebook generates the Open Graph preview automatically. |
picture | string | Image URL to use as the link preview thumbnail. Overrides the Open Graph image from the linked URL. |
SocialAPI forwards any additional keys in the target’s platform_data directly to the underlying platform API. These fields are not validated by SocialAPI and may break if the platform changes its API. See Facebook Pages API reference for the full list of supported parameters.
Photo post
Provide a single image entry in media_ids. The platform_data block is ignored for photo posts.
curl -X POST https://api.social-api.ai/v1/posts \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"targets": [{ "account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J" }],
"text": "Our new product is here.",
"media_ids": ["f47ac10b-58cc-4372-a567-0e02b2c3d479"]
}'
Multi-photo album
Provide 2 to 10 image entries in media_ids to publish a multi-photo album. SocialAPI handles the two-step Graph API flow internally: each photo is uploaded with published=false to obtain a media_fbid, then a single /{page-id}/feed call attaches all photo IDs via attached_media[] and sets the caption.
curl -X POST https://api.social-api.ai/v1/posts \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"targets": [{ "account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J" }],
"text": "Highlights from this week.",
"media_ids": [
"f47ac10b-58cc-4372-a567-0e02b2c3d479",
"8d5e9b2c-1a3f-4c6d-9e8b-2f7a4c1d6e0b",
"3b1f7a90-6c2d-4e85-b9a1-0d4f8c3e2a17"
]
}'
Unlike single-photo posts, the target’s platform_data IS honored for albums. The link, cta_type plus cta_link, and age targeting fields are forwarded to the feed call:
curl -X POST https://api.social-api.ai/v1/posts \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Shop the spring collection.",
"media_ids": [
"f47ac10b-58cc-4372-a567-0e02b2c3d479",
"8d5e9b2c-1a3f-4c6d-9e8b-2f7a4c1d6e0b",
"3b1f7a90-6c2d-4e85-b9a1-0d4f8c3e2a17",
"5e2c8a14-7b9d-4f03-a6c1-9d8e0b3f4a26"
],
"targets": [{
"account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J",
"platform_data": {
"cta_type": "SHOP_NOW",
"cta_link": "https://example.com/spring"
}
}]
}'
Limits:
- Minimum 2, maximum 10 photos per album.
- Images only. Including a video entry (any of
.mp4, .mov, .avi, .mkv, .webm) in a 2+ item media_ids returns a validation error before any upload to Facebook.
Video post
Provide a single video entry in media_ids. SocialAPI detects the video extension and routes to /{page-id}/videos.
curl -X POST https://api.social-api.ai/v1/posts \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"targets": [{ "account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J" }],
"text": "Watch our latest brand film.",
"media_ids": ["f47ac10b-58cc-4372-a567-0e02b2c3d479"]
}'
Reel
Publish a short-form vertical video as a Page Reel by setting content_type: "reel" in the target’s platform_data. Provide exactly one vertical video entry in media_ids. SocialAPI runs Facebook’s Reels publishing flow (upload, processing, publish) and returns once the Reel is accepted for processing.
The platform_data object lives on the target (inside the targets array), and its keys are read directly (do not nest them under a facebook key).
curl -X POST https://api.social-api.ai/v1/posts \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Behind the scenes #reels",
"media_ids": ["f47ac10b-58cc-4372-a567-0e02b2c3d479"],
"targets": [{
"account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J",
"platform_data": {
"content_type": "reel",
"share_to_feed": true
}
}]
}'
Reel fields (inside the target’s platform_data):
| Field | Type | Default | Description |
|---|
content_type | string | "feed" | Set to "reel" to publish a Reel. Any other value (or omitting it) publishes a standard post or feed video. |
share_to_feed | boolean | true | When true, the Reel also appears in the Page feed, not just the Reels tab. |
Requirements: exactly one video, vertical orientation (9:16), and a duration of 3 to 90 seconds. SocialAPI warns when the duration is outside that range; Facebook enforces the aspect ratio at publish time and rejects videos that do not comply.
Scheduling
Set scheduled_at to an ISO 8601 timestamp (UTC) to defer publishing:
{
"targets": [{ "account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J" }],
"text": "Scheduled announcement.",
"scheduled_at": "2026-04-15T10:00:00Z"
}
4. Update post
Facebook supports editing the message text of a post that was created by the same app. Media cannot be changed after publish. Use PATCH /v1/posts/:pid with a text field:
curl -X PATCH https://api.social-api.ai/v1/posts/post_01HZ9X3Q4R5M6N7P8V2K0W1J \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Updated message text."
}'
SocialAPI calls POST /{page-id}_{post-id} with the new message value. Only the text field is forwarded; all other patch fields are ignored for Facebook targets.
Limitation: Only posts created by your app can be updated. Posts imported from the platform (via sync) may return a 400 from Facebook if the app does not own them.
5. Delete post
curl -X DELETE https://api.social-api.ai/v1/posts/post_01HZ9X3Q4R5M6N7P8V2K0W1J \
-H "Authorization: Bearer $SOCAPI_KEY"
Or, to delete only the Facebook target of a cross-platform post:
curl -X DELETE "https://api.social-api.ai/v1/posts/post_01HZ9X3Q4R5M6N7P8V2K0W1J?platform=facebook" \
-H "Authorization: Bearer $SOCAPI_KEY"
Deletion calls DELETE /{page-id}_{post-id} on the Graph API. If the post no longer exists on Facebook, the call returns success.
6. Retrieve posts
Use GET /v1/posts to list posts. Filter by platform or account:
curl "https://api.social-api.ai/v1/posts?platform=facebook&account_ids=acc_01HZ9X3Q4R5M6N7P8V2K0W1J&limit=20" \
-H "Authorization: Bearer $SOCAPI_KEY"
Each post includes a targets array with per-platform status and engagement metrics:
{
"id": "post_01HZ9X3Q4R5M6N7P8V2K0W1J",
"text": "Exciting news from our team.",
"status": "published",
"targets": [
{
"platform": "facebook",
"platform_post_id": "123456789012345_987654321098765",
"status": "published",
"permalink": "https://www.facebook.com/permalink/123456789012345",
"metrics": {
"likes": 15,
"comments": 3,
"shares": 7,
"saves": 0,
"extra": null,
"metrics_synced_at": "2026-04-10T12:00:00Z"
}
}
]
}
Metrics notes:
likes and comments are synced periodically from the Graph API.
shares is populated for Facebook posts. Facebook is the only platform where SocialAPI reports a non-zero share count.
saves is not exposed by the Facebook Pages API and is always 0.
metrics_synced_at reflects when SocialAPI last refreshed the metrics from Facebook.
7. Quirks, errors, and recovery
Page token lifetime
Facebook Page tokens derived from long-lived user tokens do not expire. Once an account is connected, the token remains valid indefinitely unless the user revokes app access or changes their password. Reconnection is only needed if you see an auth error.
Multi-page OAuth
When a user completes the Facebook OAuth flow, SocialAPI connects all Facebook Pages that the user manages in a single OAuth exchange. Each page becomes a separate connected account entry. Users do not need to repeat the OAuth flow for additional pages.
The target’s platform_data block is forwarded to the Graph API for text/link posts and for multi-photo albums (both go through the /{page-id}/feed endpoint). For single-photo posts and single-video posts, the block is silently ignored because the /{page-id}/photos and /{page-id}/videos endpoints do not accept those fields. The alt_text field is the one exception: it is honored for single-photo posts.
Multi-photo album semantics
Multi-photo albums (2 to 10 image entries in media_ids) use a two-step flow: each photo is uploaded with published=false, then attached to a single feed post. The unpublished photos Facebook stores during step one expire after about 24 hours, so if the second step fails the photos are simply abandoned and you can retry the entire post. Mixing images and videos in the same album returns a validation error before any upload happens, and passing more than 10 entries also fails validation.
Reviews deprecated
The Facebook Graph API v22.0 removed the reviews edge. GET /v1/inbox/reviews for a Facebook account returns 501 Not Implemented. This is a platform-level deprecation and cannot be worked around.
DM 24-hour window
Facebook Messenger only allows pages to send outbound DMs within a 24-hour window after the user last messaged the page. Attempting to send outside this window returns a platform error. SocialAPI surfaces this as an api_error.
Error shapes
When a publish fails, the post target’s error field contains a structured error:
{
"code": "platform.facebook.api_error",
"message": "Invalid OAuth access token.",
"category": "platform",
"caused_by": "platform"
}
| Error code | Category | Caused by | Meaning |
|---|
platform.facebook.api_error | platform | platform | The Graph API rejected the request. Check message for details. |
platform.facebook.rate_limit | rate_limit | platform | Facebook rate limit hit. Retry after a delay. |
platform.facebook.auth | auth | platform | Access token invalid or revoked. Reconnect the account. |
Recovery
- Rate limit: Retry the post via
POST /v1/posts/:pid/retry after waiting. SocialAPI applies exponential backoff for scheduled retries.
- Auth error: Disconnect and reconnect the Facebook account through the OAuth flow to obtain a fresh token.
- API error: Check the
message field for the Graph API error description. Common causes include missing page permissions, a post that no longer exists, or an invalid media URL.
8. Full worked example
The following example publishes a link preview post with a custom thumbnail, then checks the metrics after publish.
Step 1: Publish the post
curl -X POST https://api.social-api.ai/v1/posts \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "We just launched our spring collection. Shop now and get 20% off your first order.",
"targets": [{
"account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J",
"platform_data": {
"link": "https://example.com/spring-collection",
"picture": "https://cdn.example.com/spring-og.jpg"
}
}]
}'
Response:
{
"id": "post_01HZ9X3Q4R5M6N7P8V2K0W1J",
"text": "We just launched our spring collection. Shop now and get 20% off your first order.",
"status": "publishing",
"targets": [
{
"platform": "facebook",
"status": "publishing"
}
],
"created_at": "2026-04-10T09:00:00Z"
}
Step 2: Check status
curl "https://api.social-api.ai/v1/posts/post_01HZ9X3Q4R5M6N7P8V2K0W1J" \
-H "Authorization: Bearer $SOCAPI_KEY"
Response once published:
{
"id": "post_01HZ9X3Q4R5M6N7P8V2K0W1J",
"text": "We just launched our spring collection. Shop now and get 20% off your first order.",
"status": "published",
"targets": [
{
"platform": "facebook",
"platform_post_id": "123456789012345_987654321098765",
"status": "published",
"permalink": "https://www.facebook.com/permalink/123456789012345",
"metrics": {
"likes": 15,
"comments": 3,
"shares": 7,
"saves": 0,
"extra": null,
"metrics_synced_at": "2026-04-10T12:00:00Z"
}
}
],
"created_at": "2026-04-10T09:00:00Z",
"published_at": "2026-04-10T09:00:12Z"
}
Step 3: Refresh metrics on demand
curl "https://api.social-api.ai/v1/posts/post_01HZ9X3Q4R5M6N7P8V2K0W1J/metrics" \
-H "Authorization: Bearer $SOCAPI_KEY"
9. Required OAuth scopes
SocialAPI’s managed Meta App requests the following scopes on your behalf during the OAuth flow. This is informational — you do not need to configure anything.
| Scope | Purpose |
|---|
pages_show_list | List the pages the user manages |
pages_read_engagement | Read likes, comments, and shares on page posts |
pages_read_user_content | Read posts and comments made by users on the page |
pages_manage_engagement | Reply to and delete comments |
pages_manage_metadata | Access page metadata and settings |
pages_messaging | Send and receive Messenger DMs |
pages_manage_posts | Create, update, and delete page posts |
public_profile | Access the user’s basic public profile |
To verify which scopes your connected account has granted, call GET /v1/accounts/:id/limits.