---
title: "Sync completed"
method: POST
path: "sync.completed"
tags: ["Webhook Events"]
---

# Sync completed

`POST sync.completed` (webhook)

A sync you started (adding or refreshing accounts or videos, in the dashboard or through the API) finished, and what it brought in is live in the dashboard and the API. `sync.id` is the `syncRequestId` the add or refresh call returned. One event per sync, also when some or all of its items failed (`status`). Scheduled syncs are not reported here. Opt-in: endpoints subscribed to all events (`*`) do not receive it; subscribe to it by name.

## Headers

- `webhook-id` string, required
- `webhook-timestamp` string, required
- `webhook-signature` string, required

## Payload

- SyncCompletedWebhookEvent: A sync you started (adding or refreshing accounts or videos, in the dashboard or through the API) finished, and what it brought in is live in the dashboard and the API. `sync.id` is the `syncRequestId` the add or refresh call returned. One event per sync, also when some or all of its items failed (`status`). Scheduled syncs are not reported here. Opt-in: endpoints subscribed to all events (`*`) do not receive it; subscribe to it by name.
  - `id` string, required: Event id; the `webhook-id` header. The same on every retry: dedupe on it.
  - `type` 'sync.completed', required
  - `timestamp` string, date-time, required: When the change happened
  - `organizationId` string, required
  - `actor` WebhookActor, required: Who caused the event: a member (`user`), an API key (`apiKeyId`), a creator, or viral.app itself (`system`); `surface` says where the change entered. Skip events your own API key caused to avoid loops.
    - `type` 'user' | 'api_key' | 'creator' | 'system', required
    - `surface` 'ui' | 'api' | 'copilot' | 'system', required
    - `userId` string, nullable, required
    - `apiKeyId` string, nullable, required
    - `impersonated` boolean, required
  - `data` object, required
    - `sync` object, required
      - `id` string, required
      - `trigger` 'user_add' | 'user_refresh' | 'api' | 'onboarding', required
      - `kind` 'accounts' | 'videos', required
      - `status` 'succeeded' | 'partial' | 'failed', required
      - `requestedAt` string, date-time, required
      - `finishedAt` string, date-time, required
      - `durationSeconds` number, required
      - `counts` object, required
        - `total` integer, required
        - `synced` integer, required
        - `failed` integer, required
      - `result` object, required
        - `newVideos` integer, required
        - `updatedVideos` integer, required
      - `platforms` string[], required
      - `items` object[], required
        - `kind` 'account' | 'video', required
        - `platform` 'facebook' | 'instagram' | 'tiktok' | 'youtube' | 'snapchat', required
        - `label` string, required
        - `status` 'synced' | 'failed', required
        - `videosFound` integer, nullable, required
        - `error` string, nullable, required
        - `retryable` boolean, required
      - `itemsTruncated` boolean, required

## Acknowledgement `200`

Any 2xx within 15 seconds acknowledges the event. Anything else, a timeout or a redirect is retried (10 attempts over about 3 days); 410 disables the endpoint.

---

[API](https://skmtc.dev/viral/apis/viral-app-api.md) · [All operations](https://skmtc.dev/viral/apis/viral-app-api/llms.txt) · [OpenAPI document](https://skmtc.dev/viral/apis/viral-app-api/revisions/31e97fa79ef1?raw)
