AI Schedule Instagram Posts via the Graph API
Use AI to draft captions and a posting calendar, then put Instagram publishing on rails with the official Content Publishing API — containers in, posts out, limits enforced.
Goal of This Task
Instagram's official Content Publishing API publishes in two steps: create a media container, then publish it. This task puts that flow on rails — AI drafts the captions and the weekly schedule, then generates the small script that walks the API for you, so a week of posts goes out from one working session.
Recommended Workflow
Step 1: Set up the professional account and token
API publishing only works on an Instagram professional account. Then pick one of the two documented login paths: Instagram Login (token from graph.instagram.com, permissions instagram_business_basic + instagram_business_content_publish) or Facebook Login for Business (Page token from graph.facebook.com, permissions instagram_basic + instagram_content_publish + pages_read_engagement). Both app paths require Advanced or Standard Access. Sanity-check the setup by calling GET /{ig-user-id}/content_publishing_limit — it returns the account's current publish quota.
You are my Instagram content assistant. Here are 5 post drafts about [topic]. For each one, write a caption under 150 words with a spoken-style first line, 3-5 relevant hashtags, and label the media type (single image, carousel with N slides, or reel). Return the result as a JSON array with the keys: filename, media_type, caption, hashtags. Keep every caption consistent with this voice sample: [paste one past caption you liked].
Step 2: Batch the content calendar with AI
Give the AI your posting days, not just your captions. Ask it to spread the week so carousel-heavy days do not land back to back, and to output the same JSON shape your scheduler script will consume. The calendar, the captions, and the script input should be one file — that is what makes the rest automatable.
Step 3: Create the media container
Publishing starts with POST /{ig-user-id}/media. For a single image, send image_url pointing at a publicly hosted JPEG — Meta fetches the file server-side, so local paths do not work. For video, send video_url plus media_type set to VIDEO, REELS, or STORIES; very large videos can go through the resumable endpoint POST https://rupload.facebook.com/ig-api-upload/{container-id}. For a carousel, create one child container per slide with is_carousel_item=true, then a parent container with media_type=CAROUSEL and a comma-separated children list of up to 10 child container IDs. Every container call returns an id you will publish against.
Step 4: Poll the container, then publish
Video containers need processing time. Poll GET /{ig-container-id}?fields=status_code — Meta suggests once per minute, for no more than 5 minutes — until it returns FINISHED (the other states are IN_PROGRESS, EXPIRED, ERROR, and PUBLISHED). Then publish with POST /{ig-user-id}/media_publish and creation_id set to the container id. The status check is documented as optional, so image containers can be published as soon as they are created; carousels publish as one post from the parent container.
Write a Python script that reads posts.json (filename, media_type, caption, scheduled_time) and, for each post whose scheduled_time has passed: creates the media container via the official Graph API, polls status_code once per minute up to 5 minutes for video, publishes via media_publish with creation_id, and logs the result to a runs.log file. Before each publish, call the content-publishing limit endpoint and skip with a warning if the remaining quota is zero. Read the access token and IG user ID from environment variables, never from the source file. Use only endpoints from Meta's content-publishing documentation.
Step 5: Enforce the limit inside your own scheduler
Instagram accounts are limited to 100 API-published posts within a 24-hour moving period, and the limit is enforced at the media_publish step — a container that was fine to create can still fail to publish. Meta recommends your app enforce the quota itself, so keep the content_publishing_limit check in the loop and space posts out instead of bursting. Carousels count as one post against the limit.
Recommended Tool Stack
| Tool | Use Case | Free? |
|---|---|---|
| Graph API Explorer | Mint a test token and walk the container-publish flow once by hand | Yes |
| cURL or any HTTP client | One-off container and publish calls while debugging | Yes |
| Your own scheduler (cron, GitHub Actions) | Running the generated script on a fixed schedule | Yes |
Platform Notes
- The API publishes to professional accounts only — personal accounts are out of scope for this flow.
- The 100-posts/24h limit is enforced at
media_publish; Meta's carousel section separately mentions a 50-post figure, so if you publish carousels at volume, design to the lower number. - Images must be JPEG and hosted on a publicly accessible server; carousel children crop to match the first image (1:1 by default).
status_codepolling is how you catch video processing failures — treatERRORas a stop, not a retry, until you know the media specs are right.
FAQ
Can I automate posting from a personal Instagram account?
No. The Content Publishing API requires an Instagram professional account, and that account type is the gate for every step in this task.
How many posts can the API publish per day?
Meta's doc states 100 API-published posts within a 24-hour moving period, with carousels counting as one post. The limit is enforced at media_publish, so your scheduler should check content_publishing_limit before each publish rather than assuming the count.
Where do my images and videos need to live?
On a publicly accessible server — Meta fetches the URL server-side when you create the container. A file on your laptop or a private drive will not reach the API. For large videos, use the resumable upload endpoint instead of a public URL.
Why did media_publish fail right after a successful container call?
Two usual causes: the container was not FINISHED yet (poll status_code first, especially for video), or the account hit the 24-hour publish quota. The container step succeeding says nothing about either.
Do Reels and Stories work through this API?
The documented container flow accepts media_type values of VIDEO, REELS, STORIES, and CAROUSEL. Reels and Stories follow the same poll-then-publish pattern as standard video, so the scheduler script does not need a separate code path — just the right media type per post.