---
title: "Ads initial sync completed event"
method: POST
path: "account.ads.initial_sync_completed"
tags: ["Webhook Events"]
---

# Ads initial sync completed event

`POST account.ads.initial_sync_completed` (webhook)

Fired once per ads-enabled account when the initial sync (ad-account
discovery + 90-day historical ad backfill) completes. The `sync` block
reports whether the backfill succeeded and how many ads were synced.

## Payload

- WebhookPayloadAccountAdsInitialSyncCompleted — Webhook payload for `account.ads.initial_sync_completed` events. Fired once per ads-enabled account when the initial discovery + 90-day ad backfill finishes (whether it succeeded fully, partially, or failed).
  - `id` string, required — Stable webhook event ID
  - `event` 'account.ads.initial_sync_completed', required
  - `account` object, required
    - `accountId` string, required — The account's unique identifier (same as used in /v1/accounts/{accountId})
    - `profileId` string, required — The profile's unique identifier this account belongs to
    - `platform` string, required
    - `username` string, required
    - `displayName` string
    - `platformUserId` string — The platform-side account/ad-account ID (e.g. Meta ad account ID).
    - `profilePicture` string, uri — URL of the account's profile picture, when available.
    - `platformAdAccountId` string — When the consumer scoped the connect call to a single ad account, this echoes that ID back so the webhook can be correlated to the originating connect request without consulting the consumer's DB. Meta uses the `act_*` shape.
    - `platformAdAccountIds` string[] — Every ad-account ID that the connected token could see at discovery time. Useful for "we synced ads from these accounts" UX without a follow-up API call. Empty array when the token had no ad-account visibility.
  - `sync` object, required — Summary of the initial ads sync backfill results.
    - `status` 'success' | 'failure', required — Overall outcome of the initial sync.
    - `totalAds` integer, required — Total number of ads discovered for backfill.
    - `synced` integer, required — Number of ads successfully synced.
    - `failed` integer, required — Number of ads that failed to sync.
    - `error` string — Free-form error message from the platform (typically Meta's Marketing API). Truncated to ~2KB. Present when `status` is `failure` (and sometimes on `success` when discovery saw zero ad accounts). For UX branching prefer `errorCategory`; this field is for human display and debugging.
    - `errorCode` string — Platform-native error code if parsed (e.g. Meta `190`, `10`, `200`).
    - `errorSubcode` string — Platform-native error subcode if parsed.
    - `errorCategory` 'token_invalid' | 'permission_denied' | 'no_ad_accounts' | 'rate_limited' | 'discovery_failed' | 'unknown' — Stable category for UX branching. New values may be added; existing ones are stable. Mapping: - `token_invalid`: access token is expired or revoked. Reconnect. - `permission_denied`: token lacks required scope, or the user has no role on the Business Manager that owns the ad account. Reconnect with full permissions, or have an admin grant access. - `no_ad_accounts`: token is valid but sees zero ad accounts. The user needs to connect a Business Manager that owns ad accounts. - `rate_limited`: platform throttled us. Sync will retry automatically. - `discovery_failed`: any other platform-side failure. Inspect `error`. - `unknown`: classifier could not categorize the failure.
  - `timestamp` string, date-time, required — 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.

## Acknowledgement `200`

Webhook received successfully

---

[API](https://skmtc.net/zernio/apis/zernio-api.md) · [All operations](https://skmtc.net/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/zernio/zernio-api/revisions/e0cd92070858/schema)
