Skip to content

Get Instagram posting credentials

keryx posts Reels through the Instagram API with Instagram Login (graph.instagram.com) — no Facebook Page, and own-account posting runs under Standard Access, so there is no App Review for posting to your own account. This guide gets the two things keryx needs:

  • INSTAGRAM_ACCESS_TOKEN — a long-lived access token (~60 days, refreshable), set in the environment (never committed).
  • platforms.instagram.user_id — your Instagram professional account id.

Meta's developer dashboard changes often, and the path has real snags. The steps below are the validated route (captured working end-to-end on 2026-06-17); the gotchas that cost us time are called out inline.

Prerequisites

  1. An Instagram Professional account (Business or Creator). Convert in the Instagram app: Settings → Account type and tools → Switch to professional account.
  2. A Meta developer account + an app at developers.facebook.com.

1. Add the Instagram use case

Meta's dashboard is use-case-based (there is no "Add product"):

  1. App Dashboard → Add use cases (or Use cases in the left nav).
  2. Add "Manage messaging & content on Instagram" (publishes posts via the Instagram API). A pre-existing Facebook Login for Business use case is unrelated — leave it.
  3. Customize the use case → API setup with Instagram login. This shows the Instagram app ID and Instagram app secret (distinct from the Facebook app id/secret).

2. Publish the app (switch to Live) — the key unlock

In development mode, token generation only works for accounts holding an app role (Instagram Tester). If your Instagram account belongs to the same Meta Business that owns the app (i.e. you're a business admin), you cannot add it as a tester — Meta refuses with "Unable to add a user with a role on the app's owning business" — and Add account then fails with "Insufficient developer role". The way out is to take the app Live:

  1. App settings → Basic → set a Privacy Policy URL (mandatory to publish) and a Category → Save.
  2. Left nav → PublishPublish (Development → Live). Own-account Standard Access needs no App Review.

3. Make your account reachable by the app

If the Instagram account and app share a Meta Business (you're admin) — the common case:

  1. Business Settings → switch to the business that owns the app (check Accounts → Apps for it).
  2. Accounts → Instagram accounts → Add → Connect your Instagram account → log in. This claims it into the business.
  3. With the IG account selected, Assign access → add yourself with full control. (The "0 people assigned" state is what blocks the app — you must be assigned.)

If it's a standalone account (no business): instead use App roles → Roles → Instagram testers → invite your username → accept in Instagram (Settings → Apps and websites → Tester invites).

4. Generate the token

Back on API setup with Instagram login → "Generate access tokens":

  1. Add account → log in with your professional IG account → Allow.
  2. Click Generate tokencopy it immediately (it's shown once). It's an IGAA… long-lived token (~60 days).

The default consent covers messaging + basic profile — it does not include publishing. That's enough to validate the connection (next step); adding the publish permission for actual posting is §7.

5. Validate the connection

curl -s "https://graph.instagram.com/me\
?fields=user_id,username,account_type\
&access_token=<TOKEN>"
# → {"user_id":"178414...","username":"yourhandle","account_type":"MEDIA_CREATOR", ...}

A clean JSON response means the token + account work. The user_id is your platforms.instagram.user_id.

6. Configure keryx

export INSTAGRAM_ACCESS_TOKEN='<TOKEN>'   # env only, never committed
# ~/.keryx/config.yaml
platforms:
  instagram:
    enabled: true
    user_id: "178414..."

A dry-run validates wiring without posting:

keryx post instagram --workspace <slug> --dry-run

7. Enable posting (content publish)

The connection token from §4 can't post (messaging/basic scope only). To post Reels:

  1. Use case → Permissions and features → add instagram_business_content_publish. For your own account it works under Standard Access (no App Review).
  2. Regenerate the token (§4) so it carries the publish scope, and update INSTAGRAM_ACCESS_TOKEN.

Reels publishing via this API supports Professional accounts (Business and Creator). If a publish call is rejected on a Creator account, switching the account to Business is the fallback.

Token lifecycle

The long-lived token lasts ~60 days and refreshes headlessly before expiry:

curl -s "https://graph.instagram.com/refresh_access_token\
?grant_type=ig_refresh_token&access_token=<TOKEN>"

keryx auth instagram (capture) and keryx auth refresh (rotate + persist, with alert-on-failure) will automate this — until then, refresh manually in the window.

Appendix: short-lived → long-lived exchange

If you obtain a short-lived token via the raw OAuth flow rather than the dashboard button, exchange it once:

curl -s "https://graph.instagram.com/access_token\
?grant_type=ig_exchange_token\
&client_secret=<INSTAGRAM_APP_SECRET>\
&access_token=<SHORT_LIVED_TOKEN>"
# → {"access_token":"IGAA...","expires_in":5183944}

The raw OAuth authorize URL (for keryx auth to automate): https://www.instagram.com/oauth/authorize?client_id=<INSTAGRAM_APP_ID>&redirect_uri=<REDIRECT>&response_type=code&scope=instagram_business_basic,instagram_business_content_publish