🔮 Bold Little Oracle ▸ docs/instagram-api-setup.md
updated 2026-04-04

Instagram Content Publishing API Setup

Guide for publishing to @boldlittleoracle via the Meta Graph API.

Last updated: April 2026


Background: What Changed


The Two Authentication Paths

Path B: Instagram Login (Business Login for Instagram)

We should use Path A (Facebook Login) because we already have the Facebook Page connected to the Instagram account, and we get permanent page tokens.


Our Setup

Resource Value
Meta App Bold Little Oracle
Facebook Page Bold Little Oracle
Facebook Page ID 1022988797569167
Instagram Account @boldlittleoracle
Instagram Account Type Professional (Business or Creator)
IG User ID (get this in Step 4 below)

Step-by-Step: Get a Publishing Access Token

Step 1: Ensure App Configuration

  1. Go to developers.facebook.com and open the Bold Little Oracle app
  2. In the App Dashboard, confirm Facebook Login for Business is added as a product (if not, click “Set up” on it)
  3. Under App Settings > Basic, note your App ID and App Secret (you will need these for token exchange)

Step 2: Open Graph API Explorer (Correct Settings)

  1. Go to developers.facebook.com/tools/explorer/
  2. IMPORTANT: Set the domain dropdown to graph.facebook.com (NOT graph.instagram.com). The graph.instagram.com domain is for the Instagram Login path and will not show Facebook Page permissions.
  3. Select Bold Little Oracle from the “Meta App” dropdown

Step 3: Add Permissions and Generate Token

  1. In the “Permissions” section, click “Add a Permission” and add ALL of these:

Required for publishing: - instagram_basic - instagram_content_publish - pages_show_list - pages_read_engagement

Where to find them: The pages_* permissions are under “Events Groups Pages” category. The instagram_* permissions are under “Other” or you can type them directly.

  1. Under “User or Page”, select “Get User Access Token”
  2. Click “Generate Access Token”
  3. A popup will appear. Walk through it: - Select your business (if prompted) - Select the Bold Little Oracle Facebook Page - Select the @boldlittleoracle Instagram account - Click through all the blue authorization buttons
  4. The Access Token field now contains a short-lived User access token (~1 hour)

Step 4: Get Your Instagram User ID (IG User ID)

With the token from Step 3, run this query in the Graph API Explorer (or curl):

GET /1022988797569167?fields=instagram_business_account

Or via curl:

curl -s "https://graph.facebook.com/v25.0/1022988797569167?fields=instagram_business_account&access_token=YOUR_TOKEN"

Response:

{
  "instagram_business_account": {
    "id": "17841400XXXXXXXXX"   // <-- This is your IG User ID
  },
  "id": "1022988797569167"
}

Save that instagram_business_account.id value. This is the {ig-user-id} used in all publishing API calls.

Step 5: Exchange for Long-Lived User Token (60 days)

curl -s "https://graph.facebook.com/v25.0/oauth/access_token?\
grant_type=fb_exchange_token&\
client_id=YOUR_APP_ID&\
client_secret=YOUR_APP_SECRET&\
fb_exchange_token=YOUR_SHORT_LIVED_TOKEN"

Response:

{
  "access_token": "EAAG...",
  "token_type": "bearer",
  "expires_in": 5184000
}

This long-lived user token is valid for 60 days.

Step 6: Get Permanent Page Access Token

Exchange the long-lived user token for a permanent page token (never expires):

curl -s "https://graph.facebook.com/v25.0/me/accounts?access_token=YOUR_LONG_LIVED_USER_TOKEN"

Response:

{
  "data": [
    {
      "access_token": "EAAG...",   // <-- PERMANENT page token
      "category": "...",
      "name": "Bold Little Oracle",
      "id": "1022988797569167",
      "tasks": ["ANALYZE", "ADVERTISE", "MODERATE", "CREATE_CONTENT", "MANAGE"]
    }
  ]
}

The access_token in this response is a permanent Page access token. It does not expire unless you change your password, revoke permissions, or delete the app.

Step 7: Verify the Token

Paste the permanent page token into the Access Token Debugger to confirm: - Type: Page - Expires: Never - Scopes include: instagram_basic, instagram_content_publish


Publishing Content

Publish a Single Image

Step 1: Create a media container

curl -X POST "https://graph.facebook.com/v25.0/{ig-user-id}/media" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_PAGE_TOKEN" \
  -d '{
    "image_url": "https://example.com/photo.jpg",
    "caption": "Your caption here #hashtag"
  }'

Response: {"id": "CONTAINER_ID"}

Step 2: Check container status (optional but recommended)

curl "https://graph.facebook.com/v25.0/CONTAINER_ID?fields=status_code&access_token=YOUR_PAGE_TOKEN"

Wait for status_code = FINISHED. Poll once per minute, max 5 minutes.

Step 3: Publish the container

curl -X POST "https://graph.facebook.com/v25.0/{ig-user-id}/media_publish" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_PAGE_TOKEN" \
  -d '{
    "creation_id": "CONTAINER_ID"
  }'

Response: {"id": "PUBLISHED_MEDIA_ID"}

Publish a Reel (Video)

# Step 1: Create container
curl -X POST "https://graph.facebook.com/v25.0/{ig-user-id}/media" \
  -H "Authorization: Bearer YOUR_PAGE_TOKEN" \
  -d '{
    "media_type": "REELS",
    "video_url": "https://example.com/video.mp4",
    "caption": "Reel caption"
  }'

# Step 2: Wait for FINISHED status (videos take longer)
# Step 3: Publish (same as above)
# Step 1: Create individual item containers (no caption here)
curl -X POST "https://graph.facebook.com/v25.0/{ig-user-id}/media" \
  -d '{"image_url": "https://example.com/1.jpg", "is_carousel_item": true}' \
  -H "Authorization: Bearer YOUR_PAGE_TOKEN"
# Repeat for each item (max 10), collect container IDs

# Step 2: Create carousel container
curl -X POST "https://graph.facebook.com/v25.0/{ig-user-id}/media" \
  -H "Authorization: Bearer YOUR_PAGE_TOKEN" \
  -d '{
    "media_type": "CAROUSEL",
    "caption": "Carousel caption",
    "children": "ID_1,ID_2,ID_3"
  }'

# Step 3: Publish the carousel container

Publish a Story

curl -X POST "https://graph.facebook.com/v25.0/{ig-user-id}/media" \
  -H "Authorization: Bearer YOUR_PAGE_TOKEN" \
  -d '{
    "media_type": "STORIES",
    "image_url": "https://example.com/story.jpg"
  }'
# Then publish with media_publish as usual

Limits and Restrictions


App Review / Advanced Access

For development and testing (yourself only), Standard Access is sufficient – you can publish to your own account without app review.

If you later want other users to authorize the app: - You will need to submit for App Review to get Advanced Access on instagram_content_publish - Page Publishing Authorization (PPA) may be required for some Pages. If your Page requires PPA, you must complete it before publishing will work.


Token Lifecycle Summary

Token Type How to Get Expiration Refreshable
Short-lived User Graph API Explorer “Generate Access Token” ~1 hour No, re-login required
Long-lived User Exchange short-lived via /oauth/access_token 60 days Yes, after 24h
Page Access Token GET /me/accounts with long-lived user token Never N/A

For automation, use the permanent Page Access Token. Store it securely (environment variable, secrets manager). It will work indefinitely unless you revoke it.


Quick Reference

# Store these values
IG_USER_ID="17841400XXXXXXXXX"       # From Step 4
PAGE_TOKEN="EAAG..."                  # From Step 6

# Publish an image (two API calls)
CONTAINER=$(curl -s -X POST "https://graph.facebook.com/v25.0/$IG_USER_ID/media" \
  -H "Authorization: Bearer $PAGE_TOKEN" \
  -d "image_url=https://example.com/photo.jpg" \
  -d "caption=Hello world" | jq -r '.id')

curl -X POST "https://graph.facebook.com/v25.0/$IG_USER_ID/media_publish" \
  -H "Authorization: Bearer $PAGE_TOKEN" \
  -d "creation_id=$CONTAINER"

FAQ

Q: Do I need graph.instagram.com or graph.facebook.com? A: Use graph.facebook.com. The graph.instagram.com domain is for the Instagram Login path (Path B). Since we use Facebook Login (Path A) with a Page token, all calls go to graph.facebook.com.

Q: What about the “Generate Instagram Access Token” button in Graph API Explorer? A: That button uses the Instagram Login flow (Path B) and generates an Instagram User token for graph.instagram.com. For content publishing with permanent tokens, ignore that button. Instead, switch to graph.facebook.com, add permissions manually, and use “Get User Access Token” / “Generate Access Token”.

Q: Can I publish with just an Instagram token? A: Yes, but Instagram User tokens (Path B) expire after 60 days and must be refreshed. Page tokens (Path A) never expire, making them better for automation.

Q: Why can’t I see Instagram permissions in the dropdown? A: You are likely on the graph.instagram.com domain in Graph API Explorer. Switch to graph.facebook.com. The Instagram permissions (instagram_basic, instagram_content_publish) appear in the permission list when using the Facebook Login flow on graph.facebook.com.

Q: Do I need App Review to post to my own account? A: No. With Standard Access, app admins/developers/testers can use the API on their own accounts. App Review is only needed to let other users authorize your app.


Sources