← back to Marketing Command Center
channels: add /ig-audit — enumerate ALL Instagram accounts (page-linked + business owned/client), not just the 34 page-linked
bec82b0495afaf06b194dd0aeb7280ad2ffeba26 · 2026-07-16 16:53:59 -0700 · Steve Abrams
Files touched
M modules/channels/index.js
Diff
commit bec82b0495afaf06b194dd0aeb7280ad2ffeba26
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Jul 16 16:53:59 2026 -0700
channels: add /ig-audit — enumerate ALL Instagram accounts (page-linked + business owned/client), not just the 34 page-linked
---
modules/channels/index.js | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/modules/channels/index.js b/modules/channels/index.js
index 6c5af5f..1bee6f9 100644
--- a/modules/channels/index.js
+++ b/modules/channels/index.js
@@ -554,6 +554,41 @@ module.exports = {
res.json({ ok: true, saved: Object.keys(updates), status: platformStatus() });
});
+ // Deep IG audit — find EVERY Instagram account this Meta user can reach, not
+ // just the page-linked ones. Three sources, deduped by IG id:
+ // 1. page-linked IG (from /me/accounts → instagram_business_account, per-page)
+ // 2. Business-Manager OWNED igs (/{business}/owned_instagram_accounts)
+ // 3. Business-Manager CLIENT igs (/{business}/client_instagram_accounts)
+ // Personal (non-Business/Creator) IG accounts are invisible to the Graph API and
+ // cannot appear here — that gap is reported so the count is honest.
+ router.get('/ig-audit', async (_req, res) => {
+ const token = env('META_ACCESS_TOKEN');
+ if (!token) return res.status(400).json({ error: 'META_ACCESS_TOKEN not set' });
+ const seen = new Map(); // igId → {username, id, via}
+ const add = (ig, via) => { if (ig && ig.id && !seen.has(ig.id)) seen.set(ig.id, { id: ig.id, username: ig.username || null, via }); };
+ const getJSON = async (u) => { try { const r = await fetch(u); return await r.json(); } catch { return {}; } };
+ try {
+ // 1. page-linked (reuse the fresh per-page resolver)
+ const cache = await fetchMetaPages();
+ for (const p of cache.pages) if (p.igId) add({ id: p.igId, username: p.igUsername }, 'page');
+ // 2 + 3. businesses → owned + client IG accounts
+ const biz = await getJSON(`${GRAPH}/me/businesses?fields=id,name&limit=100&access_token=${encodeURIComponent(token)}`);
+ const businesses = (biz.data || []);
+ for (const b of businesses) {
+ for (const edge of ['owned_instagram_accounts', 'client_instagram_accounts', 'instagram_business_accounts']) {
+ let url = `${GRAPH}/${b.id}/${edge}?fields=username,id&limit=200&access_token=${encodeURIComponent(token)}`, guard = 0;
+ while (url && guard++ < 20) {
+ const j = await getJSON(url);
+ for (const ig of (j.data || [])) add(ig, edge.replace('_instagram_accounts', ''));
+ url = j.paging?.next || null;
+ }
+ }
+ }
+ const all = [...seen.values()].sort((a, b) => (a.username || '').localeCompare(b.username || ''));
+ res.json({ total: all.length, businesses: businesses.map(b => b.name), byVia: all.reduce((m, a) => (m[a.via] = (m[a.via] || 0) + 1, m), {}), accounts: all });
+ } catch (e) { res.status(500).json({ error: e.message }); }
+ });
+
// OAuth: start the connect flow → redirect the browser to the platform consent.
router.get('/connect/:platform', (req, res) => {
const url = authorizeUrl(req.params.platform);
← a8a2166 auto-save: 2026-07-16T16:43:46 (1 files) — package-lock.json
·
back to Marketing Command Center
·
docs: IG fleet connect checklist (35 live + convert/link ste bb5f304 →