# Connector Checklist — Meta / LinkedIn / X / Canva

Official **OAuth app** per platform. No platform passwords, no scraping, no
unofficial APIs. Platform rules change — re-verify before go-live.

## Before you start (all platforms)
- [ ] Deploy with **HTTPS** (OAuth redirects fail on http)
- [ ] Note the exact **redirect URI** per platform (shown on the app's Social page)
- [ ] Decide one project = one brand; each brand gets its own platform app(s)

## 1. Meta (Facebook Pages + Instagram Business)

**App type:** Business · **Product:** Facebook Login for Business

| Item | Value / action |
|---|---|
| App creation | developers.facebook.com → Create App → Business |
| Redirect URI | `https://socialops.yourdomain/social_callback.php?provider=meta` |
| Permissions | `pages_show_list`, `pages_read_engagement`, `pages_manage_posts`, `instagram_basic`, `instagram_content_publish` |
| Verification | Required for `pages_manage_posts` + IG publishing before public use |
| Token | Page-scoped long-lived token after exchange; stored encrypted |
| Testing | Publish one test post; check IG requires Business/Creator account linked to a FB Page |

- [ ] App reviewed/approved for needed permissions
- [ ] Redirect URI matches exactly (https, no trailing slash mismatch)
- [ ] Test post published manually via API explorer first
- [ ] Connect in app → status ACTIVE

## 2. LinkedIn

**Product:** Community Management API (requires LinkedIn company page)

| Item | Value / action |
|---|---|
| App creation | linkedin.com/developers → Create app (must be tied to a LinkedIn Page) |
| Products | Request **Community Management API** (posting to org) |
| Redirect URI | `https://socialops.yourdomain/social_callback.php?provider=linkedin` |
| Scopes | `openid profile email` + `w_organization_social` (+ `r_organization_social`) |
| Posting | `POST /rest/posts` with `LinkedIn-Version` header, author = org URN |
| Rate limits | Community Management: low daily org-post quota — fine for a few posts/day |

- [ ] Community Management product approved
- [ ] Test org post via API tools
- [ ] Connect in app → status ACTIVE

## 3. X (Twitter)

**Tier:** Basic or Pro (paid) — required for write access

| Item | Value / action |
|---|---|
| App creation | developer.x.com → Project + App |
| User auth settings | OAuth 2.0, type **Confidential**, Redirect: `https://socialops.yourdomain/social_callback.php?provider=x` |
| Scopes | `tweet.read tweet.write users.read offline.access` |
| Posting | `POST /2/tweets` with PKCE + refresh tokens |
| Media | upload via v1.1 `media/upload` then attach `media.media_ids` |

- [ ] Paid tier active, write scope granted
- [ ] Callback URL saved in the X app settings
- [ ] Test tweet posted via API
- [ ] Connect in app → status ACTIVE

## 4. Canva (optional — asset automation)

**Tier:** Canva Enterprise required for **Autofill API** (automated template
fills). The app detects this: if the API says "not available for your plan" it
shows a **manual fallback** — you design in Canva, download, and upload the
asset here — instead of faking success.

| Item | Value / action |
|---|---|
| App creation | canva.com/developers → Create app |
| Grant type | Authorization code; Redirect: `https://socialops.yourdomain/social_callback.php?provider=canva` |
| Scopes | `asset:read asset:write design:content:read design:content:write` |
| Autofill | Enterprise-only; other plans → use manual fallback |

- [ ] Enterprise plan confirmed if automation is required
- [ ] Otherwise: manual fallback flow agreed with the team

## After connecting (per platform)
- [ ] Row shows ACTIVE with account name
- [ ] Small test post published through the app after approval flow (not directly)
- [ ] Audit log has the connect event; no token anywhere in UI/logs
- [ ] Note token expiry expectations: Meta long-lived ~60 days (auto-refresh on
      use), LinkedIn 60 days, X refresh token with `offline.access`

## Disconnect / rotate
- [ ] Disconnect from Social page (admin confirm) revokes stored token
- [ ] Rotate: disconnect → connect again; in-flight scheduled jobs to that
      account are marked FAILED and notify admins
