> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hookmyapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Publish content

> Publish images, reels, stories, and carousels to your Instagram account.

## How publishing works

Publishing is a three-step flow:

1. Create a media container with your media URL and caption.
2. Poll the container until its `status_code` is `FINISHED`.<br />
   Images usually finish immediately. Videos take longer — poll about once per minute.
3. Publish the container.

There is no publish webhook. Polling is the only way to know a container is ready.<br />
Containers expire after 24 hours. Meta has no scheduled publishing — publish when you want the post live.

```bash theme={null}
# 1. Create a media container
curl -X POST "https://gateway.hookmyapp.com/meta/v25.0/${INSTAGRAM_ACCOUNT_ID}/media" \
  -H "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
  "image_url": "https://example.com/photo.jpg",
  "caption": "New drop"
}'
# → { "id": "17900000000000001" }

# 2. Poll until FINISHED
curl "https://gateway.hookmyapp.com/meta/v25.0/17900000000000001?fields=status_code" \
  -H "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}"
# → { "status_code": "FINISHED", "id": "17900000000000001" }

# 3. Publish
curl -X POST "https://gateway.hookmyapp.com/meta/v25.0/${INSTAGRAM_ACCOUNT_ID}/media_publish" \
  -H "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{ "creation_id": "17900000000000001" }'
# → { "id": "17850000000000000" }
```

Supply media as a **public HTTPS URL**. Meta downloads it from that URL — private links, localhost, and signed URLs that expire before the fetch all fail.<br />
Some hosts block Meta's fetcher; that surfaces as a misleading `Only photo or video can be accepted as media type` error. If you hit it, move the file to a host that serves it to any client.<br />
Videos should be H.264 + AAC in an MP4 container — other codecs pass the URL check but fail processing with container status `ERROR`.

## Media requirements

| Type     | Container fields                                                                    | Limits                                                             |
| -------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Image    | `image_url`                                                                         | JPEG only. Max 8 MB. Aspect ratio between 4:5 and 1.91:1           |
| Reel     | `media_type=REELS`, `video_url`, optional `cover_url`                               | Max 15 minutes, max 1 GB                                           |
| Story    | `media_type=STORIES`, `image_url` or `video_url`                                    | Video max 60 seconds. No stickers or links. Expires after 24 hours |
| Carousel | `media_type=CAROUSEL`, `children` (containers created with `is_carousel_item=true`) | Max 10 items. Reels cannot be carousel items                       |

## Trial reels

A trial reel goes out to people who don't follow you, so you can test a hook before it reaches your followers.<br />
Add `trial_params` to a reel container — it only works with `media_type=REELS`.

```bash theme={null}
curl -X POST "https://gateway.hookmyapp.com/meta/v25.0/${INSTAGRAM_ACCOUNT_ID}/media" \
  -H "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
  "media_type": "REELS",
  "video_url": "https://example.com/reel.mp4",
  "trial_params": { "graduation_strategy": "SS_PERFORMANCE" }
}'
```

| `graduation_strategy` | What happens                                                             |
| --------------------- | ------------------------------------------------------------------------ |
| `MANUAL`              | You graduate the reel to your followers yourself, from the Instagram app |
| `SS_PERFORMANCE`      | Instagram graduates it for you if it performs well                       |

Poll and publish the container exactly as you would for a normal reel.<br />
Meta gives you no way to read back whether an existing reel is a trial reel — track that on your side if you need it.

With MCP, ask for a trial reel and say who graduates it — the `publish_instagram_media` tool takes `trialParams.graduationStrategy` as `manual` or `automatic`.

```text theme={null}
Publish https://example.com/reel.mp4 as a trial reel on Instagram channel ch_xxxxxxxx, graduated automatically if it performs.
```

## Publishing quota

Meta allows 50 publishes per rolling 24 hours, currently being raised to 100.<br />
Check your live quota and usage:

```bash theme={null}
curl "https://gateway.hookmyapp.com/meta/v25.0/${INSTAGRAM_ACCOUNT_ID}/content_publishing_limit" \
  -H "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}"
```

Container creation has its own limit: 400 containers per 24 hours.

## Publish with the CLI

The CLI runs the whole container → poll → publish flow and prints the permalink.

```bash theme={null}
# Publish image
hookmyapp instagram publish --channel @your-handle --image https://example.com/photo.jpg --caption "New drop"

# Publish reel
hookmyapp instagram publish --channel @your-handle --video https://example.com/reel.mp4 --reel --cover https://example.com/cover.jpg

# Publish story
hookmyapp instagram publish --channel @your-handle --image https://example.com/story.jpg --story

# Publish carousel (prefix video items with video: — plain URLs are images)
hookmyapp instagram publish --channel @your-handle --carousel https://example.com/1.jpg,video:https://example.com/2.mp4 --caption "Gallery"
```

## Publish with MCP

Ask your agent to publish. The `publish_instagram_media` tool handles the full flow and returns the media ID and permalink.

```text theme={null}
Use HookMyApp MCP to publish https://example.com/photo.jpg to Instagram channel ch_xxxxxxxx with the caption "New drop".
```

See [MCP](/instagram/mcp-server) for setup.

## Next steps

* [Insights](/instagram/insights): Read reach and views for what you publish.
* [Comments](/instagram/comments): Reply to and moderate comments on your posts.
