Platforms

Instagram

Publish feed posts, carousels, Reels and Stories to Instagram professional accounts.

Overview

The instagram platform publishes to Instagram professional (Business or Creator) accounts. Personal accounts cannot publish through the API. You can post:

  • A single image (JPEG) to the feed
  • A single video, published as a Reel
  • A carousel of 2–10 images and/or videos
  • A Reel (with optional cover, thumbnail frame, trial-reel mode, and "share to feed" toggle)
  • A Story (exactly one image or video)
  • Up to 3 collaborators on feed posts, carousels and Reels

Instagram does not support text-only posts: every post needs at least one image or video.

Connect the account

In Integrations, choose Instagram. There are two ways to connect, and both end up as the same Instagram account in Relaycast (reconnecting through either one updates the existing account):

Connect optionWhen to use itRequirements
Log in with Instagram (default)Most accounts. No Facebook Page needed.Instagram Business or Creator account
Log in with FacebookThe Instagram account is linked to a Facebook Page you manageInstagram professional account linked to a Facebook Page

Both options use the redirect URI https://social-publish-kappa.vercel.app/api/integrations/instagram/callback (override with INSTAGRAM_REDIRECT_URI).

Instagram Login setup (self-hosted)

  1. In your Meta app, add the Instagram product and open API setup with Instagram login.
  2. Use the Instagram app ID and secret shown there (not the Facebook app ID) for INSTAGRAM_APP_ID and INSTAGRAM_APP_SECRET.
  3. Under Set up Instagram business login → Business login settings, add the redirect URI above.

Scopes requested: instagram_business_basic, instagram_business_content_publish, instagram_business_manage_messages, instagram_business_manage_comments, instagram_business_manage_insights. Tokens are long-lived (60 days) and refreshed automatically before they expire.

Facebook Login setup (self-hosted)

  1. Use the Facebook app (FACEBOOK_APP_ID, FACEBOOK_APP_SECRET, the same one as Facebook Pages) with the Instagram use case Manage messages and content on Instagram.
  2. Add https://social-publish-kappa.vercel.app/api/integrations/instagram/callback to Facebook Login → Settings → Valid OAuth Redirect URIs.

Always requested: instagram_basic, instagram_content_publish, pages_show_list, pages_read_engagement. Optional features request more permissions only when their flag is set, because Meta rejects the whole login if a requested permission isn't added to the app:

FlagAddsEnables
INSTAGRAM_FB_ENABLE_COMMENTS=trueinstagram_manage_commentsComment replies and comment-to-DM automations
INSTAGRAM_FB_ENABLE_MESSAGES=trueinstagram_manage_messages, pages_manage_metadataDM inbox
INSTAGRAM_FB_ENABLE_INSIGHTS=trueinstagram_manage_insightsPost insights
FACEBOOK_ENABLE_BUSINESS_MANAGEMENT=truebusiness_managementPages owned through a Business portfolio

In development mode, only accounts with a role on the Meta app (and accepted Instagram testers) can connect. Publishing for other people needs Meta App Review for the permissions above.

Post types & media rules

Choose the post type with options.publishAs:

publishAsMediaResult
feed (default)1 imageFeed photo
feed1 videoReel, also shown in the feed
feed2–10 images and/or videosCarousel
reelExactly 1 videoReel (shareToFeed controls whether it also appears in the feed grid)
storyExactly 1 image or videoStory
RuleLimit
Caption2,200 characters
Hashtags30 per caption
@mentions20 per caption
Image formatJPEG only (URLs ending in .png, .gif, .webp, .heic, .avif, .bmp, .tiff are rejected)
Alt textSingle-image feed posts only, up to 1,000 characters
CollaboratorsUp to 3; not on Stories
Publishing quotaInstagram's rolling 24-hour publishing limit (100 posts by default). When it is used up, the target is retried later.

Media is fetched by Instagram from its URL, so it must be publicly reachable (media library files are served as signed URLs automatically). Size, duration and aspect-ratio checks are done by Instagram while it processes the media.

Options

OptionTypeRequiredDefaultDescription
publishAsfeed \reel \storyNo
shareToFeedbooleanNotrueAlso share reel to feed Only when publishAs is reel.
collaboratorsstring[]NoCollaborators. Invite accounts to co-author this post. They must accept the invitation in Instagram before it appears on their profile. Only when publishAs is feed or reel.
coverUrlstring (URL)NoReel cover image URL. Videos only. Public JPEG used as the cover in the Reels tab. Only when publishAs is feed or reel.
thumbOffsetnumberNoThumbnail frame (ms). Videos only. Millisecond offset of the frame used as the thumbnail. Ignored when a cover URL is set. Only when publishAs is feed or reel.
trialReeloff \MANUAL \SS_PERFORMANCENo
coverUrl and thumbOffset apply to videos only. trialReel requires publishAs: "reel".

Examples

Reel with collaborators and a cover

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": "Behind the scenes of our spring shoot #bts",
    "media": [{ "url": "https://cdn.example.com/bts.mp4", "type": "video" }],
    "targets": [{
      "accountId": "1d7e3f52-8c4a-4b9e-a0f1-7e6d5c4b3a29",
      "options": {
        "publishAs": "reel",
        "shareToFeed": true,
        "collaborators": ["studio.north"],
        "coverUrl": "https://cdn.example.com/bts-cover.jpg"
      }
    }],
    "scheduledFor": "2026-11-03T17:30:00Z"
  }'
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: "Behind the scenes of our spring shoot #bts",
    media: [{ url: "https://cdn.example.com/bts.mp4", type: "video" }],
    targets: [
      {
        accountId: "1d7e3f52-8c4a-4b9e-a0f1-7e6d5c4b3a29",
        options: {
          publishAs: "reel",
          shareToFeed: true,
          collaborators: ["studio.north"],
          coverUrl: "https://cdn.example.com/bts-cover.jpg",
        },
      },
    ],
    scheduledFor: "2026-11-03T17:30:00Z",
  }),
});
const { data } = await res.json();
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": "Behind the scenes of our spring shoot #bts",
        "media": [{"url": "https://cdn.example.com/bts.mp4", "type": "video"}],
        "targets": [{
            "accountId": "1d7e3f52-8c4a-4b9e-a0f1-7e6d5c4b3a29",
            "options": {
                "publishAs": "reel",
                "shareToFeed": True,
                "collaborators": ["studio.north"],
                "coverUrl": "https://cdn.example.com/bts-cover.jpg",
            },
        }],
        "scheduledFor": "2026-11-03T17:30:00Z",
    },
)
data = res.json()["data"]
Request body
{
  "content": "Three looks from the new collection",
  "media": [
    { "url": "https://cdn.example.com/look-1.jpg", "type": "image" },
    { "url": "https://cdn.example.com/look-2.jpg", "type": "image" },
    { "url": "https://cdn.example.com/look-3.mp4", "type": "video" }
  ],
  "targets": [{ "accountId": "1d7e3f52-8c4a-4b9e-a0f1-7e6d5c4b3a29" }],
  "publishNow": true
}

Story

Request body
{
  "content": "Story",
  "media": [{ "url": "https://cdn.example.com/story.jpg", "type": "image" }],
  "targets": [{ "accountId": "1d7e3f52-8c4a-4b9e-a0f1-7e6d5c4b3a29", "options": { "publishAs": "story" } }],
  "publishNow": true
}

The request still needs content (it is required for every post), but Stories have no caption.

Analytics & comments

  • Analytics: likes and comment counts for every post, plus Instagram insights (views, reach, shares, saves and more, depending on the media type). With Facebook Login, insights need INSTAGRAM_FB_ENABLE_INSIGHTS=true.
  • Inbox: Instagram DMs can be read and answered from the dashboard inbox.
  • Comments: comment-to-DM automations and public comment replies. See Inbox & Comment Automation.

Accounts connected before a permission was added must reconnect to use the feature.

Limitations & common errors

ErrorCause
Instagram posts need at least one image or videoText-only posts are not supported.
A reel needs exactly one videopublishAs: "reel" with images or several items.
A story needs exactly one image or videoStories take a single item.
A carousel allows 2-10 images and/or videosToo many items for a carousel.
Instagram only accepts JPEG imagesConvert PNG/WebP/HEIC images to JPEG.
Collaborators are not supported on storiesRemove collaborators for Stories.
Trial reels require post type ReelSet publishAs: "reel" to use trialReel.
Connect fails: only professional accountsSwitch the account to Business or Creator in the Instagram app.
Connect fails: no linked Instagram account (Facebook Login)Link the Instagram account to a Facebook Page and reconnect.
Target retried: publishing limit reachedThe account hit Instagram's 24-hour publishing quota.
Target fails with a media errorInstagram could not fetch or process the media (format, size, duration or aspect ratio).

This page is also available as Markdown.