Webhook event catalog
Every webhook event uses the same envelope. The event field identifies the event; data contains the event-specific payload. The body is the event object as-is — there is no separate event wrapper or event ID inside the body.
{
"event": "<event-type>",
"timestamp": "2026-06-01T14:00:00Z",
"data": { ... }
}The delivery ID and event name travel in request headers, not in the body — read X-VoxBurst-Delivery-Id and X-VoxBurst-Event from the request. All delivery requests include the headers documented in Delivery Headers. Always verify X-VoxBurst-Signature before processing.
Exception: the test delivery (POST /v1/webhooks/test) uses a different shape — see test.webhook below.
post.created
Fires when: A post is successfully created (draft or scheduled) via POST /v1/posts or POST /v1/posts/bulk.
{
"event": "post.created",
"timestamp": "2026-06-01T10:00:00Z",
"data": {
"postId": "post_abc123",
"status": "DRAFT",
"scheduledFor": null,
"platforms": ["TWITTER", "INSTAGRAM"],
"createdById": "usr_creator1"
}
}| Field | Type | Description |
|---|---|---|
postId | string | Post ID |
status | string | "DRAFT" or "SCHEDULED" |
scheduledFor | string | null | ISO 8601 scheduled time, or null if draft |
platforms | string[] | Platform constants this post targets — UPPERCASE (e.g. "TWITTER") |
createdById | string | null | User ID who created the post, or null if system-created |
post.scheduled
Fires when: A post transitions to scheduled status — either created with a scheduledFor time, or updated from draft to scheduled.
{
"event": "post.scheduled",
"timestamp": "2026-06-01T10:05:00Z",
"data": {
"id": "post_abc123",
"content": "Check out our new launch! 🚀",
"status": "SCHEDULED",
"scheduledFor": "2026-06-15T14:00:00Z",
"accountIds": ["acc_abc123"],
"contentType": "TEXT"
}
}Note: post.scheduled uses a different data shape from post.created — it carries the full post (id, content) plus accountIds (social account IDs scheduled to publish) and contentType ("TEXT" for text posts). scheduledFor is always set.
post.published
Fires when: Publishing completes — all platforms succeeded ("PUBLISHED") or at least one succeeded with at least one failed ("PARTIAL").
There is no separate post.partial event. Check data.status in every post.published handler to detect partial failures. Always inspect data.platforms for per-platform outcomes.
All platforms succeeded (status: "PUBLISHED")
{
"event": "post.published",
"timestamp": "2026-06-15T14:00:05Z",
"data": {
"id": "post_abc123",
"workspaceId": "ws_xyz",
"content": "Check out our new launch! 🚀",
"status": "PUBLISHED",
"publishedAt": "2026-06-15T14:00:05Z",
"platforms": [
{
"platform": "TWITTER",
"status": "PUBLISHED",
"platformPostId": "1234567890123456789",
"platformPostUrl": "https://x.com/user/status/1234567890123456789",
"publishedAt": "2026-06-15T14:00:04Z"
},
{
"platform": "INSTAGRAM",
"status": "PUBLISHED",
"platformPostId": "17854360229135492",
"platformPostUrl": "https://www.instagram.com/p/ABC123/",
"publishedAt": "2026-06-15T14:00:05Z"
}
]
}
}Partial failure (status: "PARTIAL")
{
"event": "post.published",
"timestamp": "2026-06-15T14:00:06Z",
"data": {
"id": "post_abc123",
"workspaceId": "ws_xyz",
"content": "Check out our new launch! 🚀",
"status": "PARTIAL",
"publishedAt": "2026-06-15T14:00:06Z",
"platforms": [
{
"platform": "TWITTER",
"status": "PUBLISHED",
"platformPostId": "1234567890123456789",
"platformPostUrl": "https://x.com/user/status/1234567890123456789",
"publishedAt": "2026-06-15T14:00:04Z"
},
{
"platform": "INSTAGRAM",
"status": "FAILED",
"error": {
"code": "MEDIA_REJECTED",
"message": "Media format not supported: image must be JPEG"
}
}
]
}
}| Field | Type | Description |
|---|---|---|
id | string | Post ID |
workspaceId | string | Workspace ID |
content | string | Post text |
status | string | "PUBLISHED" (all succeeded) or "PARTIAL" (some failed) |
publishedAt | string | ISO 8601 completion timestamp |
platforms[] | array | Per-platform publish results |
platforms[].platform | string | Platform constant — UPPERCASE (e.g. "TWITTER") |
platforms[].status | string | "PUBLISHED" or "FAILED" — UPPERCASE |
platforms[].platformPostId | string | undefined | Platform’s native post ID (success only) |
platforms[].platformPostUrl | string | undefined | Public URL of the post (success only) |
platforms[].publishedAt | string | undefined | ISO 8601 timestamp (success only) |
platforms[].error | object | undefined | { code, message } — failure only |
Platform and status strings in webhook payloads are always UPPERCASE. This differs from REST API responses, which use lowercase.
post.failed
Fires when: Publishing completed and all platforms failed.
{
"event": "post.failed",
"timestamp": "2026-06-15T14:00:08Z",
"data": {
"id": "post_abc123",
"workspaceId": "ws_xyz",
"content": "Check out our new launch! 🚀",
"status": "FAILED",
"publishedAt": "2026-06-15T14:00:08Z",
"platforms": [
{
"platform": "TWITTER",
"status": "FAILED",
"error": {
"code": "ACCOUNT_DISCONNECTED",
"message": "OAuth token expired or revoked"
}
},
{
"platform": "INSTAGRAM",
"status": "FAILED",
"error": {
"code": "PUBLISH_ERROR",
"message": "Media format not supported"
}
}
]
}
}Same schema as post.published. Use POST /v1/posts/:id/retry or POST /v1/posts/:id/platforms/:platformId/fix to recover.
post.draft.approved
Fires when: A post in an approval workflow reaches its final approval step and is queued for publishing.
{
"event": "post.draft.approved",
"timestamp": "2026-06-01T11:30:00Z",
"data": {
"postId": "post_abc123",
"approverId": "usr_approver1",
"stepOrder": 2,
"comment": "Looks good, approved."
}
}| Field | Type | Description |
|---|---|---|
postId | string | Post that was approved |
approverId | string | null | User ID who approved, or null if system-approved |
stepOrder | integer | Which approval step was completed |
comment | string | null | Reviewer’s comment, if any |
post.state_changed
Fires when: Any state-changing post lifecycle event occurs. This is an umbrella event — alongside it, VoxBurst also emits a dedicated event (e.g. post.published, post.failed) for key transitions. Subscribe to post.state_changed as a catch-all for post state changes.
{
"event": "post.state_changed",
"timestamp": "2026-06-15T14:00:08Z",
"data": {
"postId": "post_abc123",
"eventType": "PUBLISHED",
"platform": null,
"actor": null,
"details": null,
"error": null
}
}| Field | Type | Description |
|---|---|---|
postId | string | Post whose state changed |
eventType | string | Post lifecycle event type that triggered the change (e.g. PUBLISHED, FAILED, CANCELLED) |
platform | string | null | Platform involved, lowercase, or null when not platform-specific |
actor | object | null | Who triggered the change, if user-initiated |
details | object | null | Extra details about the event, if any |
error | object | null | Error details, for failed transitions |
account.connected
Fires when: A social account is successfully connected via the OAuth callback.
{
"event": "account.connected",
"timestamp": "2026-06-01T09:00:00Z",
"data": {
"accountId": "acc_abc123",
"workspaceId": "ws_xyz",
"platform": "INSTAGRAM",
"username": "brandname"
}
}| Field | Type | Description |
|---|---|---|
accountId | string | VoxBurst account ID |
workspaceId | string | Workspace ID |
platform | string | Platform constant — UPPERCASE |
username | string | null | Platform username or handle |
account.disconnected
Fires when: A social account is disconnected via DELETE /v1/accounts/:id or revoked by the platform.
{
"event": "account.disconnected",
"timestamp": "2026-06-01T15:00:00Z",
"data": {
"accountId": "acc_abc123",
"workspaceId": "ws_xyz",
"platform": "TWITTER",
"reason": "user_disconnected"
}
}| Field | Type | Description |
|---|---|---|
accountId | string | VoxBurst account ID |
workspaceId | string | Workspace ID |
platform | string | Platform constant — UPPERCASE |
reason | string | "user_disconnected", "token_revoked", "token_expired", or "platform_suspended" |
account.error
Fires when: A connected account encounters a token error (expired, revoked) that prevents publishing.
{
"event": "account.error",
"timestamp": "2026-06-01T16:00:00Z",
"data": {
"accountId": "acc_abc123",
"workspaceId": "ws_xyz",
"platform": "LINKEDIN",
"error": "Token expired"
}
}| Field | Type | Description |
|---|---|---|
accountId | string | VoxBurst account ID |
workspaceId | string | Workspace ID |
platform | string | Platform constant — UPPERCASE |
error | string | Human-readable error description |
When you receive this event, prompt the user to reconnect the account via the OAuth flow.
media.uploaded
Fires when: A media file completes the S3 upload and processing pipeline — status transitions to READY.
{
"event": "media.uploaded",
"timestamp": "2026-06-01T10:01:30Z",
"data": {
"mediaId": "media_abc1234567890abc12345678",
"filename": "campaign-banner.jpg",
"contentType": "image/jpeg",
"sizeBytes": 204800
}
}| Field | Type | Description |
|---|---|---|
mediaId | string | VoxBurst media ID |
filename | string | Display filename |
contentType | string | MIME type (always image/jpeg after normalization for PNG/WebP) |
sizeBytes | integer | File size in bytes (post-normalization) |
media.ready and media.processing_failed are internal events and are not deliverable via webhooks. To track processing failures, poll GET /v1/media/:id until status is READY or FAILED.
post.deleted
Fires when: A post is deleted (e.g. via DELETE /v1/posts/:id).
{
"event": "post.deleted",
"timestamp": "2026-06-01T12:00:00Z",
"data": {
"postId": "post_abc123",
"eventType": "DELETED",
"platform": null,
"details": null,
"error": null
}
}| Field | Type | Description |
|---|---|---|
postId | string | Post that was deleted |
eventType | string | Post lifecycle event type — "DELETED" |
platform | string | null | Platform involved, or null when the event is not platform-specific |
details | object | null | Extra details about the event, if any |
error | object | null | Error details, for failed transitions |
test.webhook
Fires when: You call the test endpoint (POST /v1/webhooks/test). Sent to the endpoint under test; not subscribed to and subject to a different payload shape than the standard envelope.
{
"id": "evt_test_7f3ab1c2d4e5f6a7",
"event": "test.webhook",
"created": "2026-06-01T09:00:00Z",
"data": {
"message": "This is a test webhook delivery from VoxBurst."
}
}| Field | Type | Description |
|---|---|---|
id | string | Test event ID (evt_test_ prefix) |
event | string | Always "test.webhook" |
created | string | ISO 8601 timestamp — note the field name is created, not timestamp |
data.message | string | Fixed test message |