Analytics webhooks
Receive a cursor each time an account's analytics sync completes, then read every changed post in one call to the delta feed.
analytics.synced tells you that an account's analytics changed and hands you the cursor to read what changed from GET /v1/analytics/delta. Subscribe with POST /v1/webhooks/settings and events: ["analytics.synced"] (first event); delivery, retries and signatures are the same for every event (how webhooks behave).
Events
| Event | Description |
|---|---|
analytics.synced | One connected account's analytics sync cycle completed successfully. Carries a cursor for the delta feed, not metrics. |
How it behaves
The payload is a cursor for the delta feed
Zernio sends no metrics in this event. It says an account's analytics changed; the delta feed says what changed. sync.cursor is an opaque GET /v1/analytics/delta cursor positioned immediately before this cycle's rows. Pass it straight to the delta feed and one call returns every post whose analytics changed, across every account you can see. That replaces polling GET /v1/analytics once per connected account, where a fleet of 1,000 accounts costs 1,000 requests an hour.
The two are designed to be used together:
- Bootstrap your baseline once from
GET /v1/analytics. - Receive
analytics.synced. - Call
GET /v1/analytics/deltawith the cursor you were given, then keep sending back eachnextCursor.
If you would rather not run a webhook consumer, skip this event and poll the delta feed on a timer. The feed is the source of truth either way.
An empty page does not mean nothing changed
Zernio serves the delta feed from a materialized view, so a read issued the instant this event lands can return an empty data array while the rows are still landing. Re-poll with the same cursor rather than advancing. Advancing on an empty page is the one way to lose changes permanently.
Volume scales with your fleet
Zernio fires this event per account, per successful sync cycle, and sync runs roughly hourly per account. An integration with 1,000 connected accounts should expect on the order of 1,000 events an hour. Two consequences:
- Subscribe on a dedicated webhook endpoint. An endpoint's consecutive-failure count is shared by every event on it, so an outage on this busy event can disable the whole endpoint and silence low-volume events like
post.publishedwith it. - Return
2xxfirst, then do the delta read out of band.
When it does not fire
Zernio skips the event when the sync cycle fails or is skipped because the account was synced recently, when the account is inactive or disconnected, and when the platform does not support analytics sync. GET /v1/analytics lists the supported set.
analytics.synced
One connected account's analytics sync cycle completed successfully. sync.cursor is the delta-feed cursor for this cycle.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for analytics.synced. Fired once per connected account each
time its analytics sync cycle completes successfully. Poll-driven (roughly
hourly per account), not real-time, and never fired for a skipped or failed
cycle.
A TRIGGER, not a transport: it deliberately carries no metrics and no cursor.
When it arrives, call GET /v1/analytics/delta with YOUR OWN last nextCursor
to read what changed, across every account, in one paginated stream.
The absent cursor is deliberate. The feed's ordering position is assigned inside
the analytics store when the row is materialized, which normally has not
happened yet at the moment this event fires, so a cursor minted here could sit
ahead of the very rows the event announces and make you skip them. Your own
nextCursor is always in the feed's own ordering and can never do that.
Because of that same lag, a delta read issued the instant this event lands can legitimately come back empty. That is not "nothing changed": poll again with the same cursor you last used rather than treating the account as done.
Subscribe to this event on a DEDICATED webhook endpoint. It is high volume (roughly one delivery per connected account per hour) and a subscription's consecutive-failure count is shared across all of its events, so an outage while this event is flowing can suppress the low-volume publishing events that share the same subscription.
Response Body
Example Requests
Webhook payload for analytics.synced. Fired once per connected account each
time its analytics sync cycle completes successfully. Poll-driven (roughly
hourly per account), not real-time, and never fired for a skipped or failed
cycle.
A TRIGGER, not a transport: it deliberately carries no metrics and no cursor.
When it arrives, call GET /v1/analytics/delta with YOUR OWN last nextCursor
to read what changed, across every account, in one paginated stream.
The absent cursor is deliberate. The feed's ordering position is assigned inside
the analytics store when the row is materialized, which normally has not
happened yet at the moment this event fires, so a cursor minted here could sit
ahead of the very rows the event announces and make you skip them. Your own
nextCursor is always in the feed's own ordering and can never do that.
Because of that same lag, a delta read issued the instant this event lands can legitimately come back empty. That is not "nothing changed": poll again with the same cursor you last used rather than treating the account as done.
Subscribe to this event on a DEDICATED webhook endpoint. It is high volume (roughly one delivery per connected account per hour) and a subscription's consecutive-failure count is shared across all of its events, so an outage while this event is flowing can suppress the low-volume publishing events that share the same subscription.
/analytics.syncedRelated
- Webhooks: create an endpoint, retries, signatures.
- Analytics delta feed: the endpoint the cursor points at.
- Get analytics: the baseline read.
- Multi-tenant analytics: per-customer dashboards on top of the feed.