instagram

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
Call the Instagram Graph API (
graph.facebook.com
) with
curl + jq
. The connector injects
$INSTAGRAM_ACCESS_TOKEN
(a token with
instagram_content_publish
+
pages_read_engagement
; a Facebook Page token or an Instagram-Login user token) and optionally
$INSTAGRAM_IG_USER_ID
. Never echo them.
Instagram publishes only images / videos / reels to a professional (Business or Creator) account linked to a Facebook Page. There are no text-only posts.
使用
curl + jq
调用Instagram Graph API
graph.facebook.com
)。连接器会注入
$INSTAGRAM_ACCESS_TOKEN
(带有
instagram_content_publish
+
pages_read_engagement
权限的令牌;可以是Facebook Page令牌或Instagram登录用户令牌),以及可选的
$INSTAGRAM_IG_USER_ID
。切勿回显这些令牌。
Instagram仅支持向关联Facebook主页的专业(商业或创作者)账号发布图片/视频/Reels内容,不支持纯文字帖子。

Resolve the Instagram account id

获取Instagram账号ID

If
$INSTAGRAM_IG_USER_ID
is set, use it. Otherwise derive it from the token — try the Page-token path first (
/me
is the Page), then fall back to the user-token path (
/me/accounts
→ linked Page → IG account), so either token type the connector accepts resolves cleanly:
bash
if [ -n "$INSTAGRAM_IG_USER_ID" ]; then
  IGID="$INSTAGRAM_IG_USER_ID"
else
  # Page access token: /me IS the Page, read its linked IG account directly
  IGID=$(curl -sS "https://graph.facebook.com/v21.0/me?fields=instagram_business_account&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r '.instagram_business_account.id // empty')
  if [ -z "$IGID" ]; then
    # User access token: list the managed Page, then its linked IG account
    PAGE=$(curl -sS "https://graph.facebook.com/v21.0/me/accounts?access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r '.data[0].id // empty')
    IGID=$(curl -sS "https://graph.facebook.com/v21.0/$PAGE?fields=instagram_business_account&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r '.instagram_business_account.id // empty')
  fi
fi
echo "ig_user_id=$IGID"
Errors are JSON with
error.message
/
error.code
— show them verbatim.
401
/
OAuthException
→ token expired or missing scope; a null
IGID
→ the token isn't linked to a professional IG account / Page (see Gotchas). Reconnect if needed.
如果已设置
$INSTAGRAM_IG_USER_ID
,直接使用该值。否则从令牌中推导——优先尝试Page令牌路径(
/me
代表Page),再回退到用户令牌路径(
/me/accounts
→ 关联的Page → IG账号),确保连接器接受的任意令牌类型都能顺利解析:
bash
if [ -n "$INSTAGRAM_IG_USER_ID" ]; then
  IGID="$INSTAGRAM_IG_USER_ID"
else
  # Page访问令牌:/me 即为Page,直接读取其关联的IG账号
  IGID=$(curl -sS "https://graph.facebook.com/v21.0/me?fields=instagram_business_account&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r '.instagram_business_account.id // empty')
  if [ -z "$IGID" ]; then
    # 用户访问令牌:列出管理的Page,再读取其关联的IG账号
    PAGE=$(curl -sS "https://graph.facebook.com/v21.0/me/accounts?access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r '.data[0].id // empty')
    IGID=$(curl -sS "https://graph.facebook.com/v21.0/$PAGE?fields=instagram_business_account&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r '.instagram_business_account.id // empty')
  fi
fi
echo "ig_user_id=$IGID"
错误信息为包含
error.message
/
error.code
的JSON——直接原样展示。
401
/
OAuthException
表示令牌过期或缺少权限;
IGID
为空表示令牌未关联专业IG账号/Page(参见注意事项)。必要时重新连接。

Publish a single image (two-step: create container → publish)

发布单张图片(两步流程:创建容器→发布)

Confirm the caption + image with the user first. The
image_url
must be a public JPEG URL (Instagram server-side cURLs it):
bash
CID=$(curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media" \
  -d "image_url=https://cdn.acedata.cloud/xxxx.jpg" \
  --data-urlencode "caption=One endpoint → posters, cards, mockups. #AI #API" \
  -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .id)
echo "container=$CID"

curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media_publish" \
  -d "creation_id=$CID" -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq .
请先与用户确认文案和图片。
image_url
必须是公开JPEG链接(Instagram服务器会通过cURL获取):
bash
CID=$(curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media" \
  -d "image_url=https://cdn.acedata.cloud/xxxx.jpg" \
  --data-urlencode "caption=One endpoint → posters, cards, mockups. #AI #API" \
  -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .id)
echo "container=$CID"

curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media_publish" \
  -d "creation_id=$CID" -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq .

→ {"id":"<IG_MEDIA_ID>"}

→ {"id":"<IG_MEDIA_ID>"}


Get the permalink to hand back to the user:

```bash
curl -sS "https://graph.facebook.com/v21.0/<IG_MEDIA_ID>?fields=permalink&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .permalink

获取永久链接返回给用户:

```bash
curl -sS "https://graph.facebook.com/v21.0/<IG_MEDIA_ID>?fields=permalink&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .permalink

Reels / video

Reels/视频

Create with
media_type=REELS
+ a public
video_url
, then poll the container status until FINISHED before publishing (video processing takes time):
bash
CID=$(curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media" \
  -d "media_type=REELS" -d "video_url=https://cdn.acedata.cloud/xxxx.mp4" \
  --data-urlencode "caption=..." -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .id)
创建时需指定
media_type=REELS
+ 公开
video_url
,然后轮询容器状态直到显示FINISHED再发布(视频处理需要时间):
bash
CID=$(curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media" \
  -d "media_type=REELS" -d "video_url=https://cdn.acedata.cloud/xxxx.mp4" \
  --data-urlencode "caption=..." -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .id)

poll until the video finishes processing (up to ~5 min) BEFORE publishing —

在发布前轮询直到视频处理完成(最多约5分钟)——发布状态为IN_PROGRESS的容器会被拒绝:

publishing an IN_PROGRESS container is rejected:

for i in $(seq 1 60); do ST=$(curl -sS "https://graph.facebook.com/v21.0/$CID?fields=status_code&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .status_code) echo "status=$ST"; [ "$ST" = "FINISHED" ] && break [ "$ST" = "ERROR" ] || [ "$ST" = "EXPIRED" ] && { echo "container failed: $ST"; break; } sleep 5 done
curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media_publish"
-d "creation_id=$CID" -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq .
undefined
for i in $(seq 1 60); do ST=$(curl -sS "https://graph.facebook.com/v21.0/$CID?fields=status_code&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .status_code) echo "status=$ST"; [ "$ST" = "FINISHED" ] && break [ "$ST" = "ERROR" ] || [ "$ST" = "EXPIRED" ] && { echo "container failed: $ST"; break; } sleep 5 done
curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media_publish"
-d "creation_id=$CID" -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq .
undefined

Carousel (2–10 items)

轮播内容(2-10个项目)

Create each child with
is_carousel_item=true
, then a
media_type=CAROUSEL
container with
children=<ID1>,<ID2>,...
+
caption
, then publish the carousel id.
创建每个子内容时设置
is_carousel_item=true
,然后创建
media_type=CAROUSEL
容器,指定
children=<ID1>,<ID2>,...
+ 文案,最后发布轮播容器ID。

Gotchas

注意事项

  • No text-only posts — Instagram requires an image or video. Use a public JPEG for images (PNG/other formats are rejected; extended JPEG like MPO/JPS too).
  • Professional account required — a Business/Creator IG account linked to a Facebook Page. If
    instagram_business_account
    is null, the account isn't a professional account or isn't linked; the user must fix that in IG / Page settings.
  • Media must be a public URL on a server Instagram can reach; local files won't work. Host on cdn.acedata.cloud first.
  • Rate limit: 100 API-published posts per 24h (a carousel counts as 1). Check via
    GET /$IGID/content_publishing_limit
    .
  • Page Publishing Authorization (PPA): some Pages must complete PPA before API publishing works — surface the API error verbatim if it mentions PPA.
  • API version: keep the
    vXX.0
    path current if you hit a version/deprecation error.
  • 不支持纯文字帖子——Instagram要求必须包含图片或视频。图片需使用公开JPEG格式(PNG或其他格式会被拒绝;MPO/JPS等扩展JPEG格式也不行)。
  • 需要专业账号——必须是关联Facebook主页的商业/创作者IG账号。如果
    instagram_business_account
    为空,说明账号不是专业账号或未关联主页;用户需要在IG/Page设置中解决该问题。
  • 媒体必须是公开链接——必须是Instagram服务器可访问的链接;本地文件无法使用。请先上传到cdn.acedata.cloud。
  • 速率限制:每24小时最多通过API发布100条帖子(轮播内容算1条)。可通过
    GET /$IGID/content_publishing_limit
    查看限制。
  • Page发布授权(PPA):部分Page必须完成PPA才能使用API发布——如果API错误信息提到PPA,直接原样展示。
  • API版本:如果遇到版本/弃用错误,请保持
    vXX.0
    路径为最新版本。

Record the output

记录输出

After you successfully publish and obtain the live permalink, call the built-in
publish_artifact
tool ONCE so the user can track it in My Outputs:
publish_artifact(kind="image", channel="instagram", title="<title>", url="<the REAL permalink>", status="delivered")
Use the real returned URL — never fabricate one. Call it once per published item, only after delivery is confirmed; skip it (or use
status="failed"
) if publishing failed. See
_shared/artifacts.md
.
成功发布并获取永久链接后,调用内置的
publish_artifact
工具一次,以便用户在我的输出中查看:
publish_artifact(kind="image", channel="instagram", title="<title>", url="<the REAL permalink>", status="delivered")
请使用实际返回的链接——切勿伪造。每个发布的内容仅调用一次,且仅在确认发布成功后调用;如果发布失败,请跳过(或使用
status="failed"
)。详见
_shared/artifacts.md