# Facebook

Publish text, link, photo and video posts, Reels and Stories to Facebook Pages.


## Overview

The `facebook` platform publishes to **Facebook Pages** (not personal profiles). Every Page you grant during login becomes its own account in Relaycast. You can post:

- Text posts, optionally with a link preview card
- 1–10 photos
- 1 video (with optional title and custom thumbnail)
- Reels (one vertical video)
- Stories (one photo or one video)
- Unpublished Page posts (for ads, or to publish later in Meta Business Suite)

## Connect the account

In **[Integrations](https://social-publish-kappa.vercel.app/dashboard/integrations)**, choose **Facebook**, log in, and select the Pages to connect.

### App setup (self-hosted)

1. Create a Meta app with the use case **Manage everything on your Page** (this adds Facebook Login).
2. Add `https://social-publish-kappa.vercel.app/api/integrations/facebook/callback` to **Facebook Login → Settings → Valid OAuth Redirect URIs** (override with `FACEBOOK_REDIRECT_URI`).
3. Set `FACEBOOK_APP_ID` and `FACEBOOK_APP_SECRET`. Optionally pin the Graph API version with `META_GRAPH_VERSION`.

Always requested: `pages_show_list`, `pages_read_engagement`, `pages_manage_posts`. Optional features request extra permissions only when their flag is set, because Meta rejects the whole login ("Invalid Scopes") when a requested permission isn't added to the app:

| Flag | Adds | Enables |
| --- | --- | --- |
| `FACEBOOK_ENABLE_INBOX=true` | `pages_messaging`, `pages_manage_metadata` | Messenger inbox |
| `FACEBOOK_ENABLE_INSIGHTS=true` | `read_insights` | Impressions, views and clicks in analytics |
| `FACEBOOK_ENABLE_BUSINESS_MANAGEMENT=true` | `business_management` | Pages owned through a Business portfolio |

> [!NOTE]
> `pages_show_list`, `pages_read_engagement` and `pages_manage_posts` need Advanced Access (App Review and Business Verification) before people without a role on the Meta app can connect.

Page tokens obtained this way don't expire. If one is invalidated (password change, app removed, Page role removed), the next publish marks the account `reconnect_required`.

## Post types & media rules

Choose the post type with `options.publishAs`:

| `publishAs` | Media | Notes |
| --- | --- | --- |
| `feed` (default) | None, 1–10 photos, or 1 video | Text-only posts can use `link` for a preview card |
| `reel` | Exactly 1 video | Vertical (9:16) video, 3–90 seconds per Facebook's requirements |
| `story` | Exactly 1 photo or 1 video | Stories have no caption; video max 60 seconds per Facebook's requirements |

| Rule | Limit |
| --- | --- |
| Text | 63,206 characters |
| Feed media | Photos **or** one video, not both; up to 10 photos |
| Feed post content | Needs text, a link, or media |
| `link` | Only used on text-only feed posts; ignored when media is attached |
| Thumbnail | JPEG, PNG or GIF up to 10 MB; feed videos and Reels only |
| Video title | 255 characters; feed videos and Reels only |
| `publishImmediately: false` | Feed posts only; Reels and Stories always publish immediately |

Reel and Story duration and aspect ratio are checked by Facebook during processing, not before the post is queued.

## Options

| Option | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `publishAs` | `feed` \\| `story` \\| `reel` | No | `"feed"` | Publish as. Text, images, and videos publish to the Page feed. |
| `link` | string (URL) | No |  | Link URL. When set on a text-only post, Facebook renders a link preview card from this URL's Open Graph tags. Ignored when media is attached. Only when `publishAs` is `feed`. |
| `thumbnail` | string (URL or media://) | No |  | Thumbnail. Custom cover for videos and reels. JPEG, PNG or GIF up to 10 MB, ideally the same aspect ratio as the video. Ignored for photos and text posts. Only when `publishAs` is `feed` or `reel`. |
| `title` | string | No |  | Video title. Optional title for videos and reels. Only when `publishAs` is `feed` or `reel`. |
| `publishImmediately` | boolean | No | `true` | Publish immediately. Turn off to create an unpublished Page post: it won't appear on your Page or in Feed, but can be used for ads or published later in Meta Business Suite. Stories and reels always publish immediately. |
`thumbnail` accepts an `http(s)` URL or a media library reference (`media://<id>`).

## Examples

### Link post

```bash tab="cURL"
curl -X POST https://social-publish-api.onrender.com/v1/posts \
  -H "x-access-key: $RELAYCAST_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "content": "Our 2026 product report is out.",
    "targets": [{
      "accountId": "9b2e4c61-3f7a-4d8e-b5c2-1a0f9e8d7c6b",
      "options": { "publishAs": "feed", "link": "https://example.com/report-2026" }
    }],
    "publishNow": true
  }'
```

```ts tab="Node.js"
const res = await fetch("https://social-publish-api.onrender.com/v1/posts", {
  method: "POST",
  headers: {
    "x-access-key": process.env.RELAYCAST_API_KEY!,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    content: "Our 2026 product report is out.",
    targets: [
      {
        accountId: "9b2e4c61-3f7a-4d8e-b5c2-1a0f9e8d7c6b",
        options: { publishAs: "feed", link: "https://example.com/report-2026" },
      },
    ],
    publishNow: true,
  }),
});
const { data } = await res.json();
```

```python tab="Python"
import os, requests

res = requests.post(
    "https://social-publish-api.onrender.com/v1/posts",
    headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
    json={
        "content": "Our 2026 product report is out.",
        "targets": [{
            "accountId": "9b2e4c61-3f7a-4d8e-b5c2-1a0f9e8d7c6b",
            "options": {"publishAs": "feed", "link": "https://example.com/report-2026"},
        }],
        "publishNow": True,
    },
)
data = res.json()["data"]
```

### Reel with title and thumbnail

```json title="Request body"
{
  "content": "60 seconds with our design team",
  "media": [{ "url": "https://cdn.example.com/design-team.mp4", "type": "video" }],
  "targets": [{
    "accountId": "9b2e4c61-3f7a-4d8e-b5c2-1a0f9e8d7c6b",
    "options": {
      "publishAs": "reel",
      "title": "Meet the design team",
      "thumbnail": "https://cdn.example.com/design-team-cover.jpg"
    }
  }],
  "scheduledFor": "2026-11-05T12:00:00Z"
}
```

### Unpublished photo post

```json title="Request body"
{
  "content": "Holiday sale creative",
  "media": [{ "url": "https://cdn.example.com/sale.jpg", "type": "image" }],
  "targets": [{
    "accountId": "9b2e4c61-3f7a-4d8e-b5c2-1a0f9e8d7c6b",
    "options": { "publishImmediately": false }
  }],
  "publishNow": true
}
```

## Analytics & comments

- **Analytics:** reactions (likes), comments and shares for every post. Impressions, views and clicks (and video/Reel play counts) come from Page insights and need `FACEBOOK_ENABLE_INSIGHTS=true` plus a reconnect.
- **Inbox:** Messenger conversations for the Page, with `FACEBOOK_ENABLE_INBOX=true`. Meta only allows replies within 24 hours of the person's last message. See [Inbox & Comment Automation](/docs/inbox).
- Comment automations are not available for Facebook.

## Limitations & common errors

| Error | Cause |
| --- | --- |
| `Facebook posts can have photos or one video, not both` | Mixed photos and video in a feed post. |
| `Facebook posts allow up to 10 photos` | More than 10 photos. |
| `A Facebook post needs text, a link, or media` | Empty feed post. |
| `A Facebook reel needs exactly one video` | Reels take one video and no photos. |
| `A Facebook story needs exactly one photo or one video` | Stories take a single item. |
| `Facebook stories always publish immediately …` | `publishImmediately: false` on a Reel or Story. |
| Login fails with "Invalid Scopes" | An optional flag is on but its permission isn't added to the Meta app. |
| Account becomes `reconnect_required` | The Page token was invalidated (Graph error 190). Reconnect from Integrations. |
| No Pages listed after login | Pages owned through a Business portfolio need `FACEBOOK_ENABLE_BUSINESS_MANAGEMENT=true`. |
