# Social Planner API — verified details (2026-08-03)

Base: `https://services.leadconnectorhq.com` · headers on every call: `Authorization: Bearer`, `Version: 2021-07-28`, `Accept: application/json`.

## Auth: the agency token WORKS here (unlike funnels)

The V3 agency token (168 scopes) reads AND writes Social Planner endpoints on any sub-account — verified live: `GET /social-media-posting/{locationId}/accounts` → 200 on RRR; `POST .../posts` → 422 validation error (auth passed, payload wrong). Funnels endpoints are the opposite (401 authClass). Always try the agency token first for `socialplanner/*`.

## Connected accounts (as of 2026-08-03, post-swap)

The social accounts were initially connected to the WRONG sub-accounts (LinkedIn on RRR, RRR's Facebook page on Pipeline Layer) and Rob swapped them in the GHL UI end-of-session 2026-08-03. Correct mapping now:

- **RRR** (`4yTvHUHrmVuP8CgCt1Q9`): Facebook page "Real Results Ready LLC" — RRR is Facebook-first (local service SMBs).
- **Pipeline Layer** (`k6PTFz0gXAdNJLDT1aji`): LinkedIn profile "Rob Blake" — account id `6a30cb2882b70196e6c86d22_4yTvHUHrmVuP8CgCt1Q9_4lUv9N6zv5_profile` was the RRR-side id pre-swap; RE-FETCH account ids per locationId with `GET .../accounts` before scheduling (account ids embed the locationId and will differ post-reconnect). LinkedIn token expires ~2026-09-29.
- **Test Sandbox** (`VLPUVcvUDOaXhgFPKiGl`): none.

**Brand↔platform rule (user-stated 2026-08-03): RRR = Facebook (local/B2C), Pipeline Layer = LinkedIn (B2B RevOps).** Never schedule B2B content to RRR's channels or local-trade content to Pipeline Layer's — Rob caught exactly this mix-up mid-session ("slow down, remember those LinkedIn posts are not for RRR").

## POST /social-media-posting/{locationId}/posts — payload gotchas (from a live 422)

The 422 message array lists every bad field at once. Corrected field rules:

- `scheduleDate` — NOT `scheduledAt` ("property scheduledAt should not exist"; "When status is scheduled or in_review, scheduleDate is required")
- `type` — must be one of `post`, `story`, `reel` (NOT `text`)
- `userId` — required non-empty string (a GHL location user id; get from `GET /users/?locationId=...`)
- `media` — must be an array (empty array is fine); omitting it 422s
- `accountIds` — array of account ids from `GET .../accounts`
- `status` — `scheduled` requires `scheduleDate`

A 422 from this endpoint means auth PASSED — treat it as pure validation feedback, not a permissions problem.

## VERIFIED WORKING create-post payload (5 posts scheduled 201, 2026-08-03)

The two additional rules beyond the 422 list: **`media[].type` must be a MIME type** (`"image/png"`, `"image/jpeg"`) — bare `"image"` 422s `Invalid media format type`; and **no `platform` field** (422 `property platform should not exist`). `userId` = the account's `oauthId` from the accounts list (NOT a location user id — the oauthId worked).

```json
{
  "accountIds": ["<account id from GET .../accounts>"],
  "summary": "<post text>",
  "type": "post",
  "status": "scheduled",
  "scheduleDate": "2026-08-03T09:00:00-06:00",
  "media": [{"url": "https://.../image.png", "type": "image/png"}],
  "userId": "<oauthId of the social account>"
}
```

→ `201 {"message":"Created Post","results":{"post":{...}}}`.

**Response artifact:** the created post echoes `"platform":"google"` regardless of the real destination — it's a display/default field, NOT the target platform. Don't panic. There is no simple GET list endpoint (`GET .../posts` 404s; `POST .../posts/list` exists but rejects `status` filter and wants `limit` as a number-STRING). Easiest verification: GHL UI → Social Planner → Scheduled tab.

**Batch scheduling pattern that worked:** sequential `curl -X POST` per post with ~1s sleep between (no rate-limit issues at 5 posts). Schedule timezone: pass the offset explicitly (`-06:00` MDT) — the stored `displayDate` came back in UTC (`15:00Z` for 9AM MDT), correct.

**First real batch (Pipeline Layer LinkedIn, week of 2026-08-03):** 5 thought-leadership posts Mon–Fri 9AM MDT with generated quote-card images, scheduled via this exact flow.

## LinkedIn format engagement research (pulled 2026-08-03 for scheduling decisions)

From SocialInsider's 2026 benchmarks (1.3M posts, 16,645 business pages, Jan 2024–Dec 2025) — use when advising on format:

| Format | Engagement rate | Notes |
|---|---|---|
| Native document (PDF carousel) | ~7.00% | Highest of any format |
| Multi-image | 6.45–6.90% | Best reach for <50K-follower pages; ~1.3x text-only reach |
| Single image | 4.85–5.30% | ~+20-30% over text-only — always attach an image |
| Text-only | 3.95–4.50% | baseline |
| Link post | 3.25–3.30% | WORST — LinkedIn suppresses external links; put links in the first comment instead |

Other verified findings: long-form text (>1,300 chars) gets ~18% more engagement than short posts (ConnectSafely Q1 2026); overall platform engagement rising YoY across all formats. Practical rule adopted for Rob's batches: every post gets a brand-styled quote-card image (charcoal #2D3748 bg, amber #E8893A pull-quote, "Pipeline Layer" footer), text stays long-form, no external links in the body.
