Relay
DocsLog inStart free

Instagram requirements

Instagram's publishing API has hard rules about account type, media format, and how often you may post. Relay enforces the ones it can check up front so you fail at upload time instead of at publish time — this page is what it checks, and why.

Account requirements

  • The Instagram account must be a professional account — Business or Creator. Personal accounts cannot publish through the API, and Relay rejects them during the connect flow rather than letting you discover it at publish time.
  • Relay connects through Instagram Login (the direct Instagram business login), so you don't need a linked Facebook Page.
  • Two permissions are requested: instagram_business_basic (read the profile) and instagram_business_content_publish (create and publish media).
  • Accounts in some regions or with certain restrictions may be excluded by Meta from API publishing entirely — that surfaces as a Graph error on the first publish.

Connecting an account

Start the flow from Accounts → Connect Instagram. Relay exchanges the authorization code for a long-lived token, reads the profile, and stores:

StoredWhy
access tokenEncrypted at rest with AES-256-GCM. Required for every publish call; never returned by any API.
Instagram user IDThe Graph-scoped account ID every publish call is addressed to.
username, name, avatarShown in the dashboard and on targets.
follower & media countsRefreshed once a day for the dashboard; never used for publishing.
token expiryDrives the refresh job and the connection health badge.

Token lifecycle

Long-lived Instagram tokens last 60 days and can be refreshed — but only while they're still alive. Relay runs a weekly refresh for every token expiring within 14 days, which in normal operation means a connection never lapses.

HealthMeaningCan publish?
connectedToken valid, more than 7 days left.Yes
expiringUnder 7 days left and the refresh has not succeeded yet.Yes — the token is valid until it actually expires.
reconnect_requiredThe token expired, was revoked, or Instagram rejected it (Graph error 190 / subcode 463). It cannot be refreshed.No — reconnect the account.
disconnectedRemoved from Relay, or revoked from the Instagram side via Meta’s deauthorize callback.No
Revoking Relay from Instagram's own settings notifies Relay immediately: the stored token is wiped and the account flips to disconnected. Meta's data-deletion request is honoured the same way — the account is deleted, or fully anonymized when post history prevents a hard delete.

Post types

TypeMediaNotes
feedExactly 1 JPEG imageAspect ratio must be between 4:5 and 1.91:1. Relay checks this at upload.
carousel2–10 images or videos, mixed allowedInstagram crops every slide to the first item’s ratio. Each slide can carry its own caption. Counts as one post against the quota.
reelExactly 1 videoSet share_to_feed: false to keep it off the profile grid; Instagram defaults to showing it.
story1 image or videoInstagram displays no caption on stories — a caption you send is stored on the post but not shown. Must be requested explicitly; never inferred.

Omit the type and Relay infers it: one image is a feed post, one video is a reel, two or more items is a carousel. Stories are the exception — ask for them by name.

Media specifications

The left column is Instagram's published specification. The right is what Relay enforces before accepting an upload, so a file that passes here will not be rejected later for format reasons.

Images

InstagramEnforced by Relay
JPEG only — PNG, HEIC, MPO, and JPS are rejectedYes for the API. The dashboard converts in your browser — drop any format and it uploads as JPEG.
8 MB maximumYes
Aspect ratio 4:5 – 1.91:1 (feed and carousel)Yes — parsed from the JPEG at upload. The dashboard fits images to the nearest accepted shape as you add them, and its editor can crop them instead.
Width 320–1440 px (scaled outside that range)The dashboard exports at 1080 px wide; the API leaves it to Instagram
sRGB colour spaceNo
9:16 recommended for storiesNo — stories accept any ratio
The dashboard and the REST/MCP API differ here on purpose. A browser can decode and re-encode an image; the API runs on Cloudflare Workers and cannot, so it accepts only what Instagram accepts and tells you what to convert.

Video (reels and stories)

PropertyInstagramEnforced by Relay
ContainerMP4 or MOVYes — image/jpeg, video/mp4, video/quicktime only
Video codecH.264 or HEVCNo
Audio codecAAC, ≤ 48 kHz, 1–2 channels, 128 kbpsNo
Frame rate23–60 FPSNo
Resolution≤ 1920 px wideNo
BitrateVBR, ≤ 25 MbpsNo
DurationReels 3 s – 15 min; stories 3 – 60 sNo — Instagram rejects at processing time
File sizeReels ≤ 300 MB; stories ≤ 100 MB100 MB for all video — Relay's own cap, below Instagram's
Anything Relay does not check is checked by Instagram after the post is queued. A video with an unsupported codec or an out-of-range duration fails during processing and lands on the target as container_error with Instagram's own message.

Captions

  • 1–2,200 characters. Relay rejects longer captions before they reach Instagram.
  • Hashtags and @mentions work inline; there is no markdown or rich text.
  • Stories ignore the caption entirely.
  • Carousel slides can each carry their own caption, 1–2,200 characters, shown on that slide. It is sent on that slide's child container, while the post's own caption goes on the parent — so a carousel can have both. Feed posts, reels, and stories have a single container and nowhere to put a per-item caption; Relay rejects one rather than dropping it silently.

First comment

first_comment is posted as a comment on the post the moment it goes live — the usual home for a hashtag block you would rather keep out of the caption. It is posted once per target account, on that account's own copy of the post, 1–2,200 characters. Stories take none: Instagram has no comments there, and Relay rejects one rather than dropping it.

It is attempted after the post is published, so it can never hold up or fail a publish. If Instagram refuses the comment, the post stays published with its permalink and the target carries a breadcrumb saying why; transient refusals are retried with a backoff for up to five attempts. Poll first_comment_status on the target (pending, posted, or failed) to see how it went.

Comments need their own permission. Posting comments requires the instagram_business_manage_comments scope, which is granted separately from publishing. An account connected before Relay asked for it does not have it — a token refresh never widens a granted scope, so the account has to be reconnected. Until then that account publishes normally and skips the first comment, and the composer says so next to the field. accounts_list reports it as can_comment.

Publishing quota

Instagram allows 100 API-published posts per account per rolling 24 hours. A carousel counts as one post regardless of how many items it holds. Relay checks the remaining quota before creating a media container.

At the ceiling, the post is not failed. The target keeps a quota_exceeded breadcrumb, the post stays in publishing, and the scheduler retries until a slot frees up — which happens automatically as older posts age out of the 24-hour window.

"error": {
  "code": "quota_exceeded",
  "message": "Instagram allows 100 API-published posts per 24h and this account is at the limit — Relay will keep retrying until a slot frees up"
}

Timing & retries

Publishing is a two-step handshake with Instagram: create a media container, wait for it to finish processing, then publish it. Relay drives that from a scheduler tick.

BehaviourValue
Scheduler intervalEvery minute
Posts claimed per tick10, oldest scheduled time first
Stalled-post reclaimA post stuck in publishing for 2 minutes is picked up again
Processing poll budget30 ticks (~30 minutes) before a container is declared timed out
Transient error retries5 attempts for HTTP 429 / 5xx and Graph code 4, then the target fails
Container validity24 hours, per Instagram — after that it expires
  • Images normally publish within the tick that claims them — a few seconds after schedule_at.
  • Video is transcoded by Instagram asynchronously. Expect a minute or several; the target sits in processing until it's ready.
  • Carousels create one child container per item, wait for all of them to finish, then create the parent. Each slide's own caption rides on its child container; the post caption goes on the parent. A single bad item fails the whole carousel.
  • Retries never duplicate a post: container IDs are persisted as they're created, so a reclaimed post resumes rather than starting over.

Failure reference

When a target fails, error.code tells you whose fault it was and whether to retry. Codes beginning graph_ are Instagram's own error codes, passed through with Instagram's message.

CodeCauseWhat to do
quota_exceededThe account hit 100 API posts in 24 hours.Nothing — Relay keeps retrying. Not a terminal failure.
auth_reconnect_requiredThe token expired or the user revoked access (Graph 190 / subcode 463).Reconnect the account, then create the post again.
account_disconnectedThe account was disconnected before the post ran.Reconnect and recreate.
container_errorInstagram rejected the media while processing it — bad codec, unsupported duration, corrupt file.Read the message, fix the file, upload again.
container_expiredThe media container went unpublished for 24 hours.Recreate the post.
child_error / child_expiredOne carousel item failed or expired.Fix that item and recreate the carousel.
processing_timeoutThe container never finished processing within ~30 minutes.Usually an oversized or unusual video — re-encode and retry.
published_unverifiedThe post went live but Relay lost the media ID mid-publish.Nothing — the post is live. The permalink is missing from the timeline.
graph_<code>A semantic rejection from Instagram, message included verbatim.Read the message — it is the actionable part.
http_<status>Instagram returned a non-JSON error.Retry later; contact support if it persists.
internalAn unexpected error inside Relay.Send the post ID to support@lantean.tech.

Not supported

  • PNG and other image formats. Instagram's publishing API takes JPEG only.
  • Text-only posts. Every Instagram post needs at least one media item.
  • Filters, shopping tags, and product tagging — not exposed by the publishing API.
  • Editing or deleting a published post. Once it's live, use the Instagram app. Relay can only cancel posts that haven't published yet.
  • Changing media, per-slide captions, or targets on an existing post. Cancel it and create a new one; only the post's own caption, its first comment, and its schedule are editable.
  • TikTok here. TikTok has its own rules — see TikTok requirements. A post can target both.

For the request and response shapes behind all of this, see the REST API reference or the MCP tool reference.

© 2026 Relaysupport@lantean.techPrivacyTerms