Posts
Create, schedule, update, and publish social media posts across multiple platforms simultaneously.
Base URL
https://api.voxburst.io/v1/postsCreate Post
POST /v1/posts
Creates a new post. Posts can be created as drafts, scheduled for a future time, or published immediately.
Required scopes: posts:write
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | Post content. Used as the default for all platforms unless overridden (max 10,000 characters). |
accountIds | string[] | Yes | IDs of connected accounts to post from. The platform is inferred from each account. |
scheduledFor | string | No | ISO 8601 datetime for scheduled publishing |
contentType | string | No | Content type hint: TEXT, IMAGE, VIDEO, CAROUSEL, THREAD, STORY, REEL |
saveAsDraft | boolean | No | If true, saves as draft regardless of scheduledFor |
platformOverrides | object | No | Per-platform content overrides — keyed by platform constant (e.g. "TWITTER"). See Content Overrides |
platformMetadata | object | No | Per-platform metadata overrides — keyed by platform constant (e.g. "TIKTOK"). See Platform Metadata |
media | string[] | No | IDs of previously uploaded media files |
tags | string[] | No | Tags for organization. Stored as metadata.tags and overwrites any metadata.tags you send. Not published as-is to most platforms, but YouTube falls back to this value for video tags — see Reserved metadata keys |
personaId | string | No | ID of a persona profile to associate with this post |
queue | boolean | No | If true, picks the next available queue slot instead of requiring scheduledFor. Mutually exclusive with scheduledFor. |
threadPosts | object[] | No | Thread items for X/Threads posts (max 25 items). Each item: { sequence: number, content: string, mediaIds?: string[] }. Sequences must be 1-based and contiguous. |
firstComment | string | No | Text to auto-post as a comment immediately after publishing (max 2,200 characters). Silently skipped on platforms that do not support comments — no error is returned. See supported platforms below. |
firstCommentDelay | integer | No | Seconds to wait before posting the first comment (0–60, default 0). Capped at 60s. Only applies on platforms where firstComment is supported. |
isManualSave | boolean | No | When true, bypasses the post.created webhook debounce window so the webhook fires immediately |
metadata | object | No | Arbitrary key-value metadata. See Metadata Constraints. |
Metadata Constraints
The metadata field accepts an arbitrary key-value object with the following limits. Requests violating these limits receive a 422 error.
| Rule | Limit |
|---|---|
| Key length | Max 100 characters |
| String value length | Max 1,000 characters |
| Array value item count | Max 100 items |
| Array value item length | Max 200 characters each |
Reserved metadata keys
Some metadata keys are read by platform adapters at publish time and are not
treated as inert user data. Setting them changes what is published.
| Key | Read by | Effect |
|---|---|---|
title | Pinterest, Reddit, YouTube | Used as the Pin title, the Reddit post title (required for Reddit — a Reddit post with no title fails validation), and as a fallback YouTube video title |
tags | YouTube | Fallback source for YouTube video tags |
youtubeTitle | YouTube | YouTube video title. Takes precedence over title |
youtubeTags | YouTube | YouTube video tags. Takes precedence over tags |
metadata.title collides across platforms on a multi-platform post. A single
post targeting Pinterest, Reddit, and YouTube shares one metadata object, so
all three read the same title value — you cannot give them different titles
through metadata alone.
To set a per-platform title, use platformMetadata instead, which is applied
per destination:
{
"platformMetadata": {
"YOUTUBE": { "youtubeTitle": "Full walkthrough — 12 min" },
"PINTEREST": { "title": "5 quick tips" },
"REDDIT": { "title": "We rebuilt our scheduler. AMA." }
}
}Prefer the namespaced youtubeTitle / youtubeTags keys over the generic
title / tags for YouTube. The generic keys are retained only as a fallback.
The top-level tags body field overwrites metadata.tags. If a request
supplies both, the top-level tags value wins and the metadata.tags value is
discarded — silently, with no error. Since YouTube falls back to metadata.tags,
sending a top-level tags array will replace the tags YouTube publishes.
Set exactly one of the two. To control YouTube tags specifically without the
top-level field interfering, use youtubeTags.
Platform Metadata
platformMetadata accepts per-platform metadata overrides. Keys are platform constants (e.g. "TIKTOK"); values are objects whose fields are merged into the post’s metadata for that platform. This is separate from platformOverrides, which overrides content/caption.
Validation constraints
Each platform’s metadata object must satisfy the following rules. Requests that violate these constraints return 400 VALIDATION_ERROR.
| Rule | Limit |
|---|---|
| Value types | string, number, boolean, null, or an array of those primitive types only. Nested objects are not permitted. |
| Array element count | Max 50 elements per array value |
| Keys per platform object | Max 20 keys |
{
"platformMetadata": {
"TIKTOK": {
"tiktokPrivacyLevel": "PUBLIC_TO_EVERYONE"
}
}
}The following would be rejected:
{
"platformMetadata": {
"TIKTOK": {
"nested": { "key": "value" }
}
}
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "platformMetadata values must be string, number, boolean, null, or arrays of those types"
}
}Recognized keys
TIKTOK.tiktokPrivacyLevel (string, required for TikTok posts) — The TikTok privacy level for this post. TikTok’s Content Sharing Guidelines require an explicit, user-made privacy selection with nothing preselected, so this field has no default. Fetch GET /v1/accounts/:id/tiktok/creator-info first and pass one of the values in the account’s privacyLevelOptions.
- Omitting
tiktokPrivacyLevelfails the TikTok publish withTIKTOK_PRIVACY_LEVEL_REQUIRED. - Passing a value outside the account’s
privacyLevelOptionsfails withTIKTOK_PRIVACY_LEVEL_UNAVAILABLE.
Both are returned as platforms[].error.code on the post response, not a top-level 400 — TikTok fails independently of any other platforms in the same post. See TikTok publish errors.
Valid values:
| Value | Description |
|---|---|
PUBLIC_TO_EVERYONE | Visible to all TikTok users |
MUTUAL_FOLLOW_FRIENDS | Visible to mutual followers only |
SELF_ONLY | Visible only to the account owner |
FOLLOWER_OF_CREATOR | Visible to followers of the creator |
Available values depend on what the connected TikTok account’s permissions allow. Accounts in unaudited or restricted states may only be allowed SELF_ONLY.
TIKTOK.tiktokAllowComment (boolean, default false) — Allow comments on this post. Has no effect if the creator has disabled comments on their own account (creatorInfo.commentDisabled).
TIKTOK.tiktokAllowDuet (boolean, default false) — Allow duets on this post. Has no effect if the creator has disabled duets on their own account (creatorInfo.duetDisabled).
TIKTOK.tiktokAllowStitch (boolean, default false) — Allow stitches on this post. Has no effect if the creator has disabled stitches on their own account (creatorInfo.stitchDisabled).
TIKTOK.tiktokCommercialContent (boolean, default false) — Enable commercial content disclosure for this post. When true, exactly one of tiktokBrandOrganic or tiktokBrandedContent must also be true, or the publish fails with TIKTOK_DISCLOSURE_INCOMPLETE.
TIKTOK.tiktokBrandOrganic (boolean, default false) — Discloses that the post promotes the creator’s own business (“Your brand”). Requires tiktokCommercialContent: true.
TIKTOK.tiktokBrandedContent (boolean, default false) — Discloses a paid partnership (“Branded content”). Requires tiktokCommercialContent: true. Cannot be combined with tiktokPrivacyLevel: "SELF_ONLY" — fails with TIKTOK_BRANDED_CONTENT_PRIVACY.
TIKTOK.tiktokAutoAddMusic (boolean, default false) — For photo posts, let TikTok automatically add a music track.
INSTAGRAM.instagramAudioId (string) — Attach a licensed audio track to an Instagram Reel. Use the id returned by GET /v1/instagram/audio/search. Only applies when the post contains a single video — ignored for images, carousels, and Stories. Requires a Facebook Login-connected Instagram account.
INSTAGRAM.instagramAudioVolume (number, 0.0–1.0, default 1.0) — Volume of the attached audio track relative to maximum. 0.0 is silent, 1.0 is full volume.
INSTAGRAM.instagramVideoVolume (number, 0.0–1.0, default 1.0) — Volume of the original video’s audio track. Set to 0.0 to mute the original video audio entirely (music-only), or blend with instagramAudioVolume for a mix.
{
"content": "Summer vibes 🌊",
"accountIds": ["acc_instagram_example"],
"platformMetadata": {
"INSTAGRAM": {
"instagramAudioId": "1234567890",
"instagramAudioVolume": 0.8,
"instagramVideoVolume": 0.3
}
}
}{
"content": "New video!",
"accountIds": ["acc_tiktok_example"],
"platformMetadata": {
"TIKTOK": {
"tiktokPrivacyLevel": "FOLLOWER_OF_CREATOR"
}
}
}First comment — platform support
firstComment is accepted on all post creation requests but is only posted on platforms that expose a comment API. On unsupported platforms it is silently skipped — the post publishes normally and no error is returned.
| Platform | First comment supported |
|---|---|
| ✅ | |
| ✅ | |
| ✗ † | |
| Threads | ✅ |
| TikTok | ✅ |
| YouTube | ✅ |
| ✅ | |
| Twitter / X | ✗ |
| Bluesky | ✗ |
| ✗ | |
| Snapchat | ✗ |
| Telegram | ✗ |
| Google Business | ✗ |
| Mastodon | ✗ |
† Facebook first comment — pending Meta API approval. The
pages_manage_engagementpermission required for Facebook first comments is currently under review by Meta. Posts that includefirstCommentwill publish normally — the comment is silently skipped on Facebook until the permission is approved and re-enabled.
Example Request
curl -X POST https://api.voxburst.io/v1/posts \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"content": "Hello from VoxBurst!",
"accountIds": ["acc_123", "acc_456"],
"scheduledFor": "2026-04-20T14:00:00Z"
}'Response
{
"id": "post_abc123",
"content": "Hello from VoxBurst! 🚀",
"status": "scheduled",
"scheduledFor": "2026-03-01T14:00:00Z",
"createdAt": "2026-02-20T10:00:00Z",
"updatedAt": "2026-02-20T10:00:00Z",
"platforms": [
{
"postPlatformId": "pp_111",
"platform": "twitter",
"accountId": "acc_123",
"accountName": "My Twitter",
"status": "pending",
"platformPostId": null,
"platformPostUrl": null,
"publishedAt": null,
"publishWarning": null,
"error": null,
"attempts": []
},
{
"postPlatformId": "pp_222",
"platform": "linkedin",
"accountId": "acc_456",
"accountName": "My LinkedIn",
"status": "pending",
"platformPostId": null,
"platformPostUrl": null,
"publishedAt": null,
"publishWarning": null,
"error": null,
"attempts": []
}
]
}The word “platforms” appears in three distinct contexts in this API — they are not interchangeable:
- Targeting accounts (request) — use
accountIdsto specify which connected accounts to post from. The platform is inferred from each account. There is noplatformsfield on post creation or update. - Publish state (response) — the
platformsarray in every post response tracks per-destination publish status, errors, and URLs. This is read-only. - Content overrides (request) — the
platformOverridesobject lets you customize content per platform constant (e.g."TWITTER"). See Content Overrides below.
The platforms array in the response tracks per-platform publish state. After publishing, each entry’s status will be published (with a platformPostUrl) or failed (with an error message). The postPlatformId is used with the Fix Platform endpoint to resubmit a specific failed platform. A non-null publishWarning indicates a non-fatal condition that occurred during publishing — see PostPlatform fields below.
Full Post Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Post ID |
content | string | Post content |
contentType | string | null | TEXT, IMAGE, VIDEO, CAROUSEL, STORY, REEL, or THREAD |
status | string | See Post Status |
scheduledFor | string | null | ISO 8601 publish time |
publishedAt | string | null | ISO 8601 timestamp when publishing completed |
platformRemovedAt | string | null | ISO 8601 timestamp when the post was deleted from the platform |
firstComment | string | null | Content of a comment auto-posted after publishing |
firstCommentDelay | number | null | Seconds to wait before posting the first comment |
queuePosition | number | null | Position in the publishing queue, if queued |
tags | string[] | Tags for organization, mirrored from metadata.tags. Used as a fallback source for YouTube video tags — see Reserved metadata keys |
metadata | object | null | Arbitrary key-value metadata — see Metadata Constraints |
media | object[] | Attached media files with full metadata — see Post media fields |
platforms | object[] | Per-platform publish state — see PostPlatform fields |
threadPosts | object[] | Thread items for X/Threads posts |
recurringPostId | string | null | ID of the recurring rule that generated this post |
isRecurring | boolean | null | true if this post is the source of a recurring rule |
personaId | string | null | Persona associated with this post |
createdAt | string | ISO 8601 creation timestamp |
updatedAt | string | ISO 8601 last-updated timestamp |
Post media fields
Each entry in the media array describes one attached file.
| Field | Type | Description |
|---|---|---|
id | string | Media record ID |
filename | string | Original file name |
contentType | string | MIME type |
sizeBytes | integer | File size in bytes |
status | string | Lowercased media status: pending, processing, ready, or failed |
url | string | Public URL of the file |
variants | object | null | Generated size/format variants, when present |
dimensions | object | undefined | { width, height }. Omitted when dimensions are unknown |
durationMs | integer | null | Duration in milliseconds for video and audio. null for images |
thumbnailUrl | string | null | Poster frame extracted from a video. null for images and for videos with no thumbnail yet — see Video thumbnails |
position | integer | Ordering of this item within the post’s media |
createdAt | string (ISO 8601) | When the media record was created |
thumbnailUrl is generated asynchronously after upload and is best-effort.
Always treat it as nullable and provide a fallback rather than assuming a
thumbnail is available.
PostPlatform fields
Each entry in the platforms array represents one publish destination. Fields marked (success only) are absent when status is not published.
| Field | Type | Description |
|---|---|---|
postPlatformId | string | ID of this PostPlatform record — used with Fix Platform |
platform | string | Platform constant (lowercase, e.g. "twitter") |
accountId | string | Connected account ID |
accountName | string | Display name of the connected account |
accountAvatarUrl | string | undefined | Profile picture URL of the connected social account. Omitted from the response entirely when the account has no stored avatar — check for presence, not for null |
accountStatus | string | Current connection state of the underlying social account, lowercased: active, expired, disconnected, suspended, or error. See Account status on historical posts |
status | string | pending, publishing, published, failed, or skipped |
platformPostId | string | null | Platform’s native post ID (success only). Facebook photo and video posts: returns the feed-level post ID (the composite pageId_postId identifier), not the media container ID returned by the upload step. This is the same ID included in post.published webhook payloads for Facebook. |
platformPostUrl | string | null | Public URL of the post (success only) |
publishedAt | string | null | ISO 8601 timestamp when this platform succeeded (success only) |
publishWarning | string | null | Non-fatal warning set during publishing. null when no warning occurred. See values below. |
error | string | null | Error message when status is failed |
attempts | object[] | History of publish attempts |
publishWarning values
| Value | Description |
|---|---|
TIKTOK_SELF_ONLY_FALLBACK | The requested TikTok privacy level was rejected by the API (typically because the application is in an unaudited state). The post was automatically retried with SELF_ONLY visibility and published successfully. |
TikTok publish errors
These appear as platforms[].error.code for the TikTok entry when status is failed. They do not affect other platforms in the same post.
| Code | Meaning | Fix |
|---|---|---|
TIKTOK_PRIVACY_LEVEL_REQUIRED | platformMetadata.TIKTOK.tiktokPrivacyLevel was not provided | Fetch creator info and pass one of privacyLevelOptions |
TIKTOK_PRIVACY_LEVEL_UNAVAILABLE | The requested tiktokPrivacyLevel is not in this account’s privacyLevelOptions | Use one of the values from creator info |
TIKTOK_CREATOR_CANNOT_POST | TikTok returned no privacy level options for this creator — the account cannot currently publish | Check the account’s status in the TikTok app and retry later |
TIKTOK_DISCLOSURE_INCOMPLETE | tiktokCommercialContent is true but neither tiktokBrandOrganic nor tiktokBrandedContent was set | Set one of the two, or turn off tiktokCommercialContent |
TIKTOK_BRANDED_CONTENT_PRIVACY | tiktokBrandedContent was combined with tiktokPrivacyLevel: "SELF_ONLY" | Use a different privacy level, or turn off tiktokBrandedContent |
Account status on historical posts
Disconnecting a social account does not remove the platform rows on posts it has
already published, so a published post can reference an account VoxBurst can no
longer authenticate as. accountStatus reports that state:
| Value | Meaning |
|---|---|
active | Account is connected and authenticated |
expired | Stored credentials have expired — the account needs reconnecting |
disconnected | Account was disconnected; its stored credentials were removed |
suspended | Account is suspended |
error | Account is in an error state |
Check accountStatus before calling Unpublish or a platform
delete. Any value other than active means the platform-side operation cannot
succeed and will return a failure reason — see
Unpublish failure reasons.
Content Overrides
Use platformOverrides to customize content per platform constant. This is separate from accountIds (which targets accounts) and from the platforms array in responses (which tracks publish state):
platformOverrides schema
platformOverrides is a map keyed by platform constant (e.g. "TWITTER"). Each value supports:
| Field | Type | Required | Description |
|---|---|---|---|
content | string | No | Override caption/text for this platform only (max 10,000 characters) |
{
"content": "Announcing our new feature!",
"accountIds": ["acc_123", "acc_456"],
"platformOverrides": {
"TWITTER": {
"content": "New feature alert! 🎉 #voxburst"
},
"LINKEDIN": {
"content": "We're excited to announce our latest feature that helps teams schedule social media content more efficiently. Read more on our blog."
}
}
}platformOverrides only overrides content — it does not override media, contentType, or other fields per platform. To post different media per platform, create separate posts targeting each platform’s account.
threadPosts schema
Used with contentType: "THREAD" for X (Twitter) only. Threads (Meta) does not use this field — individual Threads posts do not support reply-chain threading through the API. Each item represents one post in the thread.
| Field | Type | Required | Description |
|---|---|---|---|
sequence | integer | Yes | 1-based position in the thread. Must be contiguous starting from 1. |
content | string | Yes | Text of this thread item (max 280 characters for X) |
mediaIds | string[] | No | Media to attach to this thread item (max 4 items) |
Constraints:
- Max 25 thread items per post
- Sequences must start at 1 and be contiguous (1, 2, 3 … — gaps are rejected)
- When
contentType: "THREAD", each item counts as 1 post against your plan quota
{
"content": "Thread opener — first tweet",
"accountIds": ["acc_twitter_abc"],
"contentType": "THREAD",
"threadPosts": [
{ "sequence": 1, "content": "1/ This is the opening tweet of the thread." },
{ "sequence": 2, "content": "2/ The second tweet in the thread.", "mediaIds": ["media_abc123"] },
{ "sequence": 3, "content": "3/ Closing thoughts. Follow for more." }
]
}Get Post
GET /v1/posts/:id
Retrieve a single post by ID.
curl https://api.voxburst.io/v1/posts/post_abc123 \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"List Posts
GET /v1/posts
List all posts with optional filtering. Uses cursor-based pagination.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: draft, scheduled, publishing, published, failed, partial, cancelled, unpublished, archived, all |
platform | string | Filter by platform |
from | string | Start date (ISO 8601) |
to | string | End date (ISO 8601) |
limit | number | Results per page (default: 20, max: 100) |
cursor | string | Pagination cursor from previous response |
curl "https://api.voxburst.io/v1/posts?status=scheduled&limit=50" \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response
{
"data": [...],
"pagination": {
"next_cursor": "eyJpZCI6InBvc3RfYWJjMTIzIn0",
"has_more": true,
"limit": 50
}
}Update Post
PATCH /v1/posts/:id
Update a post. Posts in draft, scheduled, approved, failed, or partial status can be updated.
Required scopes: posts:write
Request Body
All fields are optional. Only include the fields you want to change.
| Field | Type | Description |
|---|---|---|
content | string | New post content (max 63,206 characters) |
contentType | string | Content type: TEXT, IMAGE, VIDEO, CAROUSEL, THREAD, STORY, REEL |
scheduledFor | string | New scheduled time (ISO 8601) |
clearSchedule | boolean | If true, removes the scheduled time and reverts the post to draft |
saveAsDraft | boolean | If true, saves as draft regardless of scheduledFor |
accountIds | string[] | Replace the set of target accounts |
media | string[] | Replace attached media |
platformOverrides | object | Per-platform content overrides |
platformMetadata | object | Per-platform metadata overrides — keyed by platform constant (e.g. "TIKTOK"). See Platform Metadata |
tags | string[] | Replace post tags. Overwrites metadata.tags — see Reserved metadata keys |
personaId | string | Replace the associated persona |
threadPosts | object[] | Replace thread items (X/Threads only). Same schema as Create Post. |
firstComment | string | Replace the first comment text (max 2,200 characters) |
firstCommentDelay | integer | Seconds before the first comment is posted (0–60). Capped at 60s. Only applies on platforms that support firstComment. |
platformRemovedAt | string | null | ISO 8601 timestamp when the post was removed from the platform, or null to clear |
metadata | object | Replace post metadata key-value pairs |
version | string | Optimistic concurrency token — the post’s updatedAt ISO string from when you loaded the post. If the post has been modified since, the request returns 409 Conflict. Omit to skip the check. |
curl -X PATCH https://api.voxburst.io/v1/posts/post_abc123 \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"content": "Updated content!",
"scheduledFor": "2026-03-02T14:00:00Z",
"version": "2026-02-20T10:00:00.000Z"
}'Published posts cannot be modified. To change published content, delete the original post and create a new one.
Delete Post
DELETE /v1/posts/:id
Delete a post. Posts in publishing or published status cannot be deleted.
Required scopes: posts:write
curl -X DELETE https://api.voxburst.io/v1/posts/post_abc123 \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response (200):
{ "success": true }Deleting a post in a non-deletable status (e.g. publishing) returns 409 Conflict. Deleting a post removes it from VoxBurst but does not delete it from social platforms if already published. You must delete published posts manually on each platform.
Publish Now
POST /v1/posts/:id/publish
Immediately publish a draft or scheduled post.
Required scopes: posts:write
Query Parameters
| Parameter | Type | Description |
|---|---|---|
sync | boolean | If true, waits for publishing to complete before responding (up to timeout seconds) |
timeout | integer | Max seconds to wait when sync=true (default: 30, max: 120) |
Request Headers
| Header | Description |
|---|---|
X-Callback-Url | Optional HTTPS URL to POST a completion callback to when publishing finishes |
curl -X POST "https://api.voxburst.io/v1/posts/post_abc123/publish?sync=true&timeout=60" \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "X-Callback-Url: https://your-webhook-url.com/hooks/publish-done"Retry Failed Post
POST /v1/posts/:id/retry
Retries all failed platform targets on a failed or partial post. Successfully published platforms are never re-posted — only platforms with a FAILED status are re-queued. Retries are subject to exponential backoff and a per-platform maximum of 3 attempts.
Required scopes: posts:write
This endpoint is idempotent when called with an Idempotency-Key header. Provide a unique key per retry attempt to avoid duplicate submissions.
Backoff Schedule
Each platform tracks its own retryCount. The delay before the next attempt doubles with each failure:
| Retry attempt | Delay |
|---|---|
| 1st retry | 2 minutes |
| 2nd retry | 4 minutes |
| 3rd retry | 8 minutes |
| After 3rd | Platform exhausted — use Fix Platform to reset |
Example Request
curl -X POST https://api.voxburst.io/v1/posts/post_abc123/retry \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "Idempotency-Key: retry-post_abc123-attempt-1"Response
{
"id": "post_abc123",
"status": "publishing",
"retriedPlatforms": [
{
"platform": "instagram",
"accountId": "acc_789",
"retryCount": 1,
"nextRetryAt": "2026-04-02T14:02:00Z"
}
],
"skippedPlatforms": [
{
"platform": "facebook",
"accountId": "acc_456",
"retryCount": 3,
"reason": "max_retries_exceeded"
}
]
}skippedPlatforms lists any failed platforms that have already hit the 3-retry limit. Use the Fix Platform endpoint to reset these manually.
Fix Platform
POST /v1/posts/:id/platforms/:platformId/fix
Fixes and re-queues a single platform on a partial or failed post. Eligible platform statuses are failed, publishing, and pending. Unlike /retry, this endpoint resets the platform’s retry counter to zero and optionally lets you supply a replacement image URL or content — useful when the original failure was caused by an invalid or rejected image.
Required scopes: posts:write
Use this endpoint when a platform has exhausted its automatic retries (retryCount = 3) or when you need to correct the media or caption before resubmitting.
Path Parameters
| Parameter | Description |
|---|---|
id | Post ID |
platformId | The id of the specific PostPlatform entry to fix. Found in the post’s platforms array. |
Request Body
All fields are optional. Omitting the body re-queues the platform with its original content.
| Field | Type | Required | Description |
|---|---|---|---|
mediaUrl | string | No | Replacement image URL (https:// only). Use when the original image was rejected by the platform (e.g., wrong aspect ratio, size exceeded). |
content | string | No | Replacement caption or post text for this platform only. |
refreshMedia | boolean | No | If true, re-fetches and re-uploads the existing media from storage before resubmitting. Useful when the original upload expired or was rejected. |
Example — Re-queue with corrected image
curl -X POST https://api.voxburst.io/v1/posts/post_abc123/platforms/pp_xyz789/fix \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"mediaUrl": "https://cdn.example.com/corrected-image-1080x1080.jpg"
}'Example — Re-queue with no changes
curl -X POST https://api.voxburst.io/v1/posts/post_abc123/platforms/pp_xyz789/fix \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response
{
"success": true,
"platformId": "pp_xyz789",
"status": "publishing"
}After a successful response, the parent post status returns to publishing. The platform is re-queued immediately without backoff delay (retryCount is reset to 0).
Handling Partial Failures
A post reaches PARTIAL status when at least one platform publishes successfully and at least one fails. Platforms that succeeded are not affected by retry or fix operations — only FAILED platforms are re-queued.
Typical partial failure workflow
- Your webhook receives a
post.publishedevent withstatus: "PARTIAL". - Inspect the
platformsarray on the post — each entry has its ownstatus,error, andretryCount. - If the failure was transient (network error, rate limit), call
POST /v1/posts/:id/retryto automatically re-queue all failed platforms with backoff. - If the failure was caused by invalid content (e.g., Instagram rejected the image), call
POST /v1/posts/:id/platforms/:platformId/fixwith a correctedmediaUrlorcontent. - If a platform has
retryCount: 3, automatic retries are exhausted —/retrywill skip it. You must use/fixto reset the counter and resubmit.
Platform status values
| Status | Description |
|---|---|
pending | Waiting to be sent |
publishing | Currently being submitted to the platform |
published | Successfully posted |
failed | Publish attempt failed — eligible for retry or fix |
skipped | Excluded from this run (e.g. platform not applicable, or media validation failed for this platform) |
If all platforms fail, the post status is FAILED (not PARTIAL). Both statuses are eligible for /retry and /fix.
Post Status
All status values are returned as lowercase strings.
| Status | Description |
|---|---|
draft | Created but not scheduled or published |
approved | Approved through the approval workflow; queued for publishing |
scheduled | Queued for future publishing |
publishing | Currently being sent to platforms |
published | Successfully published to all platforms |
failed | Publishing failed on all platforms |
partial | Published to some platforms; at least one failed — use /retry or /fix to remediate |
cancelled | Post was cancelled before publishing |
unpublished | Post was unpublished after a successful publish |
archived | Post has been archived and is hidden from default views |
State transition table
The table below shows which statuses permit each operation. “Yes” means the operation is available; ”—” means it is blocked.
| Status | Edit (PATCH) | Publish now | Cancel | Retry | Fix | Clone | Delete |
|---|---|---|---|---|---|---|---|
draft | Yes | Yes | Yes | — | — | Yes | Yes |
approved | Yes | Yes | Yes | — | — | Yes | Yes |
scheduled | Yes | Yes | Yes | — | — | Yes | Yes |
publishing | — | — | — | — | — | Yes | — |
published | — | — | — | — | — | Yes | — |
partial | Yes | — | — | Yes | Yes | Yes | Yes |
failed | Yes | — | — | Yes | Yes | Yes | Yes |
cancelled | Yes | Yes | — | — | — | Yes | Yes |
unpublished | — | — | — | — | — | Yes | — |
archived | — | — | — | — | — | Yes | — |
Terminal statuses (no further automatic transitions): published, cancelled, unpublished, archived.
User-triggered transitions:
draft→scheduled: SetscheduledForin a PATCH or at creation timedraft/scheduled→publishing: CallPOST /v1/posts/:id/publishdraft/scheduled→cancelled: CallPOST /v1/posts/:id/cancelpublished/partial→unpublished: CallPOST /v1/posts/:id/unpublishfailed/partial→publishing: CallPOST /v1/posts/:id/retryorPOST /v1/posts/:id/platforms/:id/fix
System-triggered transitions:
scheduled→publishing: Scheduler cron fires whenscheduledForis reachedapproved→publishing: Approval workflow completespublishing→published: All platform workers complete successfullypublishing→partial: At least one platform fails, at least one succeedspublishing→failed: All platforms fail
Scheduling Semantics
All scheduled times are specified using the scheduledFor field on POST /v1/posts or PATCH /v1/posts/:id.
Timestamp format
scheduledFor must be a valid ISO 8601 datetime string. Always use UTC to avoid ambiguity around daylight saving transitions:
2026-06-15T14:00:00Z ✅ UTC (recommended)
2026-06-15T10:00:00-04:00 ✅ Offset included
2026-06-15T14:00:00 ❌ No timezone — rejectedMinimum lead time
The scheduled time must be in the future. The API allows a 60-second grace window to account for clock skew between your system and VoxBurst’s servers. Requests where scheduledFor is more than 60 seconds in the past return 400 VALIDATION_ERROR.
Exception — saveAsDraft: true: When saveAsDraft: true is set, the future-date validation is bypassed entirely. You may supply any scheduledFor value, including past timestamps. This is intended for import workflows where historical posts need to preserve their original date for calendar positioning. The post is saved as a draft regardless of the scheduledFor value — it is not automatically scheduled for publishing.
Maximum scheduling horizon
There is no maximum scheduling horizon. You can schedule posts years in advance.
Rescheduling
To reschedule a post, PATCH /v1/posts/:id with a new scheduledFor. The post must be in draft, scheduled, approved, failed, or partial status. Set clearSchedule: true to remove the scheduled time and revert the post to draft.
Queue mode
Set queue: true (instead of scheduledFor) to automatically assign the next available slot in your workspace’s posting queue. These are mutually exclusive — you cannot set both.
DST guidance
Use UTC timestamps for reliability. If you need to schedule at a user-local time, convert to UTC in your application before calling the API. VoxBurst stores and compares all times in UTC.
Validate Post
POST /v1/posts/validate
Validate content against platform rules without creating a post. Returns per-platform errors and warnings.
This endpoint takes platforms (not accountIds). Pass an array of platform constants such as ["TWITTER", "INSTAGRAM"]. It does not accept account IDs — it validates content rules for the named platforms directly, with no account lookup.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | Post content to validate |
platforms | string[] | Yes | 1–15 platform constants to validate against (e.g. ["TWITTER", "INSTAGRAM"]). Must be valid Platform enum values. See platform constants. |
mediaIds | string[] | No | Media IDs to include in validation (checks dimensions, size, format) |
media | object[] | No | Inline media metadata for pre-upload checks. Each item: { type: "image"|"video"|"gif", url?: string, sizeBytes?: number, durationMs?: number } |
firstComment | string | No | Optional first-comment content to validate alongside the post (max 10,000 characters) |
curl -X POST https://api.voxburst.io/v1/posts/validate \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"content": "Test post content",
"platforms": ["TWITTER", "LINKEDIN"]
}'Response
{
"valid": true,
"platforms": {
"TWITTER": {
"valid": true,
"errors": [],
"warnings": [
{ "code": "NO_HASHTAGS", "message": "Posts with hashtags typically get more reach on Twitter" }
]
},
"LINKEDIN": {
"valid": true,
"errors": [],
"warnings": []
}
}
}Bulk Generate Check
GET /v1/posts/bulk-generate-check
Check for scheduling conflicts before bulk-generating posts. Returns a warning and a count of already-scheduled posts in the requested date range.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes | Account ID to check for conflicts |
startDate | string | Yes | Start of the range (ISO 8601) |
endDate | string | Yes | End of the range (ISO 8601) |
curl "https://api.voxburst.io/v1/posts/bulk-generate-check?accountId=acc_123&startDate=2026-04-01T00:00:00Z&endDate=2026-04-30T23:59:59Z" \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response
{
"warning": "duplicate_detected",
"warningMessage": "A similar bulk generation was run recently for this account and platform. You may be creating duplicate posts.",
"overlappingScheduledCount": 12
}When no conflict is found, warning is null, warningMessage is omitted, and overlappingScheduledCount is 0:
{
"warning": null,
"overlappingScheduledCount": 0
}Pre-flight Check
GET /v1/posts/preflight
Run distribution intelligence pre-flight checks for a set of accounts before creating a post. Returns risk tier and scheduling guidance per platform.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
platforms | string | Comma-separated platform constants to check (e.g. TWITTER,INSTAGRAM) |
text | string | Optional post text to include in the check |
curl "https://api.voxburst.io/v1/posts/preflight?platforms=TWITTER,INSTAGRAM" \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response
{
"platformResults": [
{
"platform": "INSTAGRAM",
"tier": "GREEN",
"tierLabel": "Optimal",
"guidance": [],
"isVerified": true
}
]
}Bulk Create Posts
POST /v1/posts/bulk
Create up to 50 posts in a single request. Each post in the posts array is processed independently. Add "dryRun": true to validate without creating any posts.
Required scopes: posts:write
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
posts | array | Yes | 1–50 post objects. Each item accepts the same fields as POST /v1/posts (see Create Post for the full field list). |
posts[].content | string | Yes | Post text (max 10,000 chars) |
posts[].accountIds | string[] | Yes | Target account IDs (max 10) |
posts[].scheduledFor | string | No | ISO 8601 publish time |
posts[].saveAsDraft | boolean | No | Save as draft regardless of scheduledFor |
posts[].contentType | string | No | TEXT, IMAGE, VIDEO, CAROUSEL, THREAD, STORY, or REEL |
posts[].media | string[] | No | Media IDs (max 10) |
posts[].platformOverrides | object | No | Per-platform { content } overrides |
posts[].platformMetadata | object | No | Per-platform metadata overrides (e.g. TIKTOK.tiktokPrivacyLevel) |
posts[].firstComment | string | No | First comment text (max 2,200 chars). Silently skipped on unsupported platforms. |
posts[].firstCommentDelay | integer | No | Seconds to wait before the first comment (0–60) |
posts[].threadPosts | object[] | No | Thread items (X only). Max 25. |
posts[].tags | string[] | No | Internal tags (max 20) |
posts[].metadata | object | No | Arbitrary key-value metadata |
dryRun | boolean | No | If true, validates all posts but creates nothing. Returns status: "valid" or status: "failed" per item (HTTP 200). |
Idempotency: POST /v1/posts/bulk accepts the Idempotency-Key header. Provide a unique key per bulk request to prevent duplicate batch submissions on retries. On a replay, the entire original 207 response is returned.
curl -X POST https://api.voxburst.io/v1/posts/bulk \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"posts": [
{ "content": "Post one", "accountIds": ["acc_123"] },
{ "content": "Post two", "accountIds": ["acc_456"], "scheduledFor": "2026-04-20T10:00:00Z" }
]
}'Response (207)
{
"dry_run": false,
"total": 2,
"created": 2,
"failed": 0,
"results": [
{ "index": 0, "status": "created", "postId": "post_abc1" },
{ "index": 1, "status": "created", "postId": "post_abc2" }
]
}Dry runs return HTTP 200 instead of 207. Each results item has status: "valid" or status: "failed" with an errors array when invalid.
Bulk semantics
| Property | Value |
|---|---|
| Atomicity | Non-atomic — each post is created independently. A failure on item 3 does not roll back items 0–2. |
| Success response | HTTP 207 Multi-Status |
| Per-item result | { "index": N, "status": "created" | "failed", "postId"?: string, "errors"?: object[] } |
| Partial success | Possible — check every results[].status individually |
| Max posts per request | 50 |
| Dry run | Set "dryRun": true — validates all items, creates nothing, returns HTTP 200 |
| Quota | Each successfully created post counts against your plan’s post limit |
When a post in the batch fails, its results entry contains "status": "failed" and an errors array describing the validation or creation error. Successfully created posts are not affected.
Bulk Video Posts
POST /v1/posts/bulk-video
Create up to 20 posts in a single request, each tied to a pre-uploaded validated video. Use this after bulk video upload (see Bulk Upload in the Media docs) and validation.
Required scopes: posts:write
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
posts | array | Yes | 1–20 video post descriptors |
posts[].mediaId | string | Yes | ID of a READY media record for the video |
posts[].accountIds | string[] | Yes | Accounts to post this video from |
posts[].scheduledFor | string | Yes | ISO 8601 scheduled time for this post |
posts[].content | string | No | Caption / post text |
posts[].tags | string[] | No | Internal tags |
curl -X POST https://api.voxburst.io/v1/posts/bulk-video \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"posts": [
{
"mediaId": "media_abc123",
"accountIds": ["acc_123"],
"scheduledFor": "2026-04-20T10:00:00Z",
"content": "Watch our latest reel!"
},
{
"mediaId": "media_def456",
"accountIds": ["acc_123", "acc_456"],
"scheduledFor": "2026-04-20T12:00:00Z",
"content": "Behind the scenes!"
}
]
}'Response (207)
{
"created": [
{
"id": "post_xyz1",
"content": "Watch our latest reel!",
"status": "scheduled",
"scheduledFor": "2026-04-20T10:00:00Z",
"platforms": [ "..." ]
}
],
"warnings": []
}The response uses HTTP 207 (Multi-Status). Each item in created is a full post object (same shape as POST /v1/posts). Check the warnings array for any videos that could not be posted (e.g. media not in READY state) — these are excluded from created.
Recurring Posts
Recurring rules allow a published or scheduled post to be automatically re-published on a repeating schedule defined by an iCal RRULE string.
Plan limits
| Plan | Active recurring rules |
|---|---|
| Free | 0 |
| Starter | 3 |
| Pro / Agency | Unlimited |
Create Recurrence Rule
POST /v1/posts/:id/recurrence
Attach a recurrence rule to a PUBLISHED or SCHEDULED post. Each re-run clones the post and publishes it fresh.
Required scopes: posts:write
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
recurrenceRule | string | Yes | iCal RRULE string (e.g. RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR) |
timezone | string | Yes | IANA timezone identifier (e.g. America/New_York) |
maxOccurrences | integer | No | Stop after this many runs. Omit for indefinite. |
startAt | string | No | ISO 8601 datetime — first run will not occur before this time. Defaults to now. |
curl -X POST https://api.voxburst.io/v1/posts/post_abc123/recurrence \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"recurrenceRule": "RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR",
"timezone": "America/New_York",
"maxOccurrences": 24
}'Response (201)
Returns the full recurrence rule record including the computed nextRunAt.
Get Recurrence Rule
GET /v1/posts/:id/recurrence
curl https://api.voxburst.io/v1/posts/post_abc123/recurrence \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Update Recurrence Rule
PATCH /v1/posts/:id/recurrence
Update or pause/resume an existing recurrence rule.
Required scopes: posts:write
| Field | Type | Description |
|---|---|---|
recurrenceRule | string | New RRULE string |
timezone | string | New IANA timezone |
maxOccurrences | integer | null | New limit, or null to remove |
enabled | boolean | false to pause; true to resume |
Delete Recurrence Rule
DELETE /v1/posts/:id/recurrence
Soft-disables the recurrence rule. The source post and all previously created clone posts are preserved.
Required scopes: posts:write
Response: 204 No Content
Cancel Post
POST /v1/posts/:id/cancel
Cancel a scheduled post. Only posts in draft or scheduled status can be cancelled. Cancelled posts are not deleted and remain visible in the post list with status: "cancelled".
Required scopes: posts:write
curl -X POST https://api.voxburst.io/v1/posts/post_abc123/cancel \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Unpublish Post
POST /v1/posts/:id/unpublish
Attempts to delete the published post from each connected social platform, then marks the post as unpublished in VoxBurst. Only published or partial posts can be unpublished.
Required scopes: posts:write
Platforms that support post deletion will have the post removed. Platforms that do not support deletion are returned in unsupported_platforms — you must remove posts on those platforms manually.
curl -X POST https://api.voxburst.io/v1/posts/post_abc123/unpublish \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response
{
"results": {
"INSTAGRAM": { "success": true },
"TWITTER": { "success": false, "reason": "platform_not_supported" }
},
"unsupported_platforms": ["TWITTER"],
"note": "Posts on unsupported platforms must be deleted manually."
}| Field | Type | Description |
|---|---|---|
results | object | Per-platform outcome map. Keys are platform constants (UPPERCASE). |
results[platform].success | boolean | Whether the post was successfully deleted from this platform |
results[platform].reason | string | Reason for failure, when success is false. See Unpublish failure reasons. |
unsupported_platforms | string[] | Platforms where deletion is not supported. Posts on these platforms must be removed manually. |
note | string | undefined | Human-readable explanation when unsupported_platforms is non-empty. |
Unpublish failure reasons
results[platform].reason is a stable, machine-readable string. Branch on these
values rather than on the human-readable text:
| Reason | Meaning | What to do |
|---|---|---|
platform_not_supported | The platform has no delete capability in VoxBurst | Delete the post manually on the platform |
account_disconnected | The account was disconnected; its stored credentials were removed, so the delete can never succeed | Reconnect the account, then retry, or delete manually |
account_not_authenticated | The account is in a non-active state (expired, suspended, or error) | Reconnect or repair the account, then retry |
token_expired | Credentials for an otherwise-active account could not be resolved or have expired | Reconnect the account, then retry |
token_lookup_failed | Credential retrieval failed for an infrastructure reason rather than an expiry | Transient — retry later. If it persists, contact support |
account_disconnected and account_not_authenticated are determined before
any platform call is attempted, using the account’s accountStatus. You can
predict them client-side by reading accountStatus on the post’s platforms[]
entry — see Account status on historical posts.
token_expired and token_lookup_failed describe different situations that
need different responses. token_expired requires user action (reconnect);
token_lookup_failed is a transient backend condition and reconnecting will not
help. Do not collapse them into a single “reauthenticate” path.
The VoxBurst post is marked unpublished regardless of per-platform deletion outcomes. Check results and unsupported_platforms to determine whether manual cleanup is needed on any platform.
Get Post Replies
GET /v1/posts/:id/replies
Fetches replies for a published Threads post.
Required scopes: posts:read
Threads only. Returns { "data": [] } for posts not published on Threads. For posts published on Threads, replies are fetched using the connected Threads account’s access token.
If the connected Threads account does not have the threads_read_replies permission (granted at OAuth connection time), the response is always { "data": [] } — no error is returned. To grant this permission, reconnect the Threads account via OAuth.
Returns at most 25 replies per call.
curl https://api.voxburst.io/v1/posts/post_abc123/replies \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response
{
"data": [
{
"id": "string",
"text": "string",
"username": "string",
"timestamp": "2026-06-15T14:05:00Z",
"permalink": "https://www.threads.net/@username/post/ABC123"
}
]
}| Field | Type | Description |
|---|---|---|
data | array | List of reply objects. Empty when no replies exist, the post was not published on Threads, or threads_read_replies permission is not granted. |
data[].id | string | Platform-native reply ID |
data[].text | string | Reply text content |
data[].username | string | Username of the reply author |
data[].timestamp | string | ISO 8601 timestamp of the reply |
data[].permalink | string | Public URL of the reply on Threads |
Clone Post
POST /v1/posts/:id/clone
Create a copy of an existing post as a new draft. The clone inherits the original’s content, media, platform targets, and overrides, but is saved as draft with no scheduled time and no platform publish records.
Required scopes: posts:write
curl -X POST https://api.voxburst.io/v1/posts/post_abc123/clone \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response (201)
Returns the full post object of the newly created draft.
Duplicate Post
POST /v1/posts/:id/duplicate
Alias for Clone — creates a copy of a post as a new draft. Behaves identically to /clone.
Required scopes: posts:write
curl -X POST https://api.voxburst.io/v1/posts/post_abc123/duplicate \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"CSV Import
Import posts in bulk from a CSV file. The import is asynchronous — you upload the file, receive a jobId, then poll for completion.
Download Template
GET /v1/posts/import/template
Returns a CSV file with the correct column headers and example rows.
curl https://api.voxburst.io/v1/posts/import/template \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-o voxburst-import-template.csvUpload CSV
POST /v1/posts/import
Required scopes: posts:write
Upload a CSV file to create posts in bulk. Send the file as multipart/form-data with the file in the file field. Add ?dry_run=true to validate without creating any posts.
# Dry run (validate only)
curl -X POST "https://api.voxburst.io/v1/posts/import?dry_run=true" \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-F "file=@posts.csv;type=text/csv"
# Real import
curl -X POST https://api.voxburst.io/v1/posts/import \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx" \
-F "file=@posts.csv;type=text/csv"Response (202)
{
"jobId": "job_import_abc123",
"status": "queued"
}Check Import Status
GET /v1/posts/import/:jobId/status
Poll this endpoint every 2–5 seconds until status is complete or failed.
curl https://api.voxburst.io/v1/posts/import/job_import_abc123/status \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"{
"jobId": "job_import_abc123",
"status": "done",
"totalRows": 44,
"processedRows": 44,
"successCount": 42,
"failureCount": 2,
"errors": [
{ "row": 12, "message": "Invalid scheduledFor date format" }
],
"createdPostIds": ["post_abc1", "post_abc2"]
}status | Meaning |
|---|---|
queued | Queued, not yet started |
processing | Import in progress |
done | Finished — check successCount and errors |
failed | Import job itself failed (e.g. invalid CSV structure) |
Use dry_run=true to validate your CSV structure and catch row-level errors before committing the import.
Post Events
List Post Events
GET /v1/posts/:id/events
List all lifecycle events for a post in chronological order.
curl https://api.voxburst.io/v1/posts/post_abc123/events \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"Response
{
"events": [
{
"id": "evt_001",
"type": "post.created",
"createdAt": "2026-04-01T10:00:00Z",
"data": {}
},
{
"id": "evt_002",
"type": "post.published",
"createdAt": "2026-04-01T14:00:00Z",
"data": { "status": "published" }
}
]
}Get Latest Post Event
GET /v1/posts/:id/events/latest
Returns the most recent lifecycle event for a post.
curl https://api.voxburst.io/v1/posts/post_abc123/events/latest \
-H "Authorization: Bearer vb_live_xxxxxxxxxxxxx"