← back to Norma

agents/instagram-agent/POSTING.md

66 lines

# Instagram posting — multi-account (35 accounts, one command)

All 35 IG-linked accounts post through **one never-expiring token**
(`META_ACCESS_TOKEN` in `~/Projects/secrets-manager/.env`) via the Facebook Graph
Content Publishing API. No per-account tokens, no refresh cron.

## CLI — `post-to.js`

```bash
cd ~/Projects/Norma/agents/instagram-agent

node post-to.js list                 # all 35, ranked by followers
node post-to.js verify <account>     # read-only: prove the token reaches it
node post-to.js verify --verify-all  # health-sweep every account

# POST (dry-run by default — add --confirm to actually publish)
node post-to.js <account> --product <handle>     --confirm                   # real DW product (auto image+caption)
node post-to.js <account> --image  <public_url> --caption "…" --confirm     # single image
node post-to.js <account> --images "u1,u2,u3"    --caption "…" --confirm     # carousel (2–10)
node post-to.js <account> --reel   <public_mp4>  --caption "…" --confirm     # reel
node post-to.js <account> --story  <public_url>                 --confirm     # story
node post-to.js --all      --image <public_url>  --caption "…" --confirm     # fan out to ALL 35
```

`<account>` = handle (`velvetwallpaper` / `@velvetwallpaper`), page name
(`"Velvet Wallpaper"`), or the raw `ig_user_id`.

### Safety
- **Dry-run is the default.** Nothing publishes without `--confirm` — the
  outward-facing gate is built into the tool.
- `--all` throttles 1.5s/account (each account has its own ~50-posts/24h API limit).
- Media URLs must be **public** (Meta fetches them server-side). Shopify CDN URLs work.

## HTTP — `:9810` (agent-base, Basic-Auth)

The `post`, `reel`, and `story` skills accept an `account` field, so any fleet
agent can publish to a specific handle:

```bash
curl -s -u admin:$PASS -X POST http://127.0.0.1:9810/api/skill/post \
  -H 'Content-Type: application/json' \
  -d '{"account":"velvetwallpaper","image_url":"https://…","caption":"…"}'
```

Account resolution is **registry-first, env-fallback**:
1. handle in `accounts.json`  → shared `META_ACCESS_TOKEN`
2. `dw`                        → `IG_USER_ID` + `IG_ACCESS_TOKEN` (legacy)
3. `phillipe-romano` etc.      → `IG_USER_ID_<SUFFIX>` + `IG_ACCESS_TOKEN_<SUFFIX>`
   (the dw-marketing-reels convention — unchanged)

## Registry — `accounts.json`

Regenerate from the live token (self-healing — link a new IG in Meta Business
Suite and it appears):

```bash
node build-registry.js            # refresh handles/ids
node build-registry.js --stats    # also pull follower/post counts (35 extra GETs)
```

## Not yet postable
- The 45 Facebook Pages with **no linked IG account** (see
  `UNLINKED-PAGES-CHECKLIST.md`) — they'd need IG accounts *created* first.
- `@hospitalityfabrics` — exists (360 followers, 177 posts) but isn't connected
  to a Page, so the API can't reach it. Parked on a Page decision.