# Post Stories via API to Instagram & Facebook

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

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

Stories are ephemeral posts that disappear after 24 hours. OmniSocials supports stories on Instagram and Facebook. Snapchat stories are on the roadmap.

Stories use the same `POST /posts/create` endpoint as regular posts. The difference is `type: "story"` and the fact that media is required. A story can carry up to 10 slides: every media item you pass is one slide, and each slide publishes as its own story on the platform, in the order given.

## Supported channels

| Channel ID | Platform | Supported |
|------------|----------|-----------|
| `instagram` | Instagram | ✅ |
| `facebook` | Facebook | ✅ |
| `snapchat` | Snapchat | _coming soon_ |

Calling `POST /posts/create` with `type: "story"` and a channel that does not support stories (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": "story",
    "accounts": ["your-instagram-account-id"],
    "media_urls": ["https://example.com/story.jpg"]
  }'
```

Stories always require at least one media file. A story request with no `media_ids` and no `media_urls` returns `400`.

## Multi-slide stories

Pass several media items to publish several slides in one post. The order of the array is the publish order.

```json
{
  "type": "story",
  "accounts": ["your-instagram-account-id"],
  "media_urls": [
    "https://example.com/slide-1.jpg",
    "https://example.com/slide-2.mp4",
    "https://example.com/slide-3.jpg"
  ]
}
```

How it works:

- Instagram and Facebook have no multi-slide story container. OmniSocials publishes one story per slide, one after the other, so they appear in sequence on the profile.
- Max 10 slides per platform. More than 10 returns `400 validation_error`.
- Each video slide is limited on its own (60 seconds, see Media requirements). A validation error names the slide that is over the limit.
- If a slide fails, the slides before it stay live. A retry (`POST /posts/{id}/retry`) publishes only the slides that did not go out. No slide is published twice.
- Each slide publish counts toward Instagram's 100 API publishes per 24 hours.

After publishing, the post carries a `story_slides` field with every slide per platform, in publish order:

```json
{
  "published_urls": { "instagram": "https://www.instagram.com/stories/acme/1789..." },
  "story_slides": {
    "instagram": [
      { "index": 0, "native_post_id": "1789...", "url": "https://www.instagram.com/stories/acme/1789...", "media_type": "image", "published_at": "2026-08-21T10:00:05Z" },
      { "index": 1, "native_post_id": "1790...", "url": "https://www.instagram.com/stories/acme/1790...", "media_type": "video", "published_at": "2026-08-21T10:00:41Z" }
    ]
  }
}
```

`published_urls` keeps the first slide per platform, so existing integrations keep working. `GET /analytics/posts/{id}` returns the summed metrics per platform plus a `story_slides` array with each slide's own metrics.

## Text on stories

Stories do not have captions the way feed posts do. The `content` field is optional on stories and, when provided, is used as internal notes in your OmniSocials dashboard. It is not rendered on the published story.

If you want text to appear on the story visual itself, bake it into the image or video before uploading. OmniSocials does not composite text onto media at publish time.

## Cross-posting a story to Instagram and Facebook

Pass both account IDs. Both platforms get the same media.

```json
{
  "type": "story",
  "accounts": [
    "your-instagram-account-id",
    "your-facebook-page-account-id"
  ],
  "media_urls": ["https://example.com/story-9x16.jpg"]
}
```

If you need different visuals for each (e.g. to tune the crop or overlay), use the per-platform `media_urls` shape with channel IDs as keys:

```json
{
  "type": "story",
  "accounts": [
    "your-instagram-account-id",
    "your-facebook-page-account-id"
  ],
  "media_urls": {
    "instagram": ["https://example.com/ig-story.jpg"],
    "facebook": ["https://example.com/fb-story.jpg"]
  }
}
```

## Media requirements

| Platform | Image | Video |
|----------|-------|-------|
| Instagram | JPEG or PNG, 9:16 recommended | MP4, up to 60 seconds, max 300 MB |
| Facebook | JPEG or PNG, 9:16 recommended | MP4, up to 60 seconds |

Stories on both platforms prefer a 9:16 vertical aspect ratio (e.g. 1080 × 1920). Images outside 9:16 are still accepted but are center-cropped or letterboxed by the platform.

## Carousels in stories

There is no swipeable carousel inside one story. Several media items become several consecutive stories (see Multi-slide stories above). That is how the native apps behave too.

## Scheduling stories

Stories are schedulable the same way as feed posts. Add `schedule_at` (ISO 8601 UTC) and OmniSocials publishes the story at the scheduled time.

```json
{
  "type": "story",
  "accounts": ["your-instagram-account-id"],
  "media_urls": ["https://example.com/story.jpg"],
  "schedule_at": "2026-04-18T14:00:00Z"
}
```

Because stories only live for 24 hours, scheduling them for a specific moment (e.g. "go live when my campaign starts") is usually more useful than the fire-and-forget pattern of feed posts.

## What happens after 24 hours

OmniSocials does not delete the story record from your workspace after the 24 hour window closes. The post still appears in `GET /posts` with `status: "published"`. The `published_urls` field still points at the now-expired story on the platform. Clicking the URL after 24 hours typically returns a 404 or redirects to the account's profile.

If you want to archive a story (save it permanently to your profile's Highlights or similar), do that in the native app. OmniSocials does not currently expose a "highlight" action through the API.

## Limitations

- A story has no swipeable carousel. Several media items publish as consecutive stories (max 10).
- The `content` field is not rendered on the story itself. Any text you want visible must be baked into the media.
- Stories cannot be updated after publishing. To change a story, delete and recreate. Deleting a Facebook story removes every slide; Instagram stories must be deleted in the Instagram app.
- `first_comment` is ignored on stories (platforms do not support comments on stories), and a hashtag set with `hashtag_placement: "first_comment"` falls back to the caption.
- `type: "story"` is rejected on platforms that do not support stories (all platforms except Instagram and Facebook today). Mixing story-capable and non-story-capable channels in the same `accounts` array returns `400`.
- Snapchat Spotlight and Stories are on the roadmap, not shipped yet

## Related reading

- [Creating Posts](/creating-posts) for the full field reference
- [Cross-Posting](/cross-posting) for the one-request-many-platforms model
- [Platforms](/platforms) for per-platform media specs
