Social Media
Generate and publish social media content across platforms.
One social content record holds every platform variant of a single post. You request a set of platforms, you get back one content_id, and the per-platform captions live inside that record. Read the data model section before you write any parsing code.
There is no platform column and no content column on a social content record. Captions live in the platforms object, keyed by platform name. Images live in image_urls.
/api/v1/social/contentReturns a paginated list of your social media content records. Supports filtering by platform, status, source article, and project.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| page | integer | Optional | Page number(default: 1) |
| limit | integer | Optional | Results per page (1-100)(default: 20) |
| platform | string | Optional | Filter to records that target this platform. One of the 10 supported values. |
| status | string | Optional | Filter by status: draft, queued, generating, ready, completed, scheduled, published, failed |
| article_id | uuid | Optional | Filter by source article ID |
| project_id | uuid | Optional | Filter by project ID |
curl "https://www.brainpercent.app/api/v1/social/content?platform=linkedin&status=completed&page=1&limit=10" \
-H "Authorization: Bearer bp_your_key"{
"success": true,
"data": [
{
"id": "c4a1e8b2-9f3d-4e7a-b5c6-1d2e3f4a5b6c",
"article_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"project_id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"title": "AI SEO strategies for 2026",
"status": "completed",
"source_url": "https://example.com/blog/ai-seo-strategies",
"source_type": "blog",
"language": "en",
"platforms": {
"linkedin": "Most teams treat SEO and AI as separate budgets. The ones winning in 2026 stopped doing that...",
"instagram": "SEO in 2026 is a different sport. Swipe for the 5 shifts that actually moved our numbers."
},
"image_urls": {
"linkedin": "https://xyz.supabase.co/storage/v1/object/public/social/linkedin-1.png",
"instagram": "https://xyz.supabase.co/storage/v1/object/public/social/instagram-1.png"
},
"video_urls": {},
"scheduled_publish_at": null,
"error_message": null,
"created_at": "2026-02-01T10:30:00Z",
"updated_at": "2026-02-01T10:38:00Z"
}
],
"pagination": {
"total": 15,
"page": 1,
"limit": 10,
"total_pages": 2,
"has_more": true
}
}/api/v1/social/content/:idReturns the full record for a single social content item. Includes everything from the list response plus the source author, overlay images, first comments, thread items, the per-platform carousel plans, and publishing state.
curl https://www.brainpercent.app/api/v1/social/content/CONTENT_ID \
-H "Authorization: Bearer bp_your_key"{
"success": true,
"data": {
"id": "c4a1e8b2-9f3d-4e7a-b5c6-1d2e3f4a5b6c",
"article_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"project_id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"title": "AI SEO strategies for 2026",
"status": "completed",
"source_url": "https://example.com/blog/ai-seo-strategies",
"source_type": "blog",
"source_author": "Jane Doe",
"language": "en",
"platforms": {
"linkedin": "Most teams treat SEO and AI as separate budgets...",
"instagram": "SEO in 2026 is a different sport. Swipe for the 5 shifts..."
},
"image_urls": {
"linkedin": "https://xyz.supabase.co/storage/v1/object/public/social/linkedin-1.png",
"instagram": "https://xyz.supabase.co/storage/v1/object/public/social/instagram-1.png"
},
"overlay_urls": {},
"video_urls": {},
"first_comments": {
"linkedin": "Full breakdown in the article linked in my profile."
},
"thread_items": [],
"instagram_carousel_plan": [
{
"slide": 1,
"headline": "SEO in 2026"
}
],
"linkedin_carousel_plan": [],
"tiktok_carousel_plan": [],
"facebook_carousel_plan": [],
"twitter_carousel_plan": [],
"threads_carousel_plan": [],
"bluesky_carousel_plan": [],
"telegram_carousel_plan": [],
"processing_stage": "done",
"processing_progress": 100,
"is_published": false,
"late_dev_post_id": null,
"scheduled_publish_at": null,
"error_message": null,
"created_at": "2026-02-01T10:30:00Z",
"updated_at": "2026-02-01T10:38:00Z"
}
}/api/v1/social/generateGenerate social content from a source URL for one or more platforms. Costs 0.6 credits per platform and requires write permission. Returns a single content_id covering every requested platform, not one per platform.
Request Body
| Name | Type | Required | Description |
|---|---|---|---|
| source_url | string (URL) | Required | Source page to generate content from |
| platforms | string[] | Required | Target platforms, 1 to 10 values from the supported list |
| source_type | string | Optional | website, blog, or youtube(default: website) |
| angle | string | Optional | Direction hint for the post, for example "focus on the cost savings" (max 500 characters) |
| title | string | Optional | Override the derived title (max 200 characters) |
| project_id | uuid | Optional | Project to generate under. Defaults to your active project. |
curl -X POST https://www.brainpercent.app/api/v1/social/generate \
-H "Authorization: Bearer bp_your_key" \
-H "Content-Type: application/json" \
-d '{
"source_url": "https://example.com/blog/ai-seo-strategies",
"platforms": ["twitter", "linkedin"],
"source_type": "blog",
"angle": "Lead with the measurable result, not the tooling"
}'{
"success": true,
"data": {
"content_id": "c4a1e8b2-9f3d-4e7a-b5c6-1d2e3f4a5b6c",
"status": "generating",
"platforms": [
"twitter",
"linkedin"
],
"credits_deducted": 1.2,
"credits_remaining": 48.8,
"poll_url": "/api/v1/social/content/c4a1e8b2-9f3d-4e7a-b5c6-1d2e3f4a5b6c"
}
}/api/v1/social/publishPublish or schedule a social content record to your connected accounts. Omit scheduled_at to publish immediately. Requires write permission and at least one connected social profile.
Request Body
| Name | Type | Required | Description |
|---|---|---|---|
| content_id | uuid | Required | ID of the social content record to publish |
| platforms | string[] | Optional | Optional subset of platforms to publish. Defaults to every platform present on the record. |
| scheduled_at | datetime | Optional | ISO 8601 timestamp to schedule publishing. Omit to publish now. |
# Publish now, to every platform on the record
curl -X POST https://www.brainpercent.app/api/v1/social/publish \
-H "Authorization: Bearer bp_your_key" \
-H "Content-Type: application/json" \
-d '{ "content_id": "c4a1e8b2-9f3d-4e7a-b5c6-1d2e3f4a5b6c" }'
# Or schedule a subset of platforms
curl -X POST https://www.brainpercent.app/api/v1/social/publish \
-H "Authorization: Bearer bp_your_key" \
-H "Content-Type: application/json" \
-d '{
"content_id": "c4a1e8b2-9f3d-4e7a-b5c6-1d2e3f4a5b6c",
"platforms": ["linkedin"],
"scheduled_at": "2026-02-15T14:00:00Z"
}'{
"success": true,
"data": {
"content_id": "c4a1e8b2-9f3d-4e7a-b5c6-1d2e3f4a5b6c",
"status": "publishing",
"profiles": 2
}
}Data Model
A social content record is one post with many platform variants. The platforms field has two shapes depending on where the record is in its lifecycle:
| When | Shape of platforms | Example |
|---|---|---|
| Still generating | Array of requested platform names | ["linkedin", "instagram"] |
| Generation finished | Object keyed by platform, values are captions | { "linkedin": "caption..." } |
Always branch on the shape before reading captions:
Array.isArray(data.platforms) → still generating, no captions yetdata.platforms[platform] holds the captionFor images, read image_urls[platform]. Those are permanent Supabase Storage URLs.
Content Statuses
The status field on a social content record is one of exactly these values:
| Status |
|---|
draft |
queued |
generating |
ready |
completed |
scheduled |
published |
failed |
Supported Platforms
Exactly these 10 values are accepted in the platforms array and the platform query filter:
| Platform | Value |
|---|---|
instagram | |
facebook | |
linkedin | |
| X (Twitter) | twitter |
| Threads | threads |
| TikTok | tiktok |
| Bluesky | bluesky |
pinterest | |
| Google Business Profile | google_business |
| Telegram | telegram |
Permissions & Credits
| Endpoint | Permission | Scope | Credits |
|---|---|---|---|
| GET /social/content | read | social | 0 |
| GET /social/content/:id | read | social | 0 |
| POST /social/generate | write | social | 0.6 per platform |
| POST /social/publish | write | social | 0 |
Credit calculation: 0.6 credits per platform, and 1 credit equals $1.00 of account balance. Generating for X plus LinkedIn costs 1.2 credits. Generating for all 10 platforms costs 6 credits. It all comes out of one balance, so there is nothing reserved for social specifically.
Error Responses
| Status | Code | When |
|---|---|---|
| 400 | VALIDATION_ERROR | Missing source_url, empty platforms array, or an unrecognized platform value |
| 400 | NO_PROJECT | Your account has no project yet. Create one in the app first. |
| 402 | INSUFFICIENT_CREDITS | Balance below the cost for the requested platforms |
| 403 | FORBIDDEN | API key lacks write permission or the social scope |
| 404 | NOT_FOUND | content_id does not exist or is not owned by your account |
| 409 | CONFLICT | The content has already been published |
| 412 | PRECONDITION_FAILED | The content is still generating, or no social profiles are connected |
Connect your accounts at brainpercent.app/chat/settings/social-accounts before calling the publish endpoint.
Scheduling Content
Publishing behaviour is decided by whether you send scheduled_at:
| Request | HTTP status | Returned status |
|---|---|---|
Omit scheduled_at | 202 | publishing |
Send scheduled_at | 200 | scheduled |
The value must be an ISO 8601 datetime. UTC (2026-02-15T14:00:00Z) is the recommended format. An offset such as 2026-02-15T09:00:00-05:00 is also accepted.
{
"success": true,
"data": {
"content_id": "c4a1e8b2-9f3d-4e7a-b5c6-1d2e3f4a5b6c",
"status": "scheduled",
"scheduled_at": "2026-02-15T14:00:00Z"
}
}