Posts API
The /v1/posts endpoints let you create, list, inspect, update, reschedule,
retry, and delete posts. Creating a post is the core operation — it's how you
cross-post, schedule, and attach media programmatically.
All endpoints require authentication and an active or trialing subscription.
Create a post
POST /api/v1/posts
Creates a post. Depending on the body, it becomes a draft (no
scheduledAt) or a scheduled post. A single call can fan out to multiple
accounts (cross-post) with per-channel overrides.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
accountIds | string[] | yes | One or more connected account IDs to post to. Min 1. |
caption | string | no | The default caption text. |
firstComment | string | no | A comment to post immediately after publish. |
postType | string | no | Post type (e.g. post, reel, story, short, thread). Defaults to post. |
mediaIds | string[] | no | Media IDs to attach (must be in your organization). |
accountOverrides | array | no | Per-channel caption/field overrides (see below). |
threadParts | Record of accountId → string[] | no | Thread renditions (postType thread). Chain platforms carry N parts; LinkedIn/Facebook carry the full text as one element. null clears. |
scheduledAt | string (ISO 8601) | no | Omit to save as a draft; include to schedule. |
accountOverrides[]
| Field | Type | Description |
|---|---|---|
accountId | string | The account this override applies to. |
captionOverride | string | null | Replace the caption for this channel. |
fields | object | Platform-specific field overrides ({ key: value }). |
Validation
Before any rows are written, the request is validated against
platform limits: caption length, post type, media
constraints (count, size, aspect ratio, duration), and ownership of both
accountIds and mediaIds.
This endpoint's 400/403 errors use the legacy flat shape
({ "error": "<message>" }), not the structured error.code shape.
Example: cross-post with overrides
curl -X POST https://<your-api-origin>/api/v1/posts \
-H "Authorization: Bearer sx_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"caption": "Our new feature ships today 🚀",
"postType": "post",
"accountIds": ["acc_instagram", "acc_x", "acc_linkedin"],
"mediaIds": ["med_01"],
"accountOverrides": [
{ "accountId": "acc_x", "captionOverride": "New feature, shipping today." },
{ "accountId": "acc_linkedin", "captionOverride": "Today we are launching..." }
],
"scheduledAt": "2026-07-15T14:30:00Z"
}'
Example: draft (no schedule)
curl -X POST https://<your-api-origin>/api/v1/posts \
-H "Authorization: Bearer sx_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"caption": "Draft caption",
"accountIds": ["acc_instagram"]
}'
Response — 201 Created
{
"data": {
"id": "pst_abc123",
"status": "scheduled"
}
}
status is "scheduled" when scheduledAt is provided, otherwise "draft".
Errors
| Status | Body shape | Meaning |
|---|---|---|
400 | { "error": "<message>" } | Invalid body, or platform-limit violation |
403 | { "error": "<message>" } | accountIds or mediaIds not in your organization |
401 | { "error": "<message>" } | Missing/invalid API key |
List posts
GET /api/v1/posts
Returns your posts, newest first. Uses standard pagination.
Query parameters
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
limit | integer | 25 | 1–100 | Page size |
offset | integer | 0 | ≥ 0 | Skip count |
status | string | — | enum | draft, scheduled, publishing, published, failed |
q | string | — | 1–200 | Case-insensitive caption search (ILIKE %q%) |
Example
curl "https://<your-api-origin>/api/v1/posts?status=scheduled&q=launch&limit=10" \
-H "Authorization: Bearer sx_live_YOUR_API_KEY"
Response — 200 OK
{
"data": [
{
"id": "pst_abc123",
"caption": "Our new feature ships today 🚀",
"postType": "post",
"status": "scheduled",
"scheduledAt": "2026-07-15T14:30:00.000Z",
"createdAt": "2026-07-12T09:00:00.000Z",
"updatedAt": "2026-07-12T09:00:00.000Z"
}
],
"limit": 10,
"offset": 0
}
Only posts in your organization are returned.
Get a post
GET /api/v1/posts/{id}
Returns full detail for one post.
Response — 200 OK
{
"data": {
"id": "pst_abc123",
"caption": "Our new feature ships today 🚀",
"firstComment": null,
"postType": "post",
"status": "scheduled",
"scheduledAt": "2026-07-15T14:30:00.000Z",
"mediaIds": ["med_01"],
"accountOverrides": [],
"createdAt": "2026-07-12T09:00:00.000Z",
"updatedAt": "2026-07-12T09:00:00.000Z"
}
}
Errors
| Status | Body |
|---|---|
404 | { "error": { "code": "not_found", ... } } |
Update a post
PATCH /api/v1/posts/{id}
Updates a post. Omitted fields are left unchanged; nullable fields can be
cleared by passing null.
Request body (all optional)
| Field | Type | Description |
|---|---|---|
caption | string | New caption |
firstComment | string | New first comment |
postType | string | New post type |
status | string | draft, scheduled, published, failed |
scheduledAt | string (ISO 8601) | null | New schedule time; null clears it |
delayMinutes | number | Delay before publish (minutes) |
accountIds | string[] | Replace destination accounts |
accountOverrides | array | Replace per-channel overrides |
mediaIds | string[] | Replace attached media (order preserved) |
poll | object | null | { "question", "options", "durationDays" } (durationDays ≥ 1); null removes |
threadParts | Record | null | Replace thread renditions; null clears |
Response — 200 OK
The full updated post inside data (same shape as
GET).
Reschedule a post
POST /api/v1/posts/{id}/reschedule
Moves a scheduled post to a new time.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
scheduledAt | string (ISO 8601) | yes | New time; a past timestamp is bumped to the next slot |
Response — 200 OK
The full updated post inside data.
Errors
| Status | Body |
|---|---|
400 | { "error": { "code": "validation_error", ... } } |
404 | { "error": { "code": "not_found", ... } } |
Retry a failed post
POST /api/v1/posts/{id}/retry
Queues a fresh publish job for a failed post.
Response — 200 OK
{
"data": {
"jobId": "job_...",
"status": "queued"
}
}
Errors
| Status | Body |
|---|---|
404 | { "error": { "code": "not_found", ... } } |
Post analytics
GET /api/v1/posts/{id}/analytics
Returns the insight row recorded for a published post (impressions, likes, comments, etc., as available per platform). See Analytics.
Errors
| Status | Body |
|---|---|
404 | { "error": "Insight not found" } |
Delete a post
DELETE /api/v1/posts/{id}
Deletes a post. Only drafts and scheduled posts can be deleted — published
posts cannot be deleted via the API (they return 400).
This endpoint's 400/404 errors use the legacy flat shape.
Example
curl -X DELETE https://<your-api-origin>/api/v1/posts/pst_abc123 \
-H "Authorization: Bearer sx_live_YOUR_API_KEY"
Response — 200 OK
{ "data": { "success": true } }
Errors
| Status | Body |
|---|---|
400 | { "error": "Cannot delete published post" } |
404 | { "error": "Post not found" } |
This deletes the post in post.buzz. It does not delete the post from the social platform itself. Whether a published post can be removed from a platform depends on that platform's capabilities — see the capability matrix.
Related
- Scheduling and recurrence — the user-facing counterparts.
- Comments — schedule the first comment separately.
- Webhooks —
post.published/post.failedevents.