# Sync

Sync is the CDA endpoint that synchronizes a *Space*'s published material incrementally (as deltas). Instead of re-fetching all published *Content*, *Media*, and *Content Type* every time, a client fetches everything once and caches it locally, then from that point on receives only what has changed and what has been deleted since the last sync and updates that cache. Apps that need to hold the entire published material (offline caches, search indexes, static site builds, and so on) use it to reduce the amount of data transferred.

Synchronization runs in two phases. First you fetch everything with an **initial sync** and save the `nextSyncUrl` carried in the response. From then on you call a **delta sync** with the `sync-token` contained in that URL to receive only the changes and deletions, and because the response again gives you a new `nextSyncUrl`, you save that value and repeat.

## Sync flow {#sync-flow}

1. **Initial sync:** Call with `?initial=true&type=All` to fetch all published material. A `nextSyncUrl` is carried at the end of the response.
2. **Save `nextSyncUrl`:** Save the received `nextSyncUrl` value as is. This URL contains the `sync-token` to use on the next call.
3. **Delta sync:** Call again with the `sync-token` from the saved `nextSyncUrl`. Only what has changed and what has been deleted since the last sync is carried in the response, along with a new `nextSyncUrl` at the end.
4. **Repeat:** Save the new `nextSyncUrl` you received, and repeat step 3 whenever you need to sync.

`sync-token` is not a value you create yourself but an opaque cursor. Do not interpret its format or assemble it by hand; pass the value you received from the previous response's `nextSyncUrl` to the next call as is.

## Response structure {#response-structure}

The following is the initial sync (`type=All`) response of the demo *Space*. `items` carries published entities and deletion markers mixed together, and at the end comes the `nextSyncUrl` to use for the next delta sync.

```json
{
  "sys": { "type": "PageResponse" },
  "limit": 15,
  "items": [
    {
      "sys": {
        "id": "3trmXRM3RqbgSnifyg7PBUM8Ds0Xvw",
        "type": "Content",
        "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
        "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } },
        "createdAt": "2026-06-17T16:58:56.660Z",
        "updatedAt": "2026-06-18T01:46:55.604Z",
        "revision": 3
      },
      "fields": {
        "price": { "en-US": 18000 },
        "description": { "en-US": "Double-wall vacuum insulation keeps drinks hot or cold for hours. A roomy 500ml." },
        "photo": {},
        "productName": { "en-US": "Stainless Tumbler 500ml" }
      }
    }
  ],
  "links": {},
  "nextSyncUrl": "/v1/spaces/tcq4V2Xb/sync?sync-token=165rWhDiuLNoYOwjVQQAYXMA7makztXnhAV3qamYU75jFldqtvaEhMnr29PqsKTAbcspOP6ziWrv2CuIaa450zqOtXNXBUwvoSl6VV7PzwI0SXaSv504321hl3hE7MoebljTlKeltN8fYIFldu1TPdfeIoqLtN"
}
```

Key properties:

- `sys.type`: The kind of the envelope wrapping the sync response. It is always `"PageResponse"`.
- `limit`: The number of items carried at once.
- `items`: An array into which published entities and deletion markers go mixed together. The first item in the example above is a live *Content* (with its body), and a deletion marker (`DeletedContent`) carries only `sys` without a body. Item kinds are covered in [Item kinds](#item-kinds) below.
- `links`: The page links object. Because Sync chains the next page and next delta through `nextSyncUrl`, this object can be empty.
- `nextSyncUrl`: The path to call for the next delta sync. Use the `sync-token` of this URL on the next call as is.

**The `fields` of an `items` entry come as the locale map, not resolved by locale.** As with `productName` being `{ "en-US": "Stainless Tumbler 500ml" }` in the example above, each field value comes as a map holding per-locale values. Unlike [CDA Content](/api/reference/cda/content.md) and [CDA Media](/api/reference/cda/media.md) reads, which pick a single value with the `locale` parameter, Sync sends down the full map without resolving the locale. The client receives this map, caches it locally, and resolves it when needed. That is why Sync has no `locale` parameter.

`photo` being `{}` (an empty map) in the example above is because there is no linked *Media* in any locale.

## Item kinds {#item-kinds}

`items` carries items with differing `sys.type` mixed together. Broadly there are two branches: live entities and deletion markers.

| `sys.type` | Body (`fields`) | Meaning |
|---|---|---|
| `Content` | Present | A live published *Content*. The full body is carried. |
| `Media` | Present | A live published *Media*. The full body is carried. |
| `ContentType` | Present | A live published *Content Type*. The full body is carried. |
| `DeletedContent` | None | A marker for a deleted *Content*. Only `sys` is carried, without a body. |
| `DeletedMedia` | None | A marker for a deleted *Media*. Only `sys` is carried, without a body. |

A deletion marker is a signal that the resource is no longer in the published material. The client looks at the marker's `sys.id` and removes that item from the local cache.

In an initial sync, the `type` parameter selects what to receive.

| `type` | What you receive |
|---|---|
| `All` | All live *Content*, *Media*, and *Content Type* plus all deletion markers |
| `Content` | Live *Content* (along with *Content Type* and *Media*) |
| `Media` | Live *Media* (along with *Content* and *Content Type*) |
| `Deletion` | All deletion markers (`DeletedContent` and `DeletedMedia`) |
| `DeletedContent` | Deleted *Content* markers |
| `DeletedMedia` | Deleted *Media* markers |

When `type` is `Content` or `DeletedContent`, you can narrow to only the items belonging to a specific *Content Type* with the `content-type` parameter.

## API {#api}

The base URL for the two endpoints below is `https://cda.weegloo.com/v1`, and a Bearer token that authenticates against CDA is required in the `Authorization` header. Both use the same path `GET /spaces/{spaceId}/sync`, and query parameters distinguish initial sync from delta sync. Unlike *Content* and *Media* reads, Sync has no `locale` parameter. Values come as the locale map.

```api-endpoint
{
  "title": "Initial sync",
  "method": "GET",
  "path": "/spaces/{spaceId}/sync",
  "description": "Performs the first sync by fetching all of a Space's published material. initial=true and type are required. Save the nextSyncUrl at the end of the response, then call delta sync with its sync-token afterward. Sync sends down fields as the locale map, so there is no locale parameter.",
  "responseStatus": 200,
  "baseUrl": "https://cda.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true }
  },
  "queryParameterSchema": {
    "initial": { "type": "boolean", "description": "Initial sync flag. Always true.", "required": true, "default": true },
    "type": { "type": "string", "description": "The kind of items to receive. All=everything, Content=live Content, Media=live Media, Deletion=all deletion markers, DeletedContent=deleted Content markers, DeletedMedia=deleted Media markers.", "required": true, "default": "All" },
    "content-type": { "type": "string", "description": "When type is Content or DeletedContent, narrow to a specific Content Type by its sys.id (optional)." },
    "limit": { "type": "integer", "description": "Number of items to return per page (1-100)", "default": 15 }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CDA authentication; usually a DeliveryAccessToken)" }
  },
  "responseExample": {
    "sys": { "type": "PageResponse" },
    "limit": 15,
    "items": [
      {
        "sys": {
          "id": "3trmXRM3RqbgSnifyg7PBUM8Ds0Xvw",
          "type": "Content",
          "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
          "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } },
          "createdAt": "2026-06-17T16:58:56.660Z",
          "updatedAt": "2026-06-18T01:46:55.604Z",
          "revision": 3
        },
        "fields": {
          "price": { "en-US": 18000 },
          "description": { "en-US": "Double-wall vacuum insulation keeps drinks hot or cold for hours. A roomy 500ml." },
          "photo": {},
          "productName": { "en-US": "Stainless Tumbler 500ml" }
        }
      }
    ],
    "links": {},
    "nextSyncUrl": "/v1/spaces/tcq4V2Xb/sync?sync-token=165rWhDiuLNoYOwjVQQAYXMA7makztXnhAV3qamYU75jFldqtvaEhMnr29PqsKTAbcspOP6ziWrv2CuIaa450zqOtXNXBUwvoSl6VV7PzwI0SXaSv504321hl3hE7MoebljTlKeltN8fYIFldu1TPdfeIoqLtN"
  }
}
```

```api-endpoint
{
  "title": "Delta sync",
  "method": "GET",
  "path": "/spaces/{spaceId}/sync",
  "description": "Receives only what has changed and what has been deleted since the last sync. sync-token is required, and you pass the value received from the previous response's nextSyncUrl as is (an opaque cursor you do not create yourself). A new nextSyncUrl comes at the end of the response, so save that value and use it on the next call. When there are no changes, items comes as an empty array.",
  "responseStatus": 200,
  "baseUrl": "https://cda.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true }
  },
  "queryParameterSchema": {
    "sync-token": { "type": "string", "description": "The opaque cursor received from the previous response's nextSyncUrl. Do not create it yourself; pass the received value as is.", "required": true }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CDA authentication; usually a DeliveryAccessToken)" }
  },
  "responseExample": {
    "sys": { "type": "PageResponse" },
    "limit": 15,
    "items": [],
    "links": {},
    "nextSyncUrl": "/v1/spaces/tcq4V2Xb/sync?sync-token=165rWhDiuLNoYOwjVQQAYXMA7makztXnhAV3qamYU75jFldqtvaEhMnr29PqsKTAbcspOP6ziWrv2CuIaa450zqOtXNXBUwvoSl6VV7PzwI0SXaSv504321hl3hE7MoebljTlKeltN8fYIFldu1TPdfeIoqLtN"
  }
}
```

An empty `items` means there have been no changes since the last sync. A new `nextSyncUrl` still comes in this case, so save that value and use it as is on the next sync.

## Related documents {#related-documents}

- [CDA overview](/api/reference/cda.md): CDA as a whole and its common delivery behavior.
- [CDA Content](/api/reference/cda/content.md): Reading a single locale-resolved published Content.
- [CDA Locale](/api/reference/cda/locale.md): The Locale list used when resolving the locale maps received via sync.
- [Localization (concept)](/getting-started/core-concepts/content/localization.md): Resolving locale values and fallback.
