Skip to main content

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.
FieldValue
Platform slugfacebook
Auth typeOAuth 2.0 (Meta)
APIMeta Graph API (Facebook Pages)
Create postYes
Update postYes (message text only)
Delete postYes
ScheduleYes (deferred publish via scheduled_at)
First commentNo
Carousel (multi-photo)Yes (2 to 10 photos; images only)

2. Supported media

Content typeHow to triggerNotes
Text onlyNo media_ids; no link in platform_dataPublishes a plain text status update
Link previewNo media_ids; include link in the target’s platform_dataFacebook generates an Open Graph preview card
Single photoOne image entry in media_idsRoutes to /{page-id}/photos; platform_data is ignored
Single videoOne video entry in media_ids (.mp4, .mov, .avi, .mkv, .webm)Routes to /{page-id}/videos; platform_data is ignored
ReelOne vertical video entry in media_ids plus content_type: "reel" in the target’s platform_dataRoutes to the Reels API (/{page-id}/video_reels). Unlike standard videos, platform_data IS honored (content_type, share_to_feed).
Multi-photo album2 to 10 image entries in media_idsEach 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"
      }
    }]
  }'

Platform data fields

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.
FieldTypeDescription
linkstringURL to attach as a link preview card. Facebook generates the Open Graph preview automatically.
picturestringImage 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):
FieldTypeDefaultDescription
content_typestring"feed"Set to "reel" to publish a Reel. Any other value (or omitting it) publishes a standard post or feed video.
share_to_feedbooleantrueWhen 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.

platform_data forwarding rules

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 codeCategoryCaused byMeaning
platform.facebook.api_errorplatformplatformThe Graph API rejected the request. Check message for details.
platform.facebook.rate_limitrate_limitplatformFacebook rate limit hit. Retry after a delay.
platform.facebook.authauthplatformAccess 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.
ScopePurpose
pages_show_listList the pages the user manages
pages_read_engagementRead likes, comments, and shares on page posts
pages_read_user_contentRead posts and comments made by users on the page
pages_manage_engagementReply to and delete comments
pages_manage_metadataAccess page metadata and settings
pages_messagingSend and receive Messenger DMs
pages_manage_postsCreate, update, and delete page posts
public_profileAccess the user’s basic public profile
To verify which scopes your connected account has granted, call GET /v1/accounts/:id/limits.