Publish feed posts, stories, reels, and carousels to Instagram via the PostPeer API.
Overview
Publish feed posts, stories, reels, and carousels to Instagram through PostPeer's unified API. PostPeer handles the Instagram Graph API complexity, including the async media publishing flow.
Note: Instagram feed posts and Reels require a professional Business or Creator account. Story publishing requires a Business account. PostPeer uses Instagram Login, so a linked Facebook Page is not required.
Quick Start
1. Connect an Instagram Account
curl https://api.postpeer.dev/v1/connect/instagram \
-H "x-access-key: YOUR_API_KEY"Returns an Instagram authorization URL. The user must have an Instagram professional account. See Connect Accounts for the full OAuth flow.
2. Get the Account ID
curl https://api.postpeer.dev/v1/connect/integrations \
-H "x-access-key: YOUR_API_KEY"Find the integration with "platform": "instagram" and note the id.
3. Publish a Post
curl -X POST "https://api.postpeer.dev/v1/posts" \
-H "x-access-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "New product launch! #startup #launch",
"platforms": [
{ "platform": "instagram", "accountId": "ig_456" }
],
"mediaItems": [
{ "type": "image", "url": "https://cdn.example.com/photo.jpg" }
],
"publishNow": true
}'import PostPeer from '@postpeer/node';
const client = new PostPeer();
const { data } = await client.posts.create({
body: {
content: 'New product launch! #startup #launch',
platforms: [{ platform: 'instagram', accountId: 'ig_456' }],
mediaItems: [{ type: 'image', url: 'https://cdn.example.com/photo.jpg' }],
publishNow: true,
},
});from postpeer import PostPeer
with PostPeer() as client:
post = client.posts.create(
content="New product launch! #startup #launch",
platforms=[{"platform": "instagram", "accountId": "ig_456"}],
media_items=[
{"type": "image", "url": "https://cdn.example.com/photo.jpg"},
],
publish_now=True,
)Response:
{
"success": true,
"status": "published",
"postId": "post_def456",
"platforms": [
{
"platform": "instagram",
"success": true,
"platformPostUrl": "https://www.instagram.com/p/ABC123/"
}
]
}Features
Feed Posts
Single image or video posts with captions and hashtags. Instagram requires at least one media item — text-only posts are not supported.
Stories
Set platformSpecificData.contentType to "story" to publish one image or video as an Instagram Story:
curl -X POST "https://api.postpeer.dev/v1/posts" \
-H "x-access-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "",
"platforms": [
{
"platform": "instagram",
"accountId": "ig_456",
"platformSpecificData": {
"contentType": "story"
}
}
],
"mediaItems": [
{ "type": "image", "url": "https://cdn.example.com/story.jpg" }
],
"publishNow": true
}'import PostPeer from '@postpeer/node';
const client = new PostPeer();
const { data } = await client.posts.create({
body: {
content: '',
platforms: [
{
platform: 'instagram',
accountId: 'ig_456',
platformSpecificData: {
contentType: 'story',
},
},
],
mediaItems: [{ type: 'image', url: 'https://cdn.example.com/story.jpg' }],
publishNow: true,
},
});from postpeer import PostPeer
with PostPeer() as client:
story = client.posts.create(
content="",
platforms=[
{
"platform": "instagram",
"accountId": "ig_456",
"platformSpecificData": {
"contentType": "story",
},
},
],
media_items=[
{"type": "image", "url": "https://cdn.example.com/story.jpg"},
],
publish_now=True,
)Story publishing requires an Instagram Business account and exactly one image or video. Stories disappear after 24 hours. Instagram does not display the request's content as a Story caption, and its publishing API does not support interactive stickers such as links, polls, music, locations, or mentions.
Reels
Upload short-form vertical videos as Instagram Reels:
curl -X POST "https://api.postpeer.dev/v1/posts" \
-H "x-access-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Quick tutorial #reels",
"platforms": [
{ "platform": "instagram", "accountId": "ig_456" }
],
"mediaItems": [
{ "type": "video", "url": "https://cdn.example.com/reel.mp4" }
],
"publishNow": true
}'Custom Reel cover (thumbnail)
By default Instagram auto-picks a frame from the video as the Reel cover. To override, pass a public image URL via platformSpecificData.coverUrl, or a timestamp via platformSpecificData.thumbOffset. coverUrl takes precedence when both are set.
curl -X POST "https://api.postpeer.dev/v1/posts" \
-H "x-access-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Quick tutorial #reels",
"platforms": [
{
"platform": "instagram",
"accountId": "ig_456",
"platformSpecificData": {
"coverUrl": "https://cdn.example.com/reel-cover.jpg"
}
}
],
"mediaItems": [
{ "type": "video", "url": "https://cdn.example.com/reel.mp4" }
],
"publishNow": true
}'Requirements:
coverUrlmust be a publicly accessible HTTPS URL. JPEG or PNG.- The image aspect ratio should match the video (9:16 for Reels) — Instagram rejects mismatches.
thumbOffsetis an integer in milliseconds. Instagram extracts the video frame at that timestamp.- Both fields are ignored on non-video posts.
Share Reel to feed
Reels default to also appearing in the account's main feed grid. To publish to Reels only, pass shareToFeed: false:
"platformSpecificData": { "shareToFeed": false }Reel audio name
Pass audioName to set the name shown for the Reel's audio:
"platformSpecificData": { "audioName": "Original audio - yourbrand" }Instagram does not allow selecting a track from its music library through the API. the audio has to already be in the video file. audioName only labels it.
Trial Reels
Trial Reels are shown to non-followers first, so you can test a Reel before sharing it with your existing audience. Pass trialParams.graduationStrategy with one of these values:
MANUAL— keep the Reel as a trial until you choose to share it with followers in Instagram.SS_PERFORMANCE— let Instagram automatically share the Reel with followers when it performs well.
curl -X POST "https://api.postpeer.dev/v1/posts" \
-H "x-access-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Testing this tutorial with a new audience #reels",
"platforms": [
{
"platform": "instagram",
"accountId": "ig_456",
"platformSpecificData": {
"trialParams": {
"graduationStrategy": "MANUAL"
}
}
}
],
"mediaItems": [
{ "type": "video", "url": "https://cdn.example.com/reel.mp4" }
],
"publishNow": true
}'Trial Reels require exactly one video and cannot be used with Stories, images, or carousels. Availability also depends on the connected Instagram professional account being eligible for Trial Reels.
Carousels
Create carousel posts with up to 10 images or videos by passing multiple mediaItems:
curl -X POST "https://api.postpeer.dev/v1/posts" \
-H "x-access-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Swipe through our latest designs",
"platforms": [
{ "platform": "instagram", "accountId": "ig_456" }
],
"mediaItems": [
{ "type": "image", "url": "https://cdn.example.com/slide1.jpg" },
{ "type": "image", "url": "https://cdn.example.com/slide2.jpg" },
{ "type": "image", "url": "https://cdn.example.com/slide3.jpg" }
],
"publishNow": true
}'Media Requirements
| Type | Requirement |
|---|---|
| Image | JPG or PNG; aspect ratio from 4:5 through 1.91:1 |
| Carousel | Up to 10 JPG, PNG, MP4, or MOV items; use one aspect ratio throughout |
Reel specifications
| Specification | Instagram requirement |
|---|---|
| Container | MOV or MP4; no edit lists; moov atom at the front |
| Video | H.264 or HEVC; progressive scan; closed GOP; 4:2:0 chroma subsampling |
| Audio | AAC; 48 kHz maximum; mono or stereo; 128 kbps |
| Frame rate | 23-60 FPS |
| Picture size | Maximum 1,920 px wide; aspect ratio from 0.01:1 through 10:1 |
| Video bitrate | Variable bitrate, 25 Mbps maximum |
| Duration | 3 seconds-15 minutes |
| File size | 300 MB maximum |
Instagram recommends 9:16 video to avoid cropping or blank space. See Meta's Instagram Reel specifications for current requirements.
Platform-Specific Data
Pass this object in platformSpecificData when posting to Instagram. Use contentType to publish Stories; the remaining fields customize feed posts and Reels.
| Field | Type | Required | Values and constraints | Description |
|---|---|---|---|---|
contentType | string | No | story | Set to "story" to publish an Instagram Story. Omit for the existing behavior: images publish to Feed and videos publish as Reels. |
shareToFeed | boolean | No | — | Reels-only. When true (default), the Reel also appears in the account's main feed grid. Set false to publish to Reels only. |
trialParams | object | No | — | Reels-only. Publishes a single video as a Trial Reel, initially shown to non-followers. |
trialParams.graduationStrategy | string | Yes, when trialParams is provided | MANUAL, SS_PERFORMANCE | Controls how a Trial Reel is shared with followers. MANUAL keeps graduation manual; SS_PERFORMANCE lets Instagram share it automatically when it performs well. |
coverUrl | string | No | Format: uri | Video-only. Public URL of an image Instagram will use as the cover frame for the Reel/video post. Ignored for image posts. |
thumbOffset | integer | No | Range: 0–unbounded | Video-only. Timestamp in milliseconds Instagram extracts as the cover frame. Ignored when coverUrl is set or for image posts. |
audioName | string | No | Length: 1–100 | Reels-only. Sets the name shown for the Reel audio. Instagram does not allow selecting a track from its music library via the API, so the audio must already be in the video file; this only labels it. |
collaborators | string[] | No | Items: 1–3 | Feed posts, carousels, and Reels only. Up to three Instagram usernames to invite as collaborators. Each account must accept the invitation in Instagram. |