Zernio
Zernio
OverviewWebhooksPost webhooksInbox webhooksAutomation webhooksSupport run webhooksAccount webhooksAnalytics webhooksAds webhooksCall webhooksWhatsApp webhooksPhone number webhooksSMS registration webhooksBranded Calling webhooks
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources
Webhooks

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

EventDescription
post.scheduledThe post entered the scheduled state: created with a schedule, added to a queue, promoted from draft, or retried after failing.
post.platform.publishedOne platform target finished publishing, without waiting for the others.
post.platform.failedOne platform target failed permanently.
post.publishedThe post published on every target platform.
post.partialThe post published on some platforms and failed on others.
post.failedThe post failed on every target platform.
post.tiktok.url_resolvedA published TikTok post's public URL became available.
post.platform.deletedA published platform target was deleted on the platform.
post.cancelledThe post's publishing job was cancelled.
post.recycledA recycling schedule cloned a published post for republishing.
post.external.createdA post authored natively on the platform (outside Zernio) was detected for the first time.
post.external.updatedA tracked native post's text or media changed on the platform.
post.external.deletedA 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/post.published


post.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/post.failed


post.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/post.partial


post.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/post.cancelled


post.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/post.scheduled


post.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/post.recycled


post.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/post.platform.published


post.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/post.platform.failed


post.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/post.platform.deleted


post.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/post.tiktok.url_resolved


post.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/post.external.created


post.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/post.external.updated


post.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/post.external.deleted

Related

  • Webhooks: create an endpoint, retries, signatures.
  • Post lifecycle: the status values these events mirror.
  • Error handling: what platforms[].error, errorCategory and errorSource contain.
  • Get post: the same data on demand.
  • Inbox webhooks: comments on these posts.
Was this page helpful?

Webhooks

Create a webhook endpoint, receive your first event, and verify, deduplicate and retry deliveries the way Zernio sends them.

Inbox webhooks

Receive an event for every DM, delivery receipt, reaction, comment and review that reaches the inbox, and know which platforms send which.

On this page

EventsHow it behavespost.scheduled fires on every entry into the scheduled statePlatform events stream in as each platform finishesThe rollup fires once, after every platform has terminatedTwo events can trail the rollupPost events echo the metadata you sentThree events sit outside the pipelinepost.publishedpost.failedpost.partialpost.cancelledpost.scheduledpost.recycledpost.platform.publishedpost.platform.failedpost.platform.deletedpost.tiktok.url_resolvedpost.external.createdpost.external.updatedpost.external.deletedRelated
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.scheduled"
  • "post.published"
  • "post.failed"
  • "post.partial"
  • "post.cancelled"
  • "post.recycled"
post*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.scheduled"
  • "post.published"
  • "post.failed"
  • "post.partial"
  • "post.cancelled"
  • "post.recycled"
post*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.scheduled"
  • "post.published"
  • "post.failed"
  • "post.partial"
  • "post.cancelled"
  • "post.recycled"
post*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.scheduled"
  • "post.published"
  • "post.failed"
  • "post.partial"
  • "post.cancelled"
  • "post.recycled"
post*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.scheduled"
  • "post.published"
  • "post.failed"
  • "post.partial"
  • "post.cancelled"
  • "post.recycled"
post*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.scheduled"
  • "post.published"
  • "post.failed"
  • "post.partial"
  • "post.cancelled"
  • "post.recycled"
post*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.platform.published"
  • "post.platform.failed"
  • "post.platform.deleted"
  • "post.tiktok.url_resolved"
post*
platform*

The specific platform that transitioned to a terminal state.

account*

The connected account the platform-write went through.

timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.platform.published"
  • "post.platform.failed"
  • "post.platform.deleted"
  • "post.tiktok.url_resolved"
post*
platform*

The specific platform that transitioned to a terminal state.

account*

The connected account the platform-write went through.

timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.platform.published"
  • "post.platform.failed"
  • "post.platform.deleted"
  • "post.tiktok.url_resolved"
post*
platform*

The specific platform that transitioned to a terminal state.

account*

The connected account the platform-write went through.

timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.platform.published"
  • "post.platform.failed"
  • "post.platform.deleted"
  • "post.tiktok.url_resolved"
post*
platform*

The specific platform that transitioned to a terminal state.

account*

The connected account the platform-write went through.

timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.external.created"
  • "post.external.updated"
  • "post.external.deleted"
post*

Native (external) post data shared by all post.external.* payloads.

account*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.external.created"
  • "post.external.updated"
  • "post.external.deleted"
post*

Native (external) post data shared by all post.external.* payloads.

account*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*string

Value in

  • "post.external.created"
  • "post.external.updated"
  • "post.external.deleted"
post*

Native (external) post data shared by all post.external.* payloads.

account*
timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time