Instagram Graph API integration via curl. Use this skill to fetch and publish Instagram media.
/plugin marketplace add vm0-ai/api0/plugin install api0@api0This skill inherits all available tools. When active, it can use any tool Claude has access to.
Use the Instagram Graph API by directly executing curl commands to read and publish Instagram content.
Official docs:
https://developers.facebook.com/docs/instagram-api
Use this skill when you need to:
INSTAGRAM_ACCESS_TOKEN: a long-lived user access tokenINSTAGRAM_BUSINESS_ACCOUNT_ID: your Instagram Business account IDSet the environment variables, for example:
export INSTAGRAM_ACCESS_TOKEN="EAAG..."
export INSTAGRAM_BUSINESS_ACCOUNT_ID="1784140xxxxxxx"
These examples use Graph API version v21.0. You can replace this with the latest version if needed.
Depending on which endpoints you use, make sure your app has requested and been approved for (at least):
instagram_basicpages_show_listinstagram_content_publish (for publishing media)instagram_manage_insights and related permissions (for insights / some hashtag use cases)Important: When using
$VARin a command that pipes to another command, wrap the command containing$VARinbash -c '...'. Due to a Claude Code bug, environment variables are silently cleared when pipes are used directly.bash -c 'curl -s "https://api.example.com" -H "Authorization: Bearer $API_KEY"' | jq .
All examples below assume you have already set:
INSTAGRAM_ACCESS_TOKEN
INSTAGRAM_BUSINESS_ACCOUNT_ID
Fetch the most recent media (photos / videos / Reels) for the account:
bash -c 'curl -s -X GET "https://graph.facebook.com/v21.0/${INSTAGRAM_BUSINESS_ACCOUNT_ID}/media?fields=id,caption,media_type,media_url,permalink,timestamp" --header "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}"' | jq .
Notes:
id: media ID (used for details / insights later)caption: caption textmedia_type: IMAGE / VIDEO / CAROUSEL_ALBUMmedia_url: direct URL to the mediapermalink: Instagram permalinktimestamp: creation timeIf you already have a media id, you can fetch more complete information:
Where to get
{MEDIA_ID}: Use theidfield from the "Get User Media" response (section 1 above)
MEDIA_ID="1789xxxxxxxxxxxx"
bash -c 'curl -s -X GET "https://graph.facebook.com/v21.0/${MEDIA_ID}?fields=id,caption,media_type,media_url,permalink,thumbnail_url,timestamp,username" --header "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}"' | jq .
Note: hashtag search requires proper business use cases and permissions as defined by Facebook/Instagram. Refer to the official docs.
This usually involves two steps:
Where to get
{HASHTAG_NAME}: Use any hashtag name you want to search for (without the # symbol), e.g., "travel", "food", "photography"
HASHTAG_NAME="travel"
bash -c 'curl -s -X GET "https://graph.facebook.com/v21.0/ig_hashtag_search?user_id=${INSTAGRAM_BUSINESS_ACCOUNT_ID}&q=${HASHTAG_NAME}" --header "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}"' | jq .
Take the returned id (we call it HASHTAG_ID).
Where to get
{HASHTAG_ID}: Use theidfield from the "Search Hashtag" response (section 3.1 above)
HASHTAG_ID="178434113xxxxxxxx"
bash -c 'curl -s -X GET "https://graph.facebook.com/v21.0/${HASHTAG_ID}/recent_media?user_id=${INSTAGRAM_BUSINESS_ACCOUNT_ID}&fields=id,caption,media_type,media_url,permalink,timestamp" --header "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}"' | jq .
Publishing an image post via the Graph API usually requires two steps:
Where to get
{IMAGE_URL}: Use any publicly accessible image URL (e.g., from your CDN, S3, or public hosting)Where to get
{CAPTION}: This is the text caption for your post (what you want to say in the post)
IMAGE_URL="https://example.com/image.jpg"
CAPTION="Hello from Instagram API 👋"
bash -c 'curl -s -X POST "https://graph.facebook.com/v21.0/${INSTAGRAM_BUSINESS_ACCOUNT_ID}/media" -F "image_url=${IMAGE_URL}" -F "caption=${CAPTION}" --header "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}"' | jq .
The response will contain an id (media container ID), for example:
{
"id": "1790xxxxxxxxxxxx"
}
Store this ID (for example as CREATION_ID).
Where to get
{CREATION_ID}: Use theidfield from the "Create Media Container" response (section 4.1 above)
CREATION_ID="1790xxxxxxxxxxxx"
bash -c 'curl -s -X POST "https://graph.facebook.com/v21.0/${INSTAGRAM_BUSINESS_ACCOUNT_ID}/media_publish" -F "creation_id=${CREATION_ID}" --header "Authorization: Bearer ${INSTAGRAM_ACCESS_TOKEN}"' | jq .
If successful, the response will contain the final media id:
{
"id": "1791yyyyyyyyyyyy"
}
You can then use the "Get details for a single media" command to fetch its permalink.
(#10) Application does not have permission for this actionINSTAGRAM_ACCESS_TOKEN is a valid long-lived tokenjq: all examples use jq to pretty-print JSON, which is helpful for both agents and humansINSTAGRAM_ACCESS_TOKEN is sensitive; avoid printing it in logs or chat transcriptsv21.0 version in URLs to the latest