# SocialPoster.pro Agent API

Machine-readable contract for Grok Bot and other agents. Prefer this file and https://socialposter.pro/agent-manifest.json over the React UI at https://socialposter.pro/agent-docs.

Human UI: https://socialposter.pro/agent-docs
Grok Bot guide (markdown): https://socialposter.pro/pages/grok-bot.md
Skill: https://socialposter.pro/skills/grok-bot.md
llms.txt: https://socialposter.pro/llms.txt

## Auth

- Header: `Authorization: Bearer sp_live_<key>`
- Human creates the key at https://socialposter.pro/dashboard/account?tab=api-keys (shown once). Store it in a Grok Bot secret card or MCP Authorization header — never in chat.
- Keys are user-scoped. Do not log keys in plaintext.
- Rate limit: 120 API requests per hour per key; 5 SocialPoster image generations per hour.

## URLs

- REST: `https://zqfnpnlzynhugeivtrka.supabase.co/functions/v1/agent-api`
- MCP: `https://zqfnpnlzynhugeivtrka.supabase.co/functions/v1/mcp` with `Authorization: Bearer <key>`
- Prefer MCP tools (`socialposter_*`) when available.

## Startup workflow

1. `GET /me` — verify the key; read scopes and plan. 401 → stop.
2. `GET /projects` — list brands. Match one named project. Never invent project ids.
3. `GET /projects/:id/generation-context` — use `system_prompt` as brand voice.
4. `GET /projects/:id/connections` — only use returned `platform_id` values. If empty, draft in chat only; do not create a post.
5. Draft one post. Show the human the copy, image, platforms, and schedule. Wait for approval.
6. `POST /posts` only after approval (or `socialposter_create_post` via MCP).

## Grok Bot drop-in prompt

Paste this to Grok Bot (replace `PROJECT_NAME` with the exact project name from the dashboard):

```
Connect to SocialPoster.pro using https://socialposter.pro/agent-docs
I will provide the API key via a secret card. Do not ask me to put the key in chat.
Own the project named "PROJECT_NAME".
Draft posts, then wait for my approval before publishing.
```

## Endpoints

| Method | Path | Purpose |
| --- | --- | --- |
| GET | `/me` | Verify auth, read scopes, plan, profile |
| GET | `/projects` | List projects with brand context |
| GET | `/projects/:id` | One project + generation_context |
| GET | `/projects/:id/generation-context` | system_prompt + structured context |
| GET | `/projects/:id/connections` | Connected social platforms |
| GET | `/posts` | List posts (`project_id`, `status`, `limit`) |
| POST | `/posts` | Create or schedule a post |
| POST | `/images` | Generate a standalone AI image (HTTPS URL) |
| DELETE | `/posts/:id` | Cancel a scheduled post (not published) |
| GET | `/analytics/profile` | Profile analytics (`project_id` required) |
| GET | `/analytics/posts` | Post analytics (`project_id` required) |
| GET | `/analytics/insights` | Top posts and platform averages |

### POST /posts body

```json
{
  "project_id": "<uuid>",
  "content": "<text>",
  "platforms": ["twitter", "linkedin"],
  "scheduled_at": "2026-04-20T15:00:00Z",
  "image_url": "https://...",
  "auto_image": false,
  "image_prompt": "optional"
}
```

Omit `scheduled_at` only if the user said post now. Convert local times to ISO 8601 UTC.

Optional image: `auto_image: true`, `image_prompt`, `image_url`, or inline markers in content (`[image: ...]` or `/image ...`). Markers are stripped from the saved post. HTTPS images only, max 5MB, JPEG/PNG/WebP/GIF.

Character limits: Twitter 280, LinkedIn 3000, Threads 500, Bluesky 300.

## Platform ids

Use only these strings, and only if `/connections` returned them:

`twitter` `linkedin` `instagram` `facebook` `tiktok` `youtube` `threads` `pinterest` `bluesky` `snapchat` `google_business`

## Errors

- 401: invalid or revoked key — stop
- 403: missing scope — tell the user
- 429: back off
- 4xx: quote the response body to the user

## Never

- Store the API key in a secret card or MCP header — never in chat or logs
- Invent project ids, platform names, testimonials, prices, or reviews
- Post to a platform not in `/connections`
- Publish without human approval unless the human already said to publish
