# Post Reels via API to Instagram & TikTok

import { TechArticle } from "../components/TechArticle";

<TechArticle slug="creating-reels" fm={frontmatter} />

Reels are short-form vertical videos. OmniSocials supports reels on Instagram, Facebook, YouTube (as Shorts), and TikTok. A single `POST /posts/create` call with `type: "reel"` can fan out a reel to all four platforms at once.

## Supported channels

| Channel ID | Platform | Format | Max duration |
|------------|----------|--------|--------------|
| `instagram` | Instagram Reels | Vertical 9:16 | 15 minutes |
| `facebook` | Facebook Reels | Vertical 9:16 | 240 minutes |
| `youtube` | YouTube Shorts | Vertical 9:16 | 3 minutes |
| `tiktok` | TikTok | Vertical 9:16 or 16:9 | 10 minutes |

Calling with `type: "reel"` and a channel that does not support reels (LinkedIn, X, Pinterest, etc.) returns `400`.

## Minimal example

```bash
curl -X POST https://api.omnisocials.com/v1/posts/create \
  -H "Authorization: Bearer $OMNISOCIALS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "reel",
    "content": { "default": "New drop 🔥" },
    "accounts": ["your-instagram-account-id"],
    "media_urls": ["https://example.com/reel.mp4"]
  }'
```

Reels always require a single video file. Image-only or multi-video reel requests return `400`.

## Cross-posting a reel across all four platforms

Include every channel ID in `accounts` and use per-platform options for each platform's specific requirements.

```json
{
  "type": "reel",
  "content": {
    "default": "Behind the scenes from today's shoot",
    "tiktok": "POV: behind the scenes 🎬",
    "youtube": "How we filmed today's shoot #shorts"
  },
  "accounts": [
    "your-instagram-account-id",
    "your-facebook-page-account-id",
    "your-youtube-account-id",
    "your-tiktok-account-id"
  ],
  "media_urls": ["https://example.com/vertical-video.mp4"],
  "instagram": {
    "share_to_feed": true,
    "thumbnail_type": "from-video",
    "thumb_offset": 3000
  },
  "youtube": {
    "title": "Behind the scenes",
    "privacy_status": "public",
    "notify_subscribers": true
  },
  "tiktok": {
    "privacy_level": "PUBLIC_TO_EVERYONE",
    "disable_duet": false,
    "disable_stitch": false
  }
}
```

Every platform-specific key only applies to its own channel. Instagram ignores the `youtube` and `tiktok` blocks. YouTube ignores the `instagram` and `tiktok` blocks. And so on.

## Platform-specific options

Each reel-capable platform has its own set of options. Pass them under the matching channel ID key.

### Instagram reel options

| Field | Type | Description |
|-------|------|-------------|
| `instagram.share_to_feed` | boolean | Also show the reel on the profile feed grid |
| `instagram.thumbnail_type` | string | `from-video` or `from-library` |
| `instagram.thumb_offset` | number | Timestamp in milliseconds, used when `thumbnail_type` is `from-video` |
| `instagram.cover_url` | string | URL of a custom cover image, used when `thumbnail_type` is `from-library` |
| `instagram.audio_id` | string | Licensed music track to attach, from [`GET /audio/search`](#instagram-reel-music) |
| `instagram.audio_volume` | integer | Music volume 0–100 (default 100). Only used with `audio_id`. |
| `instagram.video_volume` | integer | Volume of the video's own audio 0–100 (default 100). Set `0` for a music-only reel. |
| `instagram.is_trial_reel` | boolean | Publish as a [Trial Reel](#instagram-trial-reels): shown to non-followers first to test performance. Not available on every account. |
| `instagram.trial_graduation_strategy` | string | `MANUAL` (default) or `SS_PERFORMANCE`. How a Trial Reel graduates to all followers. Only used with `is_trial_reel`. |

#### Instagram Trial Reels

A Trial Reel is shown to **non-followers first** so you can test how content performs before (optionally) sharing it with your followers. Set `instagram.is_trial_reel: true` on a reel to publish it as a trial:

```json
{
  "type": "reel",
  "content": { "default": "Testing a new format 👀" },
  "accounts": ["your-instagram-account-id"],
  "media_urls": ["https://example.com/reel.mp4"],
  "instagram": {
    "is_trial_reel": true,
    "trial_graduation_strategy": "SS_PERFORMANCE"
  }
}
```

`trial_graduation_strategy` controls how the trial graduates to all your followers:

- `MANUAL` (default): you decide when (or whether) to share it with followers, from the Instagram app.
- `SS_PERFORMANCE`: Instagram automatically shares it with your followers if it performs well.

`GET /posts/{id}` echoes both fields back under `instagram`, so you can verify a batch of scheduled Trial Reels programmatically.

**Eligibility:** Trial Reels are **not available on every account**. Instagram requires roughly 1,000+ followers and enables the feature per account; you can check eligibility by creating a reel in the Instagram app and looking for the "Trial" toggle. Ineligible accounts fail at publish time with a clear per-platform error on the post's `errors` map.

#### Instagram reel music

Search Meta's licensed catalog with `GET /audio/search?q=...` (omit `q` for currently trending audio; add `type=original_sound` to search original sounds instead of licensed music). Pass the chosen result's `audio_id` as `instagram.audio_id` and mix levels with `audio_volume` / `video_volume`:

```json
{
  "type": "reel",
  "content": { "default": "New drop 🎵" },
  "accounts": ["your-instagram-account-id"],
  "media_urls": ["https://example.com/reel.mp4"],
  "instagram": {
    "audio_id": "587784541076604",
    "audio_volume": 80,
    "video_volume": 0
  }
}
```

Notes:

- **Reels only.** Meta's API does not support adding music to feed posts, carousels, or Stories; that remains app-only.
- Only tracks Meta has **licensed for third-party publishing** appear in search results, so the selection can differ from the native app.
- Requires a **Facebook account connected** to the workspace whose Facebook Page is linked to the same Instagram account (music publishing runs through Facebook's side of the Instagram API). If it isn't, `GET /audio/search` returns `needsFacebook: true` and publishing a reel with `audio_id` fails with a clear error before anything goes live.

### YouTube Shorts options

| Field | Type | Description |
|-------|------|-------------|
| `youtube.title` | string | Video title, max 100 characters. When omitted: the first line of the caption, else `"YouTube Short"`. |
| `youtube.tags` | array | Discovery tags. Max 500 characters total. |
| `youtube.privacy_status` | string | `public`, `private`, or `unlisted` |
| `youtube.category_id` | string | YouTube category. Defaults to `"22"` (People & Blogs). |
| `youtube.made_for_kids` | boolean | COPPA disclosure. Disables comments and interactions when true. |
| `youtube.notify_subscribers` | boolean | Send the subscriber notification when published |
| `youtube.contains_synthetic_media` | boolean | Disclose AI-generated content |

### TikTok options

| Field | Type | Description |
|-------|------|-------------|
| `tiktok.privacy_level` | string | **Required.** `PUBLIC_TO_EVERYONE`, `MUTUAL_FOLLOW_FRIENDS`, `FOLLOWER_OF_CREATOR`, `SELF_ONLY` |
| `tiktok.disable_comment` | boolean | Disable comments on the reel |
| `tiktok.disable_duet` | boolean | Disable duets |
| `tiktok.disable_stitch` | boolean | Disable stitches |
| `tiktok.video_cover_timestamp_ms` | integer | Timestamp (ms) of the frame to use as the cover |
| `tiktok.is_aigc` | boolean | Disclose AI-generated content |
| `tiktok.brand_content_toggle` | boolean | Mark as a paid partnership promoting a third-party brand |
| `tiktok.brand_organic_toggle` | boolean | Mark as promoting your own business / brand |

TikTok requires `privacy_level` on every reel. Omitting it returns `400`.

### Facebook Reels

Facebook has no specific reel option fields. The default reel body works.

## Different video per platform

Sometimes you want a slightly different cut for each platform (e.g. a shorter version for YouTube Shorts where the limit is 3 minutes, and a longer cut for TikTok where the limit is 10 minutes). Use the per-platform `media_urls` shape:

```json
{
  "type": "reel",
  "content": { "default": "Full tutorial" },
  "accounts": [
    "your-youtube-account-id",
    "your-tiktok-account-id"
  ],
  "media_urls": {
    "youtube": ["https://example.com/tutorial-60s.mp4"],
    "tiktok": ["https://example.com/tutorial-full.mp4"]
  },
  "youtube": {
    "title": "Quick tutorial #shorts",
    "privacy_status": "public"
  },
  "tiktok": {
    "privacy_level": "PUBLIC_TO_EVERYONE"
  }
}
```

## Media requirements

| Platform | Format | Aspect | Duration | File size |
|----------|--------|--------|----------|-----------|
| Instagram | MP4 | 9:16 | Up to 15 minutes | Up to 300 MB |
| Facebook | MP4 | 9:16 | Up to 240 minutes | Up to 1 GB |
| YouTube Shorts | MP4 | 9:16 | Up to 3 minutes | Up to 256 GB |
| TikTok | MP4 or MOV | 9:16 or 16:9 | 3 seconds to 10 minutes | Up to 4 GB |

Videos outside these constraints are rejected at publish time. OmniSocials does not transcode, trim, or re-encode.

The safest format for cross-platform reels: MP4, H.264 codec, 1080 × 1920 vertical, under 3 minutes (YouTube Shorts is the tightest), under 300 MB (Instagram is the tightest). That passes every platform's requirements.

## Thumbnails and cover images

The simplest way to set a cover is the top-level `video_cover` object, which works for every platform in one place (see [Video covers](/creating-posts#video-covers)):

```json
{
  "type": "reel",
  "content": { "default": "Behind the scenes" },
  "accounts": ["your-instagram-account-id", "your-facebook-page-id", "your-tiktok-account-id"],
  "media_urls": ["https://example.com/reel.mp4"],
  "video_cover": { "type": "custom", "cover_url": "https://example.com/cover.jpg" }
}
```

Per platform:

- **Instagram**: default is the first frame. `video_cover` applies, or override with `instagram.thumb_offset` (pick a video frame) or `instagram.cover_url` (supply a custom image).
- **Facebook**: default is the first frame. `video_cover` applies, or use `facebook.thumbnail_type` with `thumb_offset` or `cover_url`. The thumbnail is set after the reel is live; if Facebook refuses it, the reel still publishes with the default frame.
- **YouTube Shorts**: `video_cover` applies (a custom image or a video frame, sent with `thumbnails.set` at up to 1080 x 1920), but YouTube shows it on Shorts only on channels where it has enabled custom Shorts thumbnails (rolling out since July 2026, YouTube Partner Program channels first). On other channels YouTube stores the cover but displays a frame from the video on the Shorts tab and in the Shorts feed; there the thumbnail can only be changed by picking a frame in the YouTube app. Channels that are not verified cannot set custom thumbnails at all.
- **TikTok**: frame only. TikTok's API takes a timestamp, not an image, so a `custom` cover is skipped and the frame from `video_cover` (or `tiktok.video_cover_timestamp_ms`) is used. Set `video_cover.overrides.tiktok` to `{ "type": "frame", "thumb_offset": 2000 }` to pick a different frame for TikTok when the other platforms get an image.

## Scheduling reels

Reels are schedulable the same way as feed posts. Add `schedule_at` (ISO 8601 UTC).

```json
{
  "type": "reel",
  "content": { "default": "Friday feature" },
  "accounts": [
    "your-instagram-account-id",
    "your-tiktok-account-id"
  ],
  "media_urls": ["https://example.com/reel.mp4"],
  "tiktok": { "privacy_level": "PUBLIC_TO_EVERYONE" },
  "schedule_at": "2026-04-18T14:00:00Z"
}
```

## Limitations

- Reels must have exactly one video. Multi-video or image reels are rejected.
- `type: "reel"` is rejected on platforms that do not support reels. Mixing reel-capable and non-reel-capable channels in the same `accounts` array returns `400`.
- YouTube Shorts require the channel to be monetization-eligible on YouTube. Non-eligible channels can still publish but the video may appear as a regular video instead of a Short.
- TikTok branded-content reels (`brand_content_toggle: true`) go through TikTok's review workflow and may take longer to publish.
- Instagram enforces a 75-day maximum lookahead for scheduled reels. Scheduling further out returns `400`.

## Related reading

- [Creating Posts](/creating-posts) for the full field reference
- [Cross-Posting](/cross-posting) for the one-request-many-platforms model
- [Creating Stories](/creating-stories) for the ephemeral story workflow
- [Instagram](/platforms/instagram), [TikTok](/platforms/tiktok), [YouTube](/platforms/youtube) for full per-platform specs
