API reference.md

Social

Publish to the project's connected Instagram, Threads and Bluesky accounts, now or on a schedule. Accounts are connected once, by a person, from the project's Social page — OAuth to a platform is not something a key can do.

Publishing is public and cannot be recalled from Pharos, so social:publish is treated like the send scopes: it is never on an agent key, and the dashboard flags any key that carries it. See Authentication & keys.

GET /api/social/posts

The project's 50 most recent posts, newest first.

Scope: social:read

Parameter In Type Notes
projectId query string Required.
{
  "posts": [
    {
      "id": "sp_…",
      "platform": "instagram",
      "content": "…",
      "mediaUrl": "https://…/promo.jpg",
      "mediaType": "image",
      "status": "posted",
      "platformPostId": "1789…",
      "scheduledAt": null,
      "postedAt": "2026-09-28T12:00:41.000Z",
      "error": null,
      "createdAt": "2026-09-28T12:00:30.000Z"
    }
  ]
}

status is scheduled, posting, posted or failed. A failed post keeps the platform's message in error.

POST /api/social/posts

Publish one piece of content to one or more platforms. Each platform becomes its own post and succeeds or fails on its own.

Scope: social:publish

Field Type Notes
projectId string Required.
content string Required. Checked against the strictest limit among the chosen platforms — Bluesky 300, Threads 500, Instagram 2200.
platforms string[] Required. Any of instagram, threads, bluesky.
mediaUrl string Required for Instagram, which fetches it itself, so it must be public https. JPEG for images, MP4/MOV for Reels. Ignored by Threads and Bluesky, which post text only.
mediaType enum image or video. Inferred from the extension when omitted.
scheduledAt string ISO datetime. In the future, the post is parked and published by cron; in the past or omitted, it publishes now.
{
  "results": [
    {
      "platform": "instagram",
      "success": true,
      "postId": "sp_…",
      "platformPostId": "1789…"
    }
  ]
}

The response is 200 if any platform succeeded and 502 if none did; read results either way. An Instagram video still transcoding returns "pending": true — the post stays posting and cron finishes it. A platform with no connected account fails with No <platform> account connected.