# account.ads.initial_sync_completed

The initial sync, ad-account discovery plus a 90-day ad backfill, completed for an ads-enabled account.

### When it fires

Fires once per ads-enabled account. `sync` reports whether the backfill succeeded fully or partially, and how many ads were synced versus failed.

### Scoped connects

When scoping was applied at connect time, `account.platformAdAccountId` echoes the chosen ad account when the scope is exactly one. `account.platformAdAccountIds` lists every `act_*` synced.

### On failure

When `sync.status` is `"failure"`, the payload adds `sync.error` (raw platform error, about 2 KB), `sync.errorCode` and `sync.errorSubcode` when parseable, and `sync.errorCategory`.

### Error categories

`sync.errorCategory` is `token_invalid`, `permission_denied`, `no_ad_accounts`, `rate_limited`, `discovery_failed` or `unknown`. New values may be added; existing ones are stable.

### Retrying

Reconnecting re-queues the backfill and the event fires again. It fixes `token_invalid`, `permission_denied` and `rate_limited`; `no_ad_accounts` needs an ad account on the grant first.

### When a retry is skipped

Zernio skips the re-queue only when a backfill already completed with at least one ad, or one started less than 20 minutes ago.




**Payload for `account.ads.initial_sync_completed`:**

- **id** (required) `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.
- **profiles**: `WebhookProfiles` - See schema definition
- **test** `boolean`: Always true when present: only a sample sent by POST /v1/webhooks/test with an event carries it. Real deliveries never do.
- **event** (required) `string`: No description - one of: account.ads.initial_sync_completed
- **account** (required) `object`: 
  - **accountId** (required) `string`: The account's unique identifier (same as used in /v1/accounts/{accountId})
  - **profileId** (required) `string`: The profile's unique identifier this account belongs to
  - **platform** (required) `string`: No description
  - **username** (required) `string`: No description
  - **displayName** `string`: No description
  - **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.
 (example: "act_1330190928038136")
  - **platformAdAccountIds** `array[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** (required) `object`: Summary of the initial ads sync backfill results.
  - **status** (required) `string`: Overall outcome of the initial sync. - one of: success, failure
  - **totalAds** (required) `integer`: Total number of ads discovered for backfill.
  - **synced** (required) `integer`: Number of ads successfully synced.
  - **failed** (required) `integer`: 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** `string`: Stable category for UX branching. New values may be added; existing ones are stable.

- `token_invalid`: access token is expired or revoked. Reconnect.
- `permission_denied`: token lacks a 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`: the platform throttled us. Sync retries automatically.
- `discovery_failed`: any other platform-side failure. Inspect `error`.
- `unknown`: the classifier could not categorize the failure.
 - one of: token_invalid, permission_denied, no_ad_accounts, rate_limited, discovery_failed, unknown
- **timestamp** (required) `string` (date-time): 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.