How to Schedule Instagram Posts via API

8 min read Developers and growth teams who want to automate Instagram publishing without browser automation or scraping.Updated 2026-05-06

Instagram doesn't expose a direct schedule endpoint, so most automation tools either screen-scrape (which violates Meta's TOS) or require a full Meta app review that takes weeks. CodivUpload solves this with a managed Instagram Graph API integration: you connect your Instagram Business or Creator account once inside a CodivUpload profile, then schedule posts by referencing that profile by name and listing instagram in the platforms array. The CodivUpload backend handles container creation, media upload, and the publish call to Meta's Graph API. This guide walks through the API contract, the platform overrides Instagram supports, and the exact JSON shapes that work for Reels, carousels, and feed posts. Every code sample is copy-pasteable against the production API at api.codivupload.com.

Prerequisites

  • An Instagram Business or Creator account — Personal accounts are not allowed by Meta's API
  • An active Facebook Page linked to the Instagram account (Meta requires this link)
  • A CodivUpload profile with the Instagram account connected — free plan covers up to 30 posts/month
  • An API key generated from Dashboard → API Keys
  • Public HTTPS URLs for your media (R2, S3, GCS, or any CDN that serves over TLS)

Step-by-step

  1. 1

    Connect Instagram inside a CodivUpload profile

    Profiles in CodivUpload group all the social accounts that belong to a single brand or client. In Dashboard → Profiles, create a profile named for your brand (e.g. my_brand). Click Connect → Instagram and approve the OAuth flow. Meta redirects back with permission to read and publish on the linked Business account. The profile_name string you choose here is what every API request will reference — it's the only identifier you need; you do not pass IDs or social_account_id values.

  2. 2

    Generate an API key

    Go to Dashboard → API Keys → Create Key. Copy the key value the moment it's shown — CodivUpload stores only the SHA-256 hash and you cannot retrieve the plaintext later. Treat it like a password: store it in your secret manager, your platform's env vars (Vercel, Render, Fly), or a vault like 1Password Secrets Automation.

  3. 3

    Schedule a Reel via POST /v1/posts

    Send a POST with post_type=video, profile_name pointing at your profile, platforms=["instagram"], a single video URL inside media_urls, and scheduled_date in ISO 8601 UTC. CodivUpload validates the request, queues it inside pgmq, and the worker picks it up at the scheduled timestamp. Use Instagram-specific overrides like instagram_share_to_feed (Reels also appear on the main feed) and instagram_cover_url (custom cover frame) namespaced with instagram_.

    curl -X POST https://api.codivupload.com/v1/posts \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "post_type": "video",
        "profile_name": "my_brand",
        "platforms": ["instagram"],
        "media_urls": ["https://your-cdn.example.com/reel.mp4"],
        "description": "New product drop — link in bio.",
        "scheduled_date": "2026-05-10T14:00:00Z",
        "instagram_share_to_feed": true,
        "instagram_cover_url": "https://your-cdn.example.com/cover.jpg",
        "instagram_alt_text": "Hands holding the new product against a beige backdrop"
      }'
  4. 4

    Schedule a carousel (multi-image post)

    Carousels accept up to 10 images on Instagram. Set post_type=image and pass each image URL inside media_urls in the order you want them displayed. CodivUpload uploads each child container to Instagram's Graph API, then creates the carousel parent and stores the published media id back in the destination row. You can override the global description specifically for Instagram with the instagram_alt_text field, which Instagram uses for accessibility and image search.

    curl -X POST https://api.codivupload.com/v1/posts \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "post_type": "image",
        "profile_name": "my_brand",
        "platforms": ["instagram"],
        "media_urls": [
          "https://your-cdn.example.com/photo-1.jpg",
          "https://your-cdn.example.com/photo-2.jpg",
          "https://your-cdn.example.com/photo-3.jpg"
        ],
        "description": "Behind the scenes from our latest shoot 📸",
        "instagram_alt_text": "Studio setup with two softboxes and a teleprompter"
      }'
  5. 5

    Apply Instagram-specific overrides

    Every Instagram-only field is namespaced with the instagram_ prefix and is ignored if instagram is not in the platforms array. The most useful ones in production are: instagram_share_to_feed (a Reel also lands on the main feed grid), instagram_cover_url (custom Reel cover image), instagram_alt_text (accessibility text used by screen readers and image search), instagram_collaborators (an array of usernames to invite as collaborators), instagram_location_id (geotag the post to a Meta-known location), and instagram_media_urls (override the global media_urls just for Instagram — useful when you need a vertical version for IG and a square one for X).

  6. 6

    Verify the result with GET /v1/posts/:id

    After scheduling, the response returns post_id and destinations_count. Poll GET /v1/posts/:id (or wire up a webhook subscription via /v1/webhooks) to track status. The lifecycle is scheduled → publishing → completed (or partially_failed / failed if a destination errored). The response includes a destinations array with one row per platform, each containing status, post_url (set after success), and error_message (set after failure).

    curl -H "Authorization: Bearer YOUR_API_KEY" \
      https://api.codivupload.com/v1/posts/POST_ID
    
    # Response:
    # {
    #   "post": {
    #     "id": "...",
    #     "status": "completed",
    #     ...
    #   },
    #   "destinations": [
    #     {
    #       "platform": "instagram",
    #       "status": "success",
    #       "post_url": "https://www.instagram.com/p/ABC123/"
    #     }
    #   ]
    # }

Frequently asked

Can I schedule Instagram Stories via the API?+

Stories are not supported by Meta's Graph API for scheduling. Only Reels, carousels, and feed posts can be scheduled programmatically. Stories must be posted live from the Instagram mobile app — Meta has not opened the Stories endpoint to third-party tools.

Does this work with personal Instagram accounts?+

No. Instagram's Graph API only supports Business and Creator accounts that are linked to a Facebook Page. If your account is Personal, switch it to Business or Creator inside the IG mobile app (Settings → Account → Switch account type) — the conversion is free and reversible.

What's the rate limit?+

Meta's published cap is 200 calls per hour per Page. CodivUpload's scheduler stays well under this — even an enterprise customer publishing every 2 minutes uses ~30 calls/hour. The platform also includes per-account rate-limit handling: if you hit Meta's cap, the worker pauses that destination and resumes after the cooldown without losing the post.

Can I post the same Reel to TikTok and YouTube simultaneously?+

Yes — add tiktok and youtube to the platforms array in the same POST /v1/posts call. Make sure the same profile has TikTok and YouTube accounts connected, then add platform-specific overrides (tiktok_*, youtube_*) for any settings you want to differ. CodivUpload publishes to each platform in parallel and reports per-destination status.

Why do I get a 400 error about invalid platforms?+

The platforms array must use lowercase enum values: x, youtube, instagram, facebook, linkedin, tiktok, threads, pinterest, bluesky, google_business, snapchat. Note google_business uses an underscore. If you pass Instagram (capitalized) or insta or social-business, the request is rejected with a Zod validation error before reaching the worker.

How do I schedule the post for the best engagement time?+

Replace scheduled_date with schedule_best_time: true. CodivUpload analyzes your last 90 days of analytics for the connected Instagram account, finds the optimal hour and day of week, and schedules the post for the next occurrence of that slot. The decision logs to your post's metadata so you can audit it later.

Can I attach a custom cover image to a Reel?+

Yes. Pass instagram_cover_url with a public HTTPS URL pointing at a 1080×1920 portrait image. Meta uses it as the static thumbnail in the grid view. If you don't pass one, Instagram auto-extracts the first frame, which is often visually weak.

What media format is required?+

Images must be JPEG or PNG, max 8 MB, square or portrait aspect ratios (4:5, 1:1, or 1.91:1 for feed; 9:16 for Reels). Videos must be MP4 with H.264 codec, AAC audio, max 100 MB and 60 seconds for Reels. Carousels can mix images but every item must be the same aspect ratio.

Related guides

Ready to automate?

Free plan includes 30 posts/month across 11 platforms. No credit card required.

See pricing