---
title: Sync content data
slug: graph/docs/sync-content-data
docTags: 
createdAt: 2026-07-30T20:30:20.147Z
---

Optimizely Graph provides endpoints that let you manage custom data in your graph service. Query the custom data in the same way as content indexed automatically.

:::hint{type="info"}
**Note**
For information, refer to the [Sync content data API reference](https://docs.developers.optimizely.com/platform-optimizely/v1.4.1-optimizely-graph/reference/post-contentv2datahandler).
:::

The endpoint lets you send your content data to the Graph service:

`https://cg.optimizely.com/api/content/v2/data?id=<content source ID>`

The `id` query parameter is the ID of your content source. It must match the ID used when defining [the content types](https://docs.developers.optimizely.com/platform-optimizely/docs/synchronize-content-data) for the content source.

:::hint{type="warning"}
**Important**
Content source IDs must be four characters or fewer, lowercase, and contain only `a-z` and `0-9`.
:::

:::hint{type="info"}
**Note**
Trace the sync logs in the [Sync logs](https://cg.optimizely.com/app/portal/synclogs) of the portal. Group them in the view by adding a header (`og-job-id`) with the same value in the requests.
:::

### Example

To index data, send the data in NDJSON format. NDJSON is regular JSON separated by new lines. NDJSON streams large amounts of data without parsing everything as one JSON string.

Each data item to index must be prepended with a separate action line:
`{"index": {"_id": 1, "language_routing": "en" }}`

This indicates you want to `index` (the action) the next line in the NDJSON stream. The item has an `_id` of `1` and is in English. Get the `_id` from the content later using GraphQL.

:::hint{type="warning"}
**Important**
Each line of data goes in a pair with actions. If you omit the action line and have several consecutive data lines, the result is unpredictable, and not all data lines are added.

You do not get an error message when sending data like this. You get an error message only if the data cannot be parsed as JSON.
:::

The following example posts information for two products in English to a content source with the ID `com` (short for commerce):

```text
{ "index": { "_id": 1, "language_routing": "en" } }
{ "Id": "1", "Name": "Man shoes", "Quantity": 10, "size": 43, "Color": "Black", "Language": { "DisplayName": "English", "Name": "en" }, "ContentType": ["Catelog", "Product"], "Status": "Published", "RolesWithReadAccess": "Everyone" }
{ "index": { "_id": 2, "language_routing": "en" } }
{ "Id": "2", "Name": "Women shoes", "Quantity": 20, "size": 38, "Color": "Pink", "Language": { "DisplayName": "English", "Name": "en" }, "ContentType": ["Catelog", "Product"], "Status": "Published", "RolesWithReadAccess": "Everyone" }
```

```curl
curl --location 'https://cg.optimizely.com/api/content/v2/data?id=com' \
--header 'Content-Type: text/plain' \
--header 'og-job-id: JOB_ID_HERE' \
--header 'Authorization: Basic BASE64_ENCODED_CREDENTIALS' \
--data '{
    "index": {
        "_id": 1,
        "language_routing": "sv"
    }
}
{
    "Id": "1",
    "Name": "Man shoes",
    "Quantity": 10,
    "size": 43,
    "Color": "Black",
    "Language": {
        "DisplayName": "English",
        "Name": "en"
    },
    "ContentType": ["Catelog", "Product"],
    "Status": "Published",
    "RolesWithReadAccess": "Everyone"
}
{
    "index": {
        "_id": 2,
        "language_routing": "sv"
    }
}
{
    "Id": "2",
    "Name": "Women shoes",
    "Quantity": 20,
    "size": 38,
    "Color": "Pink",
    "Language": {
        "DisplayName": "English",
        "Name": "en"
    },
    "ContentType": ["Catelog", "Product"],
    "Status": "Published",
    "RolesWithReadAccess": "Everyone"
}'
```

## Authorization

The acceptable authorization methods are `Basic` and `epi-hmac`:

`Basic`:

- `Username` – AppKey
- `Password` – Secret

:::hint{type="info"}
**Note**
In Postman, get the basic authentication token by filling in the `Username` and `Password` with the AppKey and Secret in the `Authorization` option. Hover over **Code snippet** to see the basic authentication token, which you can reuse. The value of the basic authentication token starts with `Basic`.
:::

The endpoint lets you send your content data to the Graph service:

`https://cg.optimizely.com/api/content/v2/data?id=<content source ID>`

The `id` query parameter is the ID of your content source. It must match

`epi-hmac`:

- The AppKey and the Secret are signed by the HMAC algorithm.

The following example is a POST request to update content items:

```text
var crypto = require("crypto-js");
var sdk = require('postman-collection');
// This script uses 2 variables.
//
// EPTSKey
// EPTSSecret
//
var method = pm.request.method;
var key = pm.variables.get("EPTSKey");
var secret = CryptoJS.enc.Base64.parse(pm.variables.get("EPTSSecret"));
var target = new sdk.Url(request.url).getPathWithQuery();
var timestamp = (new Date()).getTime();
var nonce = Math.random().toString(36).substring(7);
var body = "";
if( pm.request.body )
{
    body = pm.request.body.raw;
}
var bodybase64 = crypto.MD5(body).toString(CryptoJS.enc.Base64);
var hmac = crypto.HmacSHA256(key + method + target + timestamp + nonce + bodybase64, secret);
var base64hmac = CryptoJS.enc.Base64.stringify(hmac);
var header = "epi-hmac " + key + ":" + timestamp +":" + nonce + ":" + base64hmac;
pm.request.headers.add(header, "Authorization")
```

## Purge content data

:::hint{type="info"}
**Note**
For information, refer to the [Purge content data API reference](https://docs.developers.optimizely.com/platform-optimizely/v1.4.1-optimizely-graph/reference/delete-contentv2datahandler).
:::

The `purge content data` endpoint lets you delete your data from the content source.

### Example

The following example deletes all content from a content source with the ID `cms` for the `en` and `sv` languages.

```curl
curl --location --request DELETE 'https://cg.optimizely.com/api/content/v2/data?id=cms&languages=en&languages=sv' \
--header 'Authorization: Basic BASE64_ENCODED_CREDENTIALS'
```

```text
curl --location --request DELETE 'http://cg.optimizely.com/api/content/v2/data?id=cms&languages=en&languages=sv' \
--header 'Authorization: {{authHeader}}
```

:::hint{type="info"}
**Note**
`authHeader` is the signed HMAC key pair from the [previous Postman script example in the Authorization section](https://docs.developers.optimizely.com/platform-optimizely/v1.4.1-optimizely-graph/docs/synchronize-content-data#authorization).
:::
