Anyone who regularly posts on Instagram knows the drill: open the app, upload a photo, write a caption, add hashtags, hit publish. But what if you could automate this entire process? With the Instagram Graph API and a Meta Business Suite account, you can create and even schedule posts fully automatically via a REST API.

In this article, I'll show you how to set everything up and share working code examples you can adapt for your own projects.

Prerequisites

Before you can get started, you need a few things:

  • An Instagram Business or Creator Account
  • A Facebook Page linked to that Instagram account
  • A Meta Developer Account and an app in the Meta Developer Portal
  • A valid Access Token with the required permissions

Setting Up the Meta App

Head over to the Meta for Developers portal and create a new app (type: Business). In the app dashboard, add the Instagram Graph API product. Then, under App Review, request the following permissions:

  • instagram_basic
  • instagram_content_publish
  • pages_read_engagement

For testing purposes, you can use a short-lived token from the Graph API Explorer. For production, you should implement the OAuth flow to get a long-lived token.

Finding Your Instagram Business Account ID

Before publishing, you need your Instagram Business Account ID. You can retrieve it through the linked Facebook Page:

curl -X GET \
  "https://graph.facebook.com/v21.0/me/accounts?access_token={ACCESS_TOKEN}"

This returns the pages you manage. Take the id of the relevant page and query the linked Instagram account:

curl -X GET \
  "https://graph.facebook.com/v21.0/{PAGE_ID}?fields=instagram_business_account&access_token={ACCESS_TOKEN}"

The response contains the instagram_business_account.id — save it, you'll need it for every publish request.

Publishing a Post — Two-Step Process

The Instagram Graph API uses a two-step publishing flow:

  1. Create a media container — upload the image URL and caption
  2. Publish the container — actually post it to your feed

Step 1: Create the Media Container

curl -X POST \
  "https://graph.facebook.com/v21.0/{IG_USER_ID}/media" \
  -d "image_url=https://example.com/my-image.jpg" \
  -d "caption=My automated post! 🚀 #automation #api" \
  -d "access_token={ACCESS_TOKEN}"

The response returns a creation_id which represents your media container.

Step 2: Publish the Container

curl -X POST \
  "https://graph.facebook.com/v21.0/{IG_USER_ID}/media_publish" \
  -d "creation_id={CREATION_ID}" \
  -d "access_token={ACCESS_TOKEN}"

That's it — your post is now live on Instagram!

Scheduling Posts for Later

Instead of publishing immediately, you can schedule posts for a future time. Simply add the published and scheduled_publish_time parameters when creating the media container:

curl -X POST \
  "https://graph.facebook.com/v21.0/{IG_USER_ID}/media" \
  -d "image_url=https://example.com/my-image.jpg" \
  -d "caption=Scheduled post 📅 #automation" \
  -d "published=false" \
  -d "scheduled_publish_time={UNIX_TIMESTAMP}" \
  -d "access_token={ACCESS_TOKEN}"

The scheduled_publish_time must be a Unix timestamp between 10 minutes and 75 days in the future. After creating the container, publish it the same way — Instagram will hold it until the scheduled time.

A Complete Example in Python

Here's a practical Python script that ties it all together:

import requests
import time

ACCESS_TOKEN = "your_access_token"
IG_USER_ID = "your_instagram_business_account_id"
BASE_URL = "https://graph.facebook.com/v21.0"

def create_post(image_url: str, caption: str, schedule_time: int = None):
    # Step 1: Create media container
    payload = {
        "image_url": image_url,
        "caption": caption,
        "access_token": ACCESS_TOKEN,
    }

    if schedule_time:
        payload["published"] = "false"
        payload["scheduled_publish_time"] = schedule_time

    resp = requests.post(f"{BASE_URL}/{IG_USER_ID}/media", data=payload)
    resp.raise_for_status()
    creation_id = resp.json()["id"]
    print(f"Media container created: {creation_id}")

    # Step 2: Publish the container
    publish_resp = requests.post(
        f"{BASE_URL}/{IG_USER_ID}/media_publish",
        data={
            "creation_id": creation_id,
            "access_token": ACCESS_TOKEN,
        },
    )
    publish_resp.raise_for_status()
    post_id = publish_resp.json()["id"]
    print(f"Post published: {post_id}")
    return post_id


# Publish immediately
create_post(
    image_url="https://example.com/photo.jpg",
    caption="Hello from the API! 🤖 #automation #python",
)

# Schedule for 24 hours from now
create_post(
    image_url="https://example.com/photo2.jpg",
    caption="Scheduled post 📅 #automation",
    schedule_time=int(time.time()) + 86400,
)

Posting Carousels (Multiple Images)

You can also create carousel posts with multiple images. The process is similar but requires creating individual media containers for each image first, then combining them:

def create_carousel(image_urls: list, caption: str):
    children_ids = []

    # Create a container for each image
    for url in image_urls:
        resp = requests.post(
            f"{BASE_URL}/{IG_USER_ID}/media",
            data={
                "image_url": url,
                "is_carousel_item": "true",
                "access_token": ACCESS_TOKEN,
            },
        )
        resp.raise_for_status()
        children_ids.append(resp.json()["id"])

    # Create the carousel container
    resp = requests.post(
        f"{BASE_URL}/{IG_USER_ID}/media",
        data={
            "media_type": "CAROUSEL",
            "caption": caption,
            "children": ",".join(children_ids),
            "access_token": ACCESS_TOKEN,
        },
    )
    resp.raise_for_status()
    creation_id = resp.json()["id"]

    # Publish
    publish_resp = requests.post(
        f"{BASE_URL}/{IG_USER_ID}/media_publish",
        data={
            "creation_id": creation_id,
            "access_token": ACCESS_TOKEN,
        },
    )
    publish_resp.raise_for_status()
    return publish_resp.json()["id"]

Important Limitations

Keep these limits in mind when working with the Instagram Graph API:

  • Rate Limits: You can publish up to 25 posts per 24 hours per Instagram account
  • Image Requirements: Images must be publicly accessible via URL, JPEG format is recommended, minimum 320px, maximum 1440px width
  • Caption Length: Maximum 2,200 characters
  • Hashtags: Maximum 30 hashtags per post
  • Scheduling Window: Between 10 minutes and 75 days in the future
  • No Stories/Reels: The Content Publishing API currently only supports feed posts and carousels (Reels support is in beta)

Error Handling Best Practices

The API can return various errors. Here's how to handle them gracefully:

def safe_publish(image_url: str, caption: str):
    try:
        resp = requests.post(
            f"{BASE_URL}/{IG_USER_ID}/media",
            data={
                "image_url": image_url,
                "caption": caption,
                "access_token": ACCESS_TOKEN,
            },
        )

        if resp.status_code == 400:
            error = resp.json().get("error", {})
            code = error.get("code")
            if code == 9:
                print("Rate limit reached. Try again later.")
            elif code == 36003:
                print("Image URL not accessible. Check the URL.")
            else:
                print(f"API error: {error.get('message')}")
            return None

        resp.raise_for_status()
        return resp.json()["id"]

    except requests.exceptions.RequestException as e:
        print(f"Request failed: {e}")
        return None

Conclusion

The Instagram Graph API opens up powerful automation possibilities. Whether you're building a social media management tool, automating content distribution, or scheduling posts for optimal engagement times — the API gives you full programmatic control over your Instagram presence.

Combined with a CI/CD pipeline or a simple cron job, you can build a fully automated posting workflow that saves you time and ensures consistency.

If you want to dive deeper into working with REST APIs in general, check out this article:

Understanding and using REST APIs

Artikel teilen:Share article: