Publish, schedule, and manage social media posts across Twitter/X, Facebook, Instagram, TikTok, and YouTube. Content calendar with gap analysis, A/B testing,...
---
name: socialcannon
description: >
Publish, schedule, and manage social media posts across Twitter/X, Facebook,
Instagram, TikTok, and YouTube. Content calendar with gap analysis,
A/B testing, engagement inbox, AI content repurposing, optimal timing
suggestions, auto-scheduling, and UTM tracking.
version: 1.5.1
metadata:
openclaw:
requires:
env:
- SOCIALCANNON_CLIENT_ID
- SOCIALCANNON_CLIENT_SECRET
bins:
- curl
primaryEnv: SOCIALCANNON_CLIENT_ID
emoji: "\U0001F4E3"
homepage: https://socialcannon.app
---
# SocialCannon
Social media publishing API. Publish to Twitter/X, Facebook, Instagram, TikTok, and YouTube from one API with scheduling, analytics, A/B testing, and AI-powered features. (LinkedIn and Reddit are planned for a future release.)
**Base URL:** `https://socialcannon.app`
> **Closed beta — invite only.** SocialCannon is currently in closed beta while we finalize platform integrations. Public signup is not yet open. To request access, email **support@socialcannon.app** with a short note about how you plan to use the API.
## Getting Started
Before making API calls, you need credentials and at least one connected social account.
### 1. Get your API credentials
SocialCannon is in **closed beta** — accounts are issued by request, not self-serve. Email **support@socialcannon.app** to request beta access. Once approved, you'll be sent an invite link to sign in at [socialcannon.app](https://socialcannon.app). Your **Client ID** and **Client Secret** are then available on the dashboard Settings page — these are the values for `SOCIALCANNON_CLIENT_ID` and `SOCIALCANNON_CLIENT_SECRET`.
### 2. Connect social accounts
Social accounts are connected via OAuth in the browser. Open the connect URL for each platform you want to use — you'll authorize SocialCannon and get redirected back:
| Platform | Connect URL |
|----------|-------------|
| Twitter/X | `https://socialcannon.app/api/connect/twitter?client_id=YOUR_CLIENT_ID` |
| Facebook | `https://socialcannon.app/api/connect/facebook?client_id=YOUR_CLIENT_ID` |
| Instagram | `https://socialcannon.app/api/connect/instagram?client_id=YOUR_CLIENT_ID` |
| TikTok | `https://socialcannon.app/api/connect/tiktok?client_id=YOUR_CLIENT_ID` |
| YouTube | `https://socialcannon.app/api/connect/youtube?client_id=YOUR_CLIENT_ID` |
You can also connect accounts from the dashboard at **Settings → Accounts**. Instagram uses Facebook's OAuth flow — make sure you select the Facebook Page linked to your Instagram Business account.
### 3. Get an API token and start posting
Once you have credentials and at least one connected account, authenticate and create your first post:
```bash
# Get a token
TOKEN=$(curl -s -X POST https://socialcannon.app/api/v1/auth/token \
-H "Content-Type: application/json" \
-d "{\"grant_type\": \"client_credentials\", \"client_id\": \"$SOCIALCANNON_CLIENT_ID\", \"client_secret\": \"$SOCIALCANNON_CLIENT_SECRET\"}" \
| jq -r '.data.access_token')
# List your connected accounts
curl -s https://socialcannon.app/api/v1/accounts \
-H "Authorization: Bearer $TOKEN" | jq '.data'
# Publish a post (replace <account_id> with an ID from the list above)
curl -X POST https://socialcannon.app/api/v1/posts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"accountId": "<account_id>", "content": "Hello from SocialCannon!"}'
```
## Authentication
All requests require a JWT Bearer token. Get one by exchanging your client credentials:
```bash
curl -X POST https://socialcannon.app/api/v1/auth/token \
-H "Content-Type: application/json" \
-d "{
\"grant_type\": \"client_credentials\",
\"client_id\": \"$SOCIALCANNON_CLIENT_ID\",
\"client_secret\": \"$SOCIALCANNON_CLIENT_SECRET\"
}"
```
Response:
```json
{
"success": true,
"data": {
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "posts:read posts:write ..."
}
}
```
Use `response.data.access_token` as a Bearer token in all subsequent requests. Tokens expire after 1 hour — request a new one when you get a 401.
**All requests below require this header:**
```
Authorization: Bearer <access_token>
Content-Type: application/json
```
## Response Format
**IMPORTANT: ALL responses are wrapped in a standard envelope.** This includes the token endpoint.
- Success: `{ "success": true, "data": { ... } }`
- Error: `{ "success": false, "error": "message", "code": "ERROR_CODE" }`
When extracting data from any response, always read from `response.data`, not from the response root. For example, to get the access token: `response.data.access_token`, not `response.access_token`.
## Accounts
Accounts represent social media profiles connected via OAuth (see Getting Started above). You need at least one connected account before you can create posts.
### List connected accounts
```bash
curl https://socialcannon.app/api/v1/accounts \
-H "Authorization: Bearer $TOKEN"
```
Returns all connected social accounts with their platform, username, and status. Use the account `id` field when creating posts. Filter by platform with `?platform=twitter`.
### Get a single account
```bash
curl https://socialcannon.app/api/v1/accounts/<account_id> \
-H "Authorization: Bearer $TOKEN"
```
### Disconnect an account
```bash
curl -X DELETE https://socialcannon.app/api/v1/accounts/<account_id> \
-H "Authorization: Bearer $TOKEN"
```
## Posts
### Create a post
Publish immediately (omit `scheduledAt`) or schedule for later:
```bash
curl -X POST https://socialcannon.app/api/v1/posts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accountId": "<account_id>",
"content": "Your post text here",
"mediaUrls": ["https://example.com/image.jpg"],
"scheduledAt": "2026-04-15T10:00:00Z",
"platformOptions": {
"autoUtm": true
}
}'
```
Fields:
- `accountId` (required) — ID from the accounts list
- `content` (required) — post text
- `mediaUrls` (optional) — array of public image/video URLs
- `scheduledAt` (optional) — ISO 8601 datetime, `"optimal"` (auto-pick best time based on engagement data, Pro), or omit for immediate publish
- `platformOptions.autoUtm` (optional) — auto-tag URLs with UTM parameters
- `platformOptions.mediaType` (optional) — controls content type:
- `"reel"` — Facebook/Instagram Reel (vertical 9:16 video)
- `"story"` — Facebook/Instagram/TikTok Story (24h ephemeral)
- `"short"` — YouTube Short (vertical video ≤60s)
- `"community"` — YouTube Community post (text/image)
### List posts
```bash
curl "https://socialcannon.app/api/v1/posts?status=published&platform=twitter&limit=20" \
-H "Authorization: Bearer $TOKEN"
```
Query params: `status` (draft/scheduled/published/failed), `platform`, `accountId`, `limit`, `cursor`
### Get a single post
```bash
curl https://socialcannon.app/api/v1/posts/<post_id> \
-H "Authorization: Bearer $TOKEN"
```
### Update a draft or scheduled post
```bash
curl -X PATCH https://socialcannon.app/api/v1/posts/<post_id> \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "Updated text",
"scheduledAt": "2026-04-16T14:00:00Z",
"platformOptions": { "autoUtm": true }
}'
```
Fields: `content`, `scheduledAt`, `platformOptions` — all optional.
### Delete a post
```bash
curl -X DELETE https://socialcannon.app/api/v1/posts/<post_id> \
-H "Authorization: Bearer $TOKEN"
```
If the post is published, this also attempts to delete it from the social platform.
### Retry a failed post
```bash
curl -X POST https://socialcannon.app/api/v1/posts/<post_id>/retry \
-H "Authorization: Bearer $TOKEN"
```
Resets the failed post and attempts to publish immediately. No body needed. If it fails again, the post returns to `failed` status with the new error.
## Threads & Carousels
Create multi-part threads (Twitter reply chains or Instagram carousels):
```bash
curl -X POST https://socialcannon.app/api/v1/posts/thread \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accountId": "<account_id>",
"items": [
{ "content": "Thread part 1 — the hook" },
{ "content": "Thread part 2 — the detail" },
{ "content": "Thread part 3 — the CTA", "mediaUrls": ["https://..."] }
],
"scheduledAt": "2026-04-15T10:00:00Z",
"platformOptions": { "autoUtm": true }
}'
```
Fields: `accountId` (required), `items` (required, min 2, max 25), `scheduledAt` (optional), `platformOptions` (optional). Instagram requires media on each item.
## Media Upload
Upload images/videos before creating posts. **Three-step direct-to-GCS flow** — bytes go straight to Google Cloud Storage via a signed URL, never through SocialCannon's server. This supports files up to **4GB**.
Accepted types: `image/jpeg`, `image/png`, `image/gif`, `image/webp`, `video/mp4`, `video/quicktime`, `video/webm`.
### Step 1 — Initialize upload
```bash
curl -X POST https://socialcannon.app/api/v1/media/upload-init \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"filename": "photo.jpg",
"contentType": "image/jpeg",
"size": 1048576
}'
```
Response:
```json
{
"success": true,
"data": {
"uploadUrl": "https://storage.googleapis.com/...?X-Goog-Signature=...",
"publicUrl": "https://storage.googleapis.com/<bucket>/media/<clientId>/<uuid>.jpg",
"requiredHeaders": {
"Content-Type": "image/jpeg",
"x-goog-acl": "public-read"
}
}
}
```
`uploadUrl` is a V4 signed PUT URL valid for **15 minutes**. `size` must be the exact byte size of the file you're about to upload.
### Step 2 — PUT the file to the signed URL
```bash
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: image/jpeg" \
-H "x-goog-acl: public-read" \
--data-binary @photo.jpg
```
You **must** send the exact headers returned in `requiredHeaders`. Do **not** send the `Authorization` header — the signed URL carries its own auth. A successful PUT returns HTTP 200 with an empty body.
### Step 3 — Finalize
```bash
curl -X POST https://socialcannon.app/api/v1/media/upload-complete \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "publicUrl": "https://storage.googleapis.com/<bucket>/media/<clientId>/<uuid>.jpg" }'
```
Pass the `publicUrl` you got from step 1 verbatim. The server verifies the object exists, stamps `customTime` (starting the 30-day retention window), and increments your upload quota.
Response: `{ "success": true, "data": { "url": "https://...", "filename": "media/<clientId>/<uuid>.jpg", "contentType": "image/jpeg", "size": 1048576 } }`
Use the returned `url` in the `mediaUrls` field when creating posts. Bytes are stored as-is — there is no server-side optimization, so upload the format/quality you want published.
### Quota & errors
- `403` on step 1 with `code` set → your tier has hit its upload quota. Inspect `limit` in the response body.
- `404` on step 3 → the PUT didn't actually land. Retry from step 2.
- `403` on step 3 → `publicUrl` doesn't belong to your client. Use the exact URL returned by step 1, do not construct it yourself.
## Content Calendar
### Get calendar view
See posts grouped by date with gap analysis:
```bash
curl "https://socialcannon.app/api/v1/calendar?startDate=2026-04-01&endDate=2026-04-30" \
-H "Authorization: Bearer $TOKEN"
```
Returns `posts`, `summary` (totals by status/platform/day), and `gaps` (dates with no posts).
Query params: `startDate` (required), `endDate` (required), `accountId`, `platform`
### Find available slots
```bash
curl "https://socialcannon.app/api/v1/calendar/slots?startDate=2026-04-01&endDate=2026-04-07&slotDurationMinutes=60" \
-H "Authorization: Bearer $TOKEN"
```
Query params: `startDate` (required), `endDate` (required, max 14-day range), `slotDurationMinutes` (optional, 30-1440, default 60).
Returns `{ slots[], totalSlots, availableSlots, occupiedSlots }`.
## Analytics
### Per-post analytics
Fetch live engagement metrics from the platform:
```bash
curl https://socialcannon.app/api/v1/posts/<post_id>/analytics \
-H "Authorization: Bearer $TOKEN"
```
Returns: likes, comments, shares, impressions, reach, clicks, engagementRate, plus historical snapshots.
### Aggregate analytics
```bash
curl "https://socialcannon.app/api/v1/analytics/summary?startDate=2026-04-01&endDate=2026-04-30" \
-H "Authorization: Bearer $TOKEN"
```
Returns totals across all posts for the date range.
### Bulk refresh analytics
```bash
curl -X POST https://socialcannon.app/api/v1/analytics/refresh \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "platform": "twitter", "limit": 20 }'
```
Fields: `postIds` (optional, array of up to 50 post IDs to refresh), `platform` (optional, filter), `limit` (optional, default 20, max 50). If `postIds` is provided, those specific posts are refreshed; otherwise recent published posts are refreshed.
## Engagements (Comment Inbox)
### List engagements
```bash
curl "https://socialcannon.app/api/v1/engagements?isRead=false&limit=20" \
-H "Authorization: Bearer $TOKEN"
```
Query params: `postId`, `isRead` (true/false), `limit`, `cursor`
### Fetch engagements for a post
```bash
curl "https://socialcannon.app/api/v1/posts/<post_id>/engagements?cursor=<next_cursor>" \
-H "Authorization: Bearer $TOKEN"
```
Fetches fresh comments from the platform and stores them. Supports `cursor` for pagination.
### Mark as read
```bash
curl -X PATCH https://socialcannon.app/api/v1/engagements/<engagement_id> \
-H "Authorization: Bearer $TOKEN"
```
Marks the engagement as read. No request body needed — the endpoint auto-marks on PATCH.
### Reply to an engagement
```bash
curl -X POST https://socialcannon.app/api/v1/engagements/<engagement_id>/reply \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "content": "Thanks for the feedback!" }'
```
Posts the reply directly on the social platform.
## AI Content Repurposing
Adapt content for multiple platforms using AI. Two modes available:
### Preview mode (default) — adapt and return variants for review:
```bash
curl -X POST https://socialcannon.app/api/v1/posts/repurpose \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sourceContent": "Your long-form content here...",
"targetPlatforms": ["twitter", "facebook", "tiktok"],
"mode": "preview",
"tone": "professional"
}'
```
Returns `{ "variants": [{ "platform", "content", "validation", "characterCount" }], "allValid" }`.
### Post mode — adapt and publish in one call:
```bash
curl -X POST https://socialcannon.app/api/v1/posts/repurpose \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sourceContent": "Your content here...",
"targetPlatforms": ["twitter", "facebook"],
"mode": "post",
"accountIds": { "twitter": "acc_123", "facebook": "acc_456" },
"mediaUrls": { "twitter": ["https://example.com/video.mp4"] },
"appendContent": { "twitter": "Links or extra text for Twitter only" },
"appendToAll": "Text appended to all platforms"
}'
```
Returns `{ "results": [{ "platform", "success", "postUrl?", "error?" }] }`.
All content is humanized automatically to remove AI writing patterns. Trusted clients bypass tier limits.
## A/B Testing (Pro)
### Create a test
```bash
curl -X POST https://socialcannon.app/api/v1/ab-tests \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accountId": "<account_id>",
"name": "CTA test",
"variants": [
{ "content": "Check out our new feature!", "mediaUrls": ["https://..."] },
{ "content": "You won'\''t believe this new feature..." }
],
"metric": "engagementRate",
"minDurationHours": 24,
"scheduledAt": "2026-04-20T10:00:00Z"
}'
```
**Publish behavior matches `POST /api/v1/posts`:**
- **Omit `scheduledAt`** → all variants publish **immediately** to the platform via the social adapter
- **Provide `scheduledAt`** → all variants are **scheduled** for that time (must be within 30 days; cron publishes them hourly)
Each variant is a separate post record. Auto-completes after `minDurationHours` and the winner is determined by the chosen metric. Per-variant `mediaUrls` is optional.
**Partial failure semantics:** if ANY variant fails to publish during immediate mode, the endpoint returns **HTTP 502** and the failed variants are marked with `status: 'failed'`. The A/B test record is still created, but the winner comparison at completion only considers successfully published variants. Inspect each variant's post status before relying on test results.
### Get test results
```bash
curl https://socialcannon.app/api/v1/ab-tests/<test_id> \
-H "Authorization: Bearer $TOKEN"
```
Returns per-variant metrics, current winner, and confidence score.
### List tests
```bash
curl "https://socialcannon.app/api/v1/ab-tests?status=active" \
-H "Authorization: Bearer $TOKEN"
```
### Force-complete a test
```bash
curl -X POST https://socialcannon.app/api/v1/ab-tests/<test_id>/complete \
-H "Authorization: Bearer $TOKEN"
```
## Timing Suggestions (Pro)
### Get recommended posting times
```bash
curl "https://socialcannon.app/api/v1/accounts/<account_id>/timing?timezone=UTC-5" \
-H "Authorization: Bearer $TOKEN"
```
Returns top 5 time slots ranked by average engagement rate with confidence scores.
### Find the single best available slot
Combines engagement data with calendar availability:
```bash
curl "https://socialcannon.app/api/v1/timing/optimal-slot?accountId=<account_id>&timezone=UTC-5" \
-H "Authorization: Bearer $TOKEN"
```
Returns the next open slot ranked by historical performance.
### Auto-schedule multiple posts
Distribute posts across optimal time slots for the next 7 days:
```bash
curl -X POST https://socialcannon.app/api/v1/posts/auto-schedule \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accountId": "<account_id>",
"posts": [
{ "content": "Post 1 text" },
{ "content": "Post 2 text", "mediaUrls": ["https://..."] },
{ "content": "Post 3 text" }
],
"timezone": "UTC-5"
}'
```
Max 20 posts per request. Each post gets a unique slot. Returns `{ scheduled: [...], unscheduled: [...], summary: {...} }`.
## UTM Link Tracking
Generate UTM-tagged URLs:
```bash
curl -X POST https://socialcannon.app/api/v1/links/generate \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/product",
"platform": "twitter",
"campaign": "spring-launch",
"content": "hero-cta",
"postId": "<post_id>",
"save": true
}'
```
Fields: `url` (required), `platform` (optional — sets `utm_source`), `campaign` (optional — `utm_campaign`), `content` (optional — `utm_content`), `term` (optional — `utm_term`), `postId` (optional — link to a post), `save` (optional, default true — persist to tracked_links).
### List tracked links
```bash
curl "https://socialcannon.app/api/v1/links?postId=<post_id>&platform=twitter&limit=20&cursor=<cursor>" \
-H "Authorization: Bearer $TOKEN"
```
Query params: `postId`, `platform`, `limit`, `cursor` — all optional.
## Platforms
List supported platforms and their capabilities (public, no auth required):
```bash
curl https://socialcannon.app/api/v1/platforms
```
## Platform-Specific Notes
### Twitter/X
- 280 char limit. Up to 4 images. Threads via reply chains.
### Facebook
- 63,206 char limit. Supports native scheduling. Page-level tokens.
- **Reels**: Set `platformOptions.mediaType` to `"reel"`. Video must be MP4/MOV, vertical (9:16). Without this, videos post as regular video posts.
- **Stories**: Set `platformOptions.mediaType` to `"story"`. Supports one image or video. Ephemeral (24h).
```bash
curl -X POST https://socialcannon.app/api/v1/posts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accountId": "<account_id>",
"content": "Check out this tutorial!",
"mediaUrls": ["https://example.com/video.mp4"],
"platformOptions": {
"mediaType": "reel"
}
}'
```
### Instagram
- Requires media (no text-only). Max 10 carousel items. No API deletion.
- **Stories**: Set `platformOptions.mediaType` to `"story"`. One image or video.
- **Reels**: Set `platformOptions.mediaType` to `"reel"`. Vertical 9:16 video.
### TikTok
- Requires media — no text-only posts. Supports video, photo carousel (up to 35 images), and Stories.
- **Stories**: Set `platformOptions.mediaType` to `"story"`. One video. Ephemeral (24h).
- Video publish uses async poll model. No API deletion support.
### YouTube
- Supports regular videos, Shorts, and Community posts. Native scheduling support.
- **Shorts**: Set `platformOptions.mediaType` to `"short"`. Vertical video ≤60s.
- **Community posts**: Set `platformOptions.mediaType` to `"community"`. Text/image post to channel's Community tab.
- Scheduled videos are uploaded as private with a `publishAt` timestamp.
## Rate Limits
- Free tier: 30 requests/minute
- Pro tier: 300 requests/minute
- Agency tier: 600 requests/minute
- Enterprise tier: 1200 requests/minute (default; negotiable)
- Returns `429` with `Retry-After` header when exceeded
## Subscription Tiers
Four tiers. Twitter/X is the only platform with a per-post API cost passed through, so every tier carries an X-write quota.
### Free — $0
- 2 connected accounts
- 10 posts per billing period
- **3 Twitter/X posts per billing period** (thread items count individually)
- 2 scheduled posts at a time
- 3 media uploads per billing period
- 2-item threads, 5 tracked links
- Twitter/X, Facebook, Reddit only — Instagram, LinkedIn, TikTok, YouTube are Pro+
- No analytics, no engagement replies, no A/B testing, no timing suggestions
- 30 API requests/minute
### Pro — $15/month
- Unlimited accounts, posts, scheduling on free platforms
- **50 Twitter/X posts per billing period**
- All 4 platforms (Twitter/X, Facebook, Instagram, TikTok, YouTube — LinkedIn and Reddit not publicly listed)
- Analytics with history, 90-day calendar
- 25-item threads, unlimited tracked links
- A/B testing (5 concurrent, 4 variants)
- Engagement replies, timing suggestions
- 300 API requests/minute
### Agency — $49/month
- Everything in Pro
- **250 Twitter/X posts per billing period**
- A/B testing (20 concurrent, 6 variants)
- 365-day calendar range
- Priority support
- 600 API requests/minute
### Enterprise — custom contract
- Custom Twitter/X quota, custom rate limits, SLA, dedicated support
- Contact `sales@socialcannon.app`
### Hitting a cap
Any tier exceeding its `maxTwitterPostsPerPeriod` cap returns:
```json
{
"success": false,
"error": "Twitter/X post limit reached (50/50). Upgrade to Pro for unlimited Twitter publishing.",
"code": "LIMIT_EXCEEDED",
"limit": { "type": "twitter_posts_per_period", "current": 50, "max": 50, "tier": "pro" }
}
```
HTTP `403`. Resets at the start of the next billing period.
## Support
If you run into issues with the API, account connections, or integration setup, contact **support@socialcannon.app**.
## Tips for Agents
1. Always list accounts first to get valid `accountId` values before creating posts.
2. Use the calendar endpoint to check for gaps before suggesting new posts.
3. For Instagram and TikTok, always include at least one media URL — text-only posts will fail.
4. Use `autoUtm: true` in `platformOptions` to automatically tag URLs in posts.
5. Check analytics after 24+ hours for meaningful engagement data.
6. When repurposing content, review the returned `validation` field — if `valid` is false, adjust the content before publishing.
7. Use `scheduledAt: "optimal"` to let SocialCannon pick the best posting time automatically (Pro).
8. For batch scheduling, use the auto-schedule endpoint instead of creating posts one by one.
9. For YouTube, set `mediaType` to `"short"` for Shorts or `"community"` for Community tab posts.
don't have the plugin yet? install it then click "run inline in claude" again.