---
title: Sync content types for external data
slug: graph/docs/sync-content-types-for-external-data
docTags: 
createdAt: 2026-07-30T20:30:19.179Z
---

Optimizely Graph provides endpoints that let you define the GraphQL schema of your content source. The schema is important for the data you [upload](https://docs.developers.optimizely.com/platform-optimizely/v1.4.1-optimizely-graph/reference/synchronize-content-data) to the Optimizely Graph service.

:::hint{type="warning"}
**Important**
This feature is not enabled by default for your account. Contact Optimizely to request additional sources.
:::

## Before you begin

Review the following constraints:

- Content type names must be unique across all sources.
- External content types must not conflict with CMS content types.
- Syncing a full content definition replaces the entire schema for the source.

For API details, see the [Full content type update API reference](https://docs.developers.optimizely.com/platform-optimizely/v1.4.1-optimizely-graph/reference/put-contentv3typehandler).

## Sync full content definition

Use the full content type endpoint to upload a complete schema definition for a content source. This operation creates or replaces the schema associated with the specified source ID.

:::hint{type="info"}
**Note**
The schema does not work if several content types have the same name across sources. Content type names from external sources must be unique and must not conflict with content type names in CMS.
:::

The `full content type` API endpoint lets you sync the full definition of your content to the service.

```curl
curl --request PUT \
  'https://dev.cg.optimizely.com/api/content/v3/types?id=src2' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Basic <Base64(AppKey:Secret)>' \
  --data '{
    "languages": ["en"],
    "contentTypes": {
      "test": {
        "contentType": [],
        "properties": {
          "Name": {
            "type": "String"
          }
        }
      }
    }
  }'
```

```csharp
var client = new HttpClient();
var request = new HttpRequestMessage(
    HttpMethod.Put,
    "https://dev.cg.optimizely.com/api/content/v3/types?id=src2"
);

request.Headers.Add("Authorization", "Basic <Base64(AppKey:Secret)>");

request.Content = new StringContent(
@"{
  ""languages"": [""en""],
  ""contentTypes"": {
    ""test"": {
      ""contentType"": [],
      ""properties"": {
        ""Name"": { ""type"": ""String"" }
      }
    }
  }
}",
Encoding.UTF8,
"application/json"
);

var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
```

- `id=src2` – Source name, four characters or fewer.
- `languages` – Required and not empty.
- `contentTypes` – Required and not empty.
- `test` – Content type name.
- `contentType` – Required.
- `properties` – Required and not empty.

The previous request creates a `src2` data source and a GraphQL schema that matches the content type.

:::hint{type="warning"}
**Important**
If you upload a full content definition using the `full content type` API endpoint, all data in the content source is deleted.
:::

### Example: Define a product catalog schema

The following example shows how to define property types, languages, and content types for a content source that contains product information. It uses simple data types in addition to the `ProductLanguage` property type.

```json
{
    "propertyTypes": {
        "ProductLanguage": {
            "properties": {
                "DisplayName": {
                    "name": "DisplayName",
                    "type": "String"
                },
                "Name": {
                    "name": "Name",
                    "type": "String"
                }
            }
        }
    },
    "label": "Commerce",
    "languages": [
        "en"
    ],
    "contentTypes": {
        "Catalog": {
            "abstract": true,
            "contentType": [],
            "properties": {
                "Id": {
                    "type": "String"
                },
                "Name": {
                    "type": "String"
                }
            }
        },
        "Product": {
            "contentType": [
                "Catalog"
            ],
            "properties": {
                "Id": {
                    "type": "String"
                },
                "Name": {
                    "type": "String"
                },
                "Language":{ 
                    "type": "ProductLanguage"
                },
                "Quantity": {
                    "type": "Int"
                },
                "Size": {
                    "type": "Float"
                },
                "Color": {
                    "type": "String"
                }
            }
        }
    }
}
```

To make a property point at another content item instead of holding a value, add a `ref` object to the property. For details, see [Reference properties](https://docs.developers.optimizely.com/platform-optimizely/v1.4.1-optimizely-graph/docs/reference-properties).

The following `curl` command issues a `PUT` request with the definition using the ID `com`, which is the name of the content source. If the content source does not exist, the request creates it.

:::hint{type="warning"}
**Important**
If you create more content sources than your account allows, the call fails, and the content source is not created.
:::

```curl
curl --location --request PUT 'https://cg.optimizely.com/api/content/v3/types?id=com' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <Base64(AppKey:Secret)>' \
--data '{
    "propertyTypes": {
        "ProductLanguage": {
            "properties": {
                "DisplayName": {
                    "name": "DisplayName",
                    "type": "String"
                },
                "Name": {
                    "name": "Name",
                    "type": "String"
                }
            }
        }
    },
    "label": "Commerce",
    "languages": [
        "sv"
    ],
    "contentTypes": {
        "Catalog": {
            "abstract": true,
            "contentType": [],
            "properties": {
                "Id": {
                    "type": "String"
                },
                "Name": {
                    "type": "String"
                }
            }
        },
        "Product": {
            "contentType": [
                "Catalog"
            ],
            "properties": {
                "Id": {
                    "type": "String"
                },
                "Name": {
                    "type": "String"
                },
                "Language":{ 
                    "type": "ProductLanguage"
                },
                "Quantity": {
                    "type": "Int"
                },
                "Size": {
                    "type": "Float"
                },
                "Color": {
                    "type": "String"
                }
            }
        }
    }
}'
```

### Authorization

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

`Basic`:

- **Username** – AppKey
- **Password** – Secret

Both the username and password must be encoded with the Base64 algorithm, so the header is `Authorization: Basic base64(AppKey:Secret)`.

`epi-hmac` – The AppKey and the Secret are signed by the HMAC algorithm.

```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")
```

## Sync partial content type

The `Partial content type` endpoint lets you sync the partial content type to the service.

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

You must call [sync full content type](https://docs.developers.optimizely.com/platform-optimizely/v1.4.1-optimizely-graph/docs/sync-content-types-for-external-data#synchronize-full-content-type) before using this endpoint to update a partial content type.
:::

### Example: Make a field searchable

The following example updates the `Product` content type by marking the `Name` property as searchable:

```json
{
    "languages": [
        "en"
    ],
    "contentTypes": {
        "Product": {
            "contentType": [
                "Catalog"
            ],
            "properties": {
                "Id": {
                    "type": "String"
                },
                "Name": {
                    "type": "String",
                  	"searchable": true
                },
                "Language":{ 
                    "type": "ProductLanguage"
                },
                "Quantity": {
                    "type": "Int"
                },
                "Size": {
                    "type": "Float"
                },
                "Color": {
                    "type": "String"
                }
            }
        }
    }
}
```

Again, send the data to the `types` endpoint, but use `POST` instead of `PUT`. The request uses the `com` ID to specify the target content source.

```curl
curl --location 'https://cg.optimizely.com/api/content/v3/types?id=com' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic <Base64(AppKey:Secret)>' \
--data '{
    "languages": [
        "en"
    ],
    "contentTypes": {
        "Product": {
            "contentType": [
                "Catalog"
            ],
            "properties": {
                "Id": {
                    "type": "String"
                },
                "Name": {
                    "type": "String",
                  	"searchable": true
                },
                "Language":{ 
                    "type": "ProductLanguage"
                },
                "Quantity": {
                    "type": "Int"
                },
                "Size": {
                    "type": "Float"
                },
                "Color": {
                    "type": "String"
                }
            }
        }
    }
}'
```
