Plank help · updated 2026-08-24

Posting to Instagram

Connect an Instagram professional account through the official Meta API so your assistant can publish posts, carousels, Reels and Stories — with the traps that make this setup slow called out up front.

Agents: fetch the raw markdown of this page at /en/help/connecting-instagram.md

Posting to Instagram

Your assistant can publish to Instagram for you through Meta's official API — posts, carousels, Reels and Stories — plus read your profile, comments and messages.

You don't wire this up by hand. Ask your assistant in chat ("connect our Instagram account so you can post"), and it builds the posting script and walks you through the parts only you can do. This page is written for both of you: the assistant fetches it at https://plank.md/help/connecting-instagram.md before starting, so the connection goes cleanly instead of down one of the dead ends below.

Set aside 20 minutes and read "Before you start" first. This is the fiddliest connection Plank supports. Not because any single step is hard, but because Meta gives you three similar-looking numbers, two similarly-named APIs, and a failure mode where everything appears to work and nothing happens. All of it is avoidable if you check three things before you begin.

Before you start

Three prerequisites. Confirm all three now — each one, discovered later, sends you back to the beginning.

1. The account must be a Professional account — Business or Creator. A personal account cannot publish through the API at all. Change it in Instagram under Settings → Account type and tools.

2. The account must be connected to a Facebook Page. This is the one that hurts. If the account isn't linked to a Page, Meta's API simply cannot see it — the authorization screens still appear, you still approve everything, and the account is silently absent from the results. There is nothing to diagnose because nothing reports an error.

To connect one:

  • In Instagram: Edit profile → Public business information → Page, then create a Page or pick an existing one.
  • Or in Meta Business Suite: Settings → Accounts → Instagram accounts → Add → Connect assets.

3. Know how you log in to Instagram. Answer this before anything else, because it picks your entire path:

How you sign inWhich API you need
Through Facebook (you may not even have an Instagram password)Instagram API with Facebook Login — the common case, and what the rest of this page describes
Directly with an Instagram username and passwordInstagram API with Instagram Login — a different flow with different permission names

Tell your assistant which one applies. Picking the wrong one costs you the whole setup twice.

The three app IDs — read this before copying any number

A single Meta app shows you three different numeric IDs, in three different places, and they are not interchangeable. This is the single most common way this setup fails.

IDWhere you find itWhat it's forWhat happens if you use it wrongly
Meta App IDApp settings → BasicFacebook Login, Graph API Explorer
Instagram App IDInstagram product pageThe Instagram Login flow onlyInvalid App ID, or a login that completes and asks you nothing
Threads App IDThreads product pageThreads only — see Posting to ThreadsSame as above

When you're asked for "the app ID", it's the Meta App ID from App settings → Basic. If your assistant hands you an authorization link and the page just logs you in and stops — no permission prompt, no redirect — it almost certainly has the wrong one of these three.

Step 1 — Create the Meta app

  1. Go to developers.facebook.com/apps and click Create App.
  2. Choose the Business app type.
  3. Name it something you'll recognise later, e.g. "Acme Instagram".
  4. Add the Instagram product, and choose API setup with Facebook login.

That's all you need. You do not have to add the Facebook Login for Business product or fill in App Domains — those belong to the redirect flow, which the next step deliberately avoids.

Step 2 — Generate an access token

This is the step that actually works, and it's simpler than it looks. You will not use a redirect/callback flow (see "Why not the sign-in link" below).

  1. Open the Graph API Explorer.
  2. In Meta App, select the app you just made — by its Meta App ID.
  3. Set the API version to v26.0.
  4. For token type, choose User Access Token.
  5. Add these permissions:
    • pages_show_list
    • pages_read_engagement
    • instagram_basic
    • instagram_content_publish
    • instagram_manage_comments
    • instagram_manage_insights
    • instagram_manage_contents — only needed if you want the assistant to be able to delete posts
  6. Click Generate Access Token and approve in the Facebook window that opens. Choose the Page connected to your Instagram account.
  7. Copy the token and paste it to your assistant.

Your assistant then looks up which Page is linked to your Instagram account, saves that Page's token, and reads your profile back to confirm — without publishing anything.

The token is a live credential. Anyone who has it can post as you until it expires (about 60 days). It gets saved inside your workspace, so everyone with access to that workspace can use it. If a token ends up somewhere you'd rather it hadn't, generating a new one in the Explorer retires the old one.

If instagram_manage_contents isn't offered

It's a newer permission and may need to be requested: App Review → Permissions and Features, find it, and click Request advanced access. Note the spelling — it is instagram_manage_contents, plural. There is no instagram_manage_content, and searching for the singular turns up nothing.

Before you spend time on App Review for it, read "Deleting posts is unreliable right now" below — the permission grants cleanly, but Meta's delete endpoint was failing regardless when this was last tested.

Why not the sign-in link?

You'd expect a "sign in with Facebook" link to be the clean way to do this. It isn't, and it fails in a way that wastes a lot of time:

  • Facebook Login for Business returns the token in the URL fragment — the part after #. A callback page can't read that, so after you pick your account the flow just… stops. No error, no completed connection, nothing to report.
  • It needs the extra Facebook Login for Business product, plus App Domains (App settings → Basic) and Valid OAuth Redirect URIs lined up exactly. A mismatch surfaces as an unrelated-sounding "Can't load URL: the domain of this URL isn't included in the app's domains", at the point where you'd least expect a settings problem.

The Graph API Explorer path avoids all of it. If your assistant offers you an authorization link, it's fine to say "let's use the Graph API Explorer instead".

Step 3 — Publishing

Ask in plain language — "post this image to Instagram with this caption", "put these five screens up as Stories". Your assistant always does a dry run first, showing exactly what would be published before anything goes out.

One thing to know: Instagram doesn't accept file uploads through the API. Meta downloads your media from a public link, so every image or video needs a public URL first. Your assistant handles this by sharing the file from your workspace and giving Meta the direct link — the media stays in Plank rather than going through a third-party host.

Limits worth knowing

Publishes per 24 hours100
Items in a carousel10 maximum
Story image size1080 × 1920
Token life~60 days

Stories behave differently

  • Stories take no caption — text has to be part of the image.
  • They publish one at a time, in order. Your assistant waits for each to finish before sending the next, so a numbered sequence stays in sequence.
  • A published Story can't be edited. Fixing one means deleting it and posting a replacement, so it's worth reviewing the images before they go up.
  • Keep meaningful content away from the edges — Instagram's own interface covers the top and bottom of the screen.

Deleting posts is unreliable right now

As of 2026-08-07, Meta's delete endpoint returns internal error 2207085 even with instagram_manage_contents granted, on both user and Page tokens. This is on Meta's side, not something your setup can fix. Delete in the Instagram app instead. It may well have been fixed since — worth one retry before falling back.

When it stops working

Tokens last about 60 days, and an expired one is the usual cause of posting suddenly failing. Ask your assistant to refresh it, or generate a new one in the Graph API Explorer exactly as in Step 2.

Not every failure means reconnecting, though — and reconnecting when that isn't the problem just costs you the setup again:

What you seeWhat it usually means
invalid_grant, revoked access, or a 401 that survives a refreshThe credential is genuinely dead — reconnect
A 403, a quota message, or a missing permissionThe connection is fine; a permission or limit is the problem
The account isn't foundThe Facebook Page link came undone — check prerequisite 2

For your assistant: implementation notes

Choosing the flow. Ask how the user signs in to Instagram before proposing anything. Facebook sign-in ⇒ Instagram API with Facebook Login (instagram_* scopes, tokens from graph.facebook.com/v26.0). Direct Instagram credentials ⇒ Instagram Login (instagram_business_* scopes, graph.instagram.com). The two scope vocabularies are not interchangeable.

Verify the Page link before touching OAuth. Call /me/accounts with fields=id,name,access_token,instagram_business_account{id,username} and confirm the target username actually appears. If it doesn't, stop and have the user connect the Page — no authorization flow can work around it, and continuing produces a confusing series of successful-looking steps.

Graph API v26 field removals. account_type can no longer be requested inside a nested instagram_business_account selection, nor read directly off the object. Requesting it fails the whole query. You don't need it: the presence of instagram_business_account already proves the account is Professional.

Use the Page access token for publishing and deletion, not the user token — it's the one tied to the Instagram business account.

Publishing is two steps: create a media container (POST /<ig-user-id>/media), poll it until status_code is FINISHED, then publish (POST /<ig-user-id>/media_publish with creation_id). Reels take the longest; allow roughly a minute before treating a container as stuck. Carousels create and finish each child container first, then a parent with media_type=CAROUSEL.

Line breaks in a caption are real newlines, never a literal \n. Instagram shows the characters you send, and a caption assembled as a double-quoted shell string turns \n into a visible backslash-plus-n in the middle of the post. Write the caption to a file and let the tool read it verbatim (jq --rawfile caption /tmp/ig-caption.txt, or --data-urlencode "caption@/tmp/ig-caption.txt"); for a one-liner, CAPTION=$'Line one.\n\nLine two.' — inside $'…', and only there, \n is a newline. In Python a "\n" in a string is already a real newline; the trap is the shell's.

Stories: pass media_type: STORIES and send no caption — a caption in a Story container is rejected. Honour an explicit mediaType rather than defaulting images to IMAGE.

Public media URLs. Meta fetches the file itself, so it needs a URL that returns raw bytes with an image or video content type. Share the workspace file, then use the /download endpoint:

https://api.plank.md/public/w/<workspace-slug>/s/<share-token>/download

Verified to return content-type: image/png with the correct byte length. Do not use /content — it returns JSON with the file as a UTF-8 string, which Meta cannot read. Check each URL returns 200 and an image content type before creating any container.

Credentials live at scripts/instagram/token.json inside the workspace, alongside a @plank-integration header on the posting script so it appears in the Integrations sidebar. See Workspace scripts & the sidebar, and Connecting your tools for how connections work generally.

Always --dry-run first, and never publish without the user confirming the exact copy and media.