Instagram supports several post types, and its publishing API treats each one a little differently. This tutorial shows how to publish a single image, a Reel, a carousel and a Story with Relaycast, and explains the two ways to connect an Instagram account.
Which Instagram accounts can publish?
Instagram's publishing API works with professional accounts, which means Business or Creator accounts. Personal accounts cannot publish through the API. If your account is personal, you can switch it to a professional account in the Instagram app's settings; it is free.
Two ways to connect
When you add Instagram under Integrations, you can connect in one of two ways. Both publish the same post types with the same options.
Instagram Login. You sign in with your Instagram credentials. No Facebook Page is required. This is the simplest option for most creators and businesses.
Facebook Login. You sign in with Facebook and choose an Instagram professional account that is linked to a Facebook Page you manage. Choose this if your Instagram account is already managed through a Facebook Page and Meta's business tools, or if your team's access is organised around Facebook Pages.
If you are not sure, start with Instagram Login.
Once connected, find the account ID with GET /v1/accounts (it has "platform": "instagram").
export RELAYCAST_API_URL="https://api.your-domain.com"
export RELAYCAST_API_KEY="your-key-here"The publishAs option
The Instagram target's publishAs option decides the post type:
publishAs | Media | Result |
|---|---|---|
feed (default) | 1 image | Image post |
feed | 1 video | Published as a Reel |
feed | 2 to 10 images and/or videos | Carousel |
reel | exactly 1 video | Reel |
story | exactly 1 image or video | Story |
Every Instagram post needs at least one image or video. Images must be JPEG. Captions can be up to 2,200 characters, with at most 30 hashtags.
A single image
curl -X POST "$RELAYCAST_API_URL/v1/posts" \
-H "x-access-key: $RELAYCAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Fresh out of the oven. #bakery #sourdough",
"media": [{ "url": "https://cdn.example.com/loaf.jpg", "type": "image", "altText": "A sourdough loaf on a wooden board" }],
"targets": [{ "accountId": "INSTAGRAM_ACCOUNT_ID" }],
"publishNow": true
}'await fetch(`${process.env.RELAYCAST_API_URL}/v1/posts`, {
method: "POST",
headers: { "x-access-key": process.env.RELAYCAST_API_KEY!, "Content-Type": "application/json" },
body: JSON.stringify({
content: "Fresh out of the oven. #bakery #sourdough",
media: [{ url: "https://cdn.example.com/loaf.jpg", type: "image", altText: "A sourdough loaf on a wooden board" }],
targets: [{ accountId: "INSTAGRAM_ACCOUNT_ID" }],
publishNow: true,
}),
});import os, requests
requests.post(
f"{os.environ['RELAYCAST_API_URL']}/v1/posts",
headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
json={
"content": "Fresh out of the oven. #bakery #sourdough",
"media": [{"url": "https://cdn.example.com/loaf.jpg", "type": "image", "altText": "A sourdough loaf on a wooden board"}],
"targets": [{"accountId": "INSTAGRAM_ACCOUNT_ID"}],
"publishNow": True,
},
)A Reel
Set publishAs to reel and attach one video. Reel-specific options:
shareToFeed(defaulttrue): also show the Reel in your profile grid, not only the Reels tab.coverUrl: a public JPEG to use as the cover in the Reels tab.thumbOffset: the frame, in milliseconds from the start, to use as the thumbnail. Ignored whencoverUrlis set.trialReel:off(default),MANUALorSS_PERFORMANCE. Trial Reels are shown to non-followers first;MANUALlets you decide later whether to share it with followers, whileSS_PERFORMANCEdoes so automatically if it performs well.collaborators: up to 3 usernames to invite as co-authors.
{
"content": "60-second focaccia. Recipe in the caption below.",
"media": [{ "url": "https://cdn.example.com/focaccia.mp4", "type": "video" }],
"targets": [
{
"accountId": "INSTAGRAM_ACCOUNT_ID",
"options": {
"publishAs": "reel",
"shareToFeed": true,
"coverUrl": "https://cdn.example.com/focaccia-cover.jpg",
"collaborators": ["partnerbakery"]
}
}
],
"publishNow": true
}Collaborators receive an invitation and must accept it in Instagram before the post appears on their profile.
A carousel
Keep publishAs as feed (or leave it out) and attach between 2 and 10 items. Images and videos can be mixed, and collaborators works here too. Alt text is applied to single-image posts; it is not sent for carousel items.
{
"content": "This week's specials, swipe through.",
"media": [
{ "url": "https://cdn.example.com/special-1.jpg", "type": "image", "altText": "Cardamom buns" },
{ "url": "https://cdn.example.com/special-2.jpg", "type": "image", "altText": "Rye loaves on a shelf" },
{ "url": "https://cdn.example.com/special-3.mp4", "type": "video" }
],
"targets": [{ "accountId": "INSTAGRAM_ACCOUNT_ID" }],
"publishNow": true
}A Story
Set publishAs to story and attach exactly one image or video. Collaborators are not available on Stories.
{
"content": "Open until 8pm today",
"media": [{ "url": "https://cdn.example.com/storefront.jpg", "type": "image" }],
"targets": [{ "accountId": "INSTAGRAM_ACCOUNT_ID", "options": { "publishAs": "story" } }],
"publishNow": true
}Validation catches mistakes early
All of these rules are checked when you create the post. A Reel with an image, a Story with two items, a PNG image URL, a carousel of 11, or a trial Reel on a feed post comes back as a 400 validation_error that names the field and the problem, before anything is published or any credits are used. The dashboard Playground shows the same messages live as you edit.
Media hosting
Instagram fetches media from a URL rather than receiving an upload, so your media must be reachable over the public internet. You can either use your own CDN URLs or upload files to your project's media library in the dashboard and reference them as media://<asset-id>. Library files are turned into short-lived signed URLs at publish time.
Cross-posting from the same request
Instagram often shares content with Facebook, Threads and others. Put them in the same request and give each target its own text or options:
{
"content": "60-second focaccia. Full recipe on our site.",
"media": [{ "url": "https://cdn.example.com/focaccia.mp4", "type": "video" }],
"targets": [
{ "accountId": "INSTAGRAM_ACCOUNT_ID", "content": "60-second focaccia. Recipe link in bio.", "options": { "publishAs": "reel" } },
{ "accountId": "FACEBOOK_ACCOUNT_ID" },
{ "accountId": "THREADS_ACCOUNT_ID" }
],
"publishNow": true
}Each target reports its own result, so if one network has a problem the others still go out.
Full details are in the Instagram platform guide.
Ready to build?
Get an access key and publish your first post in minutes.