Post webhooks
Receive an event at every step of a post's publishing lifecycle, per platform, and for posts authored natively on the platform.
Post events tell you when a post is accepted, when each platform finishes, and when a post is later deleted or edited on the platform. Subscribe with POST /v1/webhooks/settings and the event names below (first event); delivery, retries and signatures are the same for every event (how webhooks behave).
Events
| Event | Description |
|---|---|
post.scheduled | The post entered the scheduled state: created with a schedule, added to a queue, promoted from draft, or retried after failing. |
post.platform.published | One platform target finished publishing, without waiting for the others. |
post.platform.failed | One platform target failed permanently. |
post.published | The post published on every target platform. |
post.partial | The post published on some platforms and failed on others. |
post.failed | The post failed on every target platform. |
post.tiktok.url_resolved | A published TikTok post's public URL became available. |
post.platform.deleted | A published platform target was deleted on the platform. |
post.cancelled | The post's publishing job was cancelled. |
post.recycled | A recycling schedule cloned a published post for republishing. |
post.external.created | A post authored natively on the platform (outside Zernio) was detected for the first time. |
post.external.updated | A tracked native post's text or media changed on the platform. |
post.external.deleted | A tracked native post was removed from the platform. |
How it behaves
A post you publish emits events at three moments, in a fixed order:
post.scheduled fires on every entry into the scheduled state
Zernio sends post.scheduled each time a post enters the scheduled state, not only at creation: a post created with a schedule (including publishNow, where it means accepted and queued), a draft promoted to scheduled or queued, a post added to a queue, and a failed or partial post you retry. It does not fire when an already-scheduled post is edited or moved to another time. One post can emit it more than once over its life.
Platform events stream in as each platform finishes
Zernio sends one post.platform.published or post.platform.failed per platform target as soon as that target terminates, without waiting for the slowest one. A post targeting 3 platforms emits up to 3 of them. post.platform.failed fires only on permanent failure; retryable errors stay silent until they succeed or fail for good.
The rollup fires once, after every platform has terminated
Zernio sends post.published when all targets succeeded, post.partial when the result is mixed, and post.failed when all failed. Exactly one of the three fires per publishing job.
Two events can trail the rollup
Zernio sends post.tiktok.url_resolved minutes after the rollup, when a TikTok target already reported as published gains its public URL. post.platform.deleted can trail by days: a background sync, roughly hourly, detects that a target you published was later deleted on the platform.
Post events echo the metadata you sent
Zernio returns the free-form metadata object you supplied on Create post as post.metadata on every rollup event (post.scheduled, post.published, post.partial, post.failed, post.cancelled, post.recycled) and every per-platform event (post.platform.published, post.platform.failed, post.platform.deleted, post.tiktok.url_resolved). Put your own record id in it at creation and no event needs a lookup by post._id. The key is omitted when the post was created without it, and the post.external.* events never carry it, because Zernio did not create those posts.
Three events sit outside the pipeline
Zernio sends post.cancelled when a publishing job is cancelled before anything published; if a platform already published, the rollup is post.partial instead. post.recycled fires when a recycling schedule clones a published post, carries the new post's id, and that clone emits its own post.scheduled. The post.external.* family comes from the same background sync of posts authored natively on the platform, roughly hourly, not from publishing at all.
post.published
The post published on every target platform. Each platforms[] entry carries the platformPostId and publishedUrl.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post events
Response Body
Example Requests
Webhook payload for post events
/post.publishedpost.failed
The post failed on every target platform. Each platforms[] entry carries the platform's error, plus errorCategory and errorSource, the same taxonomy as platforms[] on Get post (categories and fixes). Branch on errorCategory, not on the message text.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post events
Response Body
Example Requests
Webhook payload for post events
/post.failedpost.partial
The post published on some platforms and failed on others. Read platforms[].status to tell them apart; failed entries carry error, errorCategory and errorSource.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post events
Response Body
Example Requests
Webhook payload for post events
/post.partialpost.cancelled
The post's publishing job was cancelled before anything published.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post events
Response Body
Example Requests
Webhook payload for post events
/post.cancelledpost.scheduled
The post entered the scheduled state: created with a schedule, added to a queue, promoted from draft, retried after a failure, or created as a recycled clone. Editing or rescheduling an already-scheduled post does not fire it.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post events
Response Body
Example Requests
Webhook payload for post events
/post.scheduledpost.recycled
A recycling schedule cloned a published post for republishing. post.id is the new clone's id.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post events
Response Body
Example Requests
Webhook payload for post events
/post.recycledpost.platform.published
One platform target finished publishing, without waiting for the other platforms on the same post. Use it for incremental UIs and post.published for the post-level rollup. The payload carries a platform block (platform post id and URL) and an account block identifying the connected account, so a cross-post to 2 accounts on the same platform produces 2 events.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for the per-platform terminal events
post.platform.published and post.platform.failed, for
post.platform.deleted (same shape, fired when Zernio's background
sync detects that a platform target published through Zernio was
later deleted on the platform; poll-driven ~hourly, not real-time),
and for post.tiktok.url_resolved (same shape, fired when a
published TikTok post's public URL is backfilled). Terminal events
fire once per platform target inside a post as that platform
reaches a terminal state (published or permanent failure), except
that a target which later fails background reconciliation emits
post.platform.failed a second time, after its own
post.platform.published. The post envelope mirrors the shape
of WebhookPayloadPost so
consumers can reuse rendering logic; the platform block
identifies which specific platform transitioned; the account
block identifies the connected account behind that
platform-write.
Response Body
Example Requests
Webhook payload for the per-platform terminal events
post.platform.published and post.platform.failed, for
post.platform.deleted (same shape, fired when Zernio's background
sync detects that a platform target published through Zernio was
later deleted on the platform; poll-driven ~hourly, not real-time),
and for post.tiktok.url_resolved (same shape, fired when a
published TikTok post's public URL is backfilled). Terminal events
fire once per platform target inside a post as that platform
reaches a terminal state (published or permanent failure), except
that a target which later fails background reconciliation emits
post.platform.failed a second time, after its own
post.platform.published. The post envelope mirrors the shape
of WebhookPayloadPost so
consumers can reuse rendering logic; the platform block
identifies which specific platform transitioned; the account
block identifies the connected account behind that
platform-write.
/post.platform.publishedpost.platform.failed
One platform target failed permanently. platform.error carries the platform's message, and platform.errorCategory and platform.errorSource classify it with the same taxonomy as Get post, so you can tell a reconnect (auth_expired) from a content fix (user_content) without parsing text. Retryable failures do not fire it, so retry loops stay quiet. The rollup (post.failed or post.partial) fires separately once every platform has terminated.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for the per-platform terminal events
post.platform.published and post.platform.failed, for
post.platform.deleted (same shape, fired when Zernio's background
sync detects that a platform target published through Zernio was
later deleted on the platform; poll-driven ~hourly, not real-time),
and for post.tiktok.url_resolved (same shape, fired when a
published TikTok post's public URL is backfilled). Terminal events
fire once per platform target inside a post as that platform
reaches a terminal state (published or permanent failure), except
that a target which later fails background reconciliation emits
post.platform.failed a second time, after its own
post.platform.published. The post envelope mirrors the shape
of WebhookPayloadPost so
consumers can reuse rendering logic; the platform block
identifies which specific platform transitioned; the account
block identifies the connected account behind that
platform-write.
Response Body
Example Requests
Webhook payload for the per-platform terminal events
post.platform.published and post.platform.failed, for
post.platform.deleted (same shape, fired when Zernio's background
sync detects that a platform target published through Zernio was
later deleted on the platform; poll-driven ~hourly, not real-time),
and for post.tiktok.url_resolved (same shape, fired when a
published TikTok post's public URL is backfilled). Terminal events
fire once per platform target inside a post as that platform
reaches a terminal state (published or permanent failure), except
that a target which later fails background reconciliation emits
post.platform.failed a second time, after its own
post.platform.published. The post envelope mirrors the shape
of WebhookPayloadPost so
consumers can reuse rendering logic; the platform block
identifies which specific platform transitioned; the account
block identifies the connected account behind that
platform-write.
/post.platform.failedpost.platform.deleted
Zernio's background sync detected that a platform target you published was later deleted on the platform, for example the user removed the Instagram post in the Instagram app. Detection is poll-driven, roughly hourly, because platforms push no deletion notice for published media: Zernio diffs the platform's post listing and probes posts that stop resolving. platform.status is deleted and platform.deletedAt is the detection time, not the moment of deletion. Coverage is bounded to the posts the platform's listing returns, so deletions of very old posts may go undetected.
Detection is listing-based, so a rare false positive is possible, for example a platform API briefly omitting a post. Zernio heals its own data when the post reappears but does not retract the webhook. Re-check the post against the platform before deleting on your side.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for the per-platform terminal events
post.platform.published and post.platform.failed, for
post.platform.deleted (same shape, fired when Zernio's background
sync detects that a platform target published through Zernio was
later deleted on the platform; poll-driven ~hourly, not real-time),
and for post.tiktok.url_resolved (same shape, fired when a
published TikTok post's public URL is backfilled). Terminal events
fire once per platform target inside a post as that platform
reaches a terminal state (published or permanent failure), except
that a target which later fails background reconciliation emits
post.platform.failed a second time, after its own
post.platform.published. The post envelope mirrors the shape
of WebhookPayloadPost so
consumers can reuse rendering logic; the platform block
identifies which specific platform transitioned; the account
block identifies the connected account behind that
platform-write.
Response Body
Example Requests
Webhook payload for the per-platform terminal events
post.platform.published and post.platform.failed, for
post.platform.deleted (same shape, fired when Zernio's background
sync detects that a platform target published through Zernio was
later deleted on the platform; poll-driven ~hourly, not real-time),
and for post.tiktok.url_resolved (same shape, fired when a
published TikTok post's public URL is backfilled). Terminal events
fire once per platform target inside a post as that platform
reaches a terminal state (published or permanent failure), except
that a target which later fails background reconciliation emits
post.platform.failed a second time, after its own
post.platform.published. The post envelope mirrors the shape
of WebhookPayloadPost so
consumers can reuse rendering logic; the platform block
identifies which specific platform transitioned; the account
block identifies the connected account behind that
platform-write.
/post.platform.deletedpost.tiktok.url_resolved
A published TikTok post's public URL became available. TikTok exposes the numeric video id asynchronously, often minutes after the upload completes, so post.published can carry an empty publishedUrl for TikTok. This event delivers the resolved URL and platform post id, at most once per platform target. It never fires for drafts or private posts, which have no public URL.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for the per-platform terminal events
post.platform.published and post.platform.failed, for
post.platform.deleted (same shape, fired when Zernio's background
sync detects that a platform target published through Zernio was
later deleted on the platform; poll-driven ~hourly, not real-time),
and for post.tiktok.url_resolved (same shape, fired when a
published TikTok post's public URL is backfilled). Terminal events
fire once per platform target inside a post as that platform
reaches a terminal state (published or permanent failure), except
that a target which later fails background reconciliation emits
post.platform.failed a second time, after its own
post.platform.published. The post envelope mirrors the shape
of WebhookPayloadPost so
consumers can reuse rendering logic; the platform block
identifies which specific platform transitioned; the account
block identifies the connected account behind that
platform-write.
Response Body
Example Requests
Webhook payload for the per-platform terminal events
post.platform.published and post.platform.failed, for
post.platform.deleted (same shape, fired when Zernio's background
sync detects that a platform target published through Zernio was
later deleted on the platform; poll-driven ~hourly, not real-time),
and for post.tiktok.url_resolved (same shape, fired when a
published TikTok post's public URL is backfilled). Terminal events
fire once per platform target inside a post as that platform
reaches a terminal state (published or permanent failure), except
that a target which later fails background reconciliation emits
post.platform.failed a second time, after its own
post.platform.published. The post envelope mirrors the shape
of WebhookPayloadPost so
consumers can reuse rendering logic; the platform block
identifies which specific platform transitioned; the account
block identifies the connected account behind that
platform-write.
/post.tiktok.url_resolvedpost.external.created
Zernio's background sync detected a post authored natively on the platform, outside Zernio, such as a Google Business Profile post created in the Google interface. Detection is poll-driven, roughly hourly, because most platforms push no notice for merchant-authored posts. post.source is always "external" and post.id is the platform-native post id.
On a freshly connected account, every existing native post is reported as post.external.created on the first sync, a one-time backfill. Treat created as an idempotent upsert keyed on post.id.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post.external.created / post.external.updated / post.external.deleted. Fired by Zernio's background sync when it detects a natively-authored post (e.g. a Google Business Profile localPost created in the Google UI), NOT a post published through Zernio. Poll-driven (~hourly), not real-time. On post.external.deleted, post.deletedAt is populated.
Response Body
Example Requests
Webhook payload for post.external.created / post.external.updated / post.external.deleted. Fired by Zernio's background sync when it detects a natively-authored post (e.g. a Google Business Profile localPost created in the Google UI), NOT a post published through Zernio. Poll-driven (~hourly), not real-time. On post.external.deleted, post.deletedAt is populated.
/post.external.createdpost.external.updated
A tracked native post's text or media changed on the platform. Zernio detects edits by comparing the post's text and media structure and, where the platform exposes one, the platform's own edit timestamp. A media-URL-only refresh (some platforms rotate expiring CDN URLs) does not fire it.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post.external.created / post.external.updated / post.external.deleted. Fired by Zernio's background sync when it detects a natively-authored post (e.g. a Google Business Profile localPost created in the Google UI), NOT a post published through Zernio. Poll-driven (~hourly), not real-time. On post.external.deleted, post.deletedAt is populated.
Response Body
Example Requests
Webhook payload for post.external.created / post.external.updated / post.external.deleted. Fired by Zernio's background sync when it detects a natively-authored post (e.g. a Google Business Profile localPost created in the Google UI), NOT a post published through Zernio. Poll-driven (~hourly), not real-time. On post.external.deleted, post.deletedAt is populated.
/post.external.updatedpost.external.deleted
A tracked native post was removed from the platform. post.deletedAt is the detection time. Coverage is bounded to the most recent posts the platform's listing returns, so deletions of very old posts may go undetected.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for post.external.created / post.external.updated / post.external.deleted. Fired by Zernio's background sync when it detects a natively-authored post (e.g. a Google Business Profile localPost created in the Google UI), NOT a post published through Zernio. Poll-driven (~hourly), not real-time. On post.external.deleted, post.deletedAt is populated.
Response Body
Example Requests
Webhook payload for post.external.created / post.external.updated / post.external.deleted. Fired by Zernio's background sync when it detects a natively-authored post (e.g. a Google Business Profile localPost created in the Google UI), NOT a post published through Zernio. Poll-driven (~hourly), not real-time. On post.external.deleted, post.deletedAt is populated.
/post.external.deletedRelated
- Webhooks: create an endpoint, retries, signatures.
- Post lifecycle: the
statusvalues these events mirror. - Error handling: what
platforms[].error,errorCategoryanderrorSourcecontain. - Get post: the same data on demand.
- Inbox webhooks: comments on these posts.