Instagram Content Publishing API Setup
Guide for publishing to @boldlittleoracle via the Meta Graph API.
Last updated: April 2026
Background: What Changed
- Instagram Basic Display API was fully deprecated December 4, 2024. It only supported read-only access to personal accounts. It no longer functions.
- Instagram Graph API is the current standard. It supports Business and Creator accounts and includes content publishing.
- There are now two authentication paths for the Instagram Graph API. Both can publish content. The choice affects which domain, permissions, and token type you use.
The Two Authentication Paths
Path A: Facebook Login for Business (Recommended for us)
- User logs in with Facebook credentials
- API base URL:
graph.facebook.com - Token type: Facebook Page access token
- Requires Instagram Professional account linked to a Facebook Page (we have this)
- Page access tokens derived from long-lived user tokens never expire
- Supports resumable video uploads
Path B: Instagram Login (Business Login for Instagram)
- User logs in with Instagram credentials
- API base URL:
graph.instagram.com - Token type: Instagram User access token
- Long-lived tokens expire after 60 days (refreshable)
- Does not support resumable video uploads
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
- Go to developers.facebook.com and open the Bold Little Oracle app
- In the App Dashboard, confirm Facebook Login for Business is added as a product (if not, click “Set up” on it)
- 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)
- Go to developers.facebook.com/tools/explorer/
- IMPORTANT: Set the domain dropdown to
graph.facebook.com(NOTgraph.instagram.com). Thegraph.instagram.comdomain is for the Instagram Login path and will not show Facebook Page permissions. - Select Bold Little Oracle from the “Meta App” dropdown
Step 3: Add Permissions and Generate Token
- 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.
- Under “User or Page”, select “Get User Access Token”
- Click “Generate Access Token”
- 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
- 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)
Publish a Carousel
# 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
- 50 posts per 24-hour period per Instagram Professional account (carousel = 1 post)
- 200 API calls per hour per app
- Images must be JPEG format (not PNG, MPO, or JPS)
- Media must be hosted on a publicly accessible URL at time of upload
- Resumable upload (local files) is available via
rupload.facebook.comwith Facebook Login path - No support for: shopping tags, branded content tags, Instagram filters via API
alt_textfield available for image posts (added March 2025)
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
- Instagram Platform: Content Publishing – Official Meta docs
- Instagram Platform: Overview – Login methods comparison
- Instagram API with Facebook Login: Get Started – Setup walkthrough
- Media Publish Reference – Endpoint reference
- Permissions Reference – All Meta API permissions
- Graph API Explorer Guide – Explorer tool docs
- Access Token Debugger – Verify and extend tokens