HomeDev guideRecipesAPI Reference
Dev guideUser GuidesLegal TermsNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev guide

Synchronize content types

With custom content sources, you can add custom data to Optimizely Graph and query using the GraphQL API.

Optimizely Graph provides endpoints to let you define the GraphQL schema of your content source. The schema is important for the data you upload to the Optimizely Graph service.

🚧

Important

This feature is not enabled by default for your account. Contact Optimizely with a request to get additional sources.

Synchronize full content definition

📘

Note

The schema does not work if several content types have the same name across sources. You must have unique names on the content types from external sources that do not conflict with content types in CMS.

For information, refer to the Full content type update API reference.

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

curl --location --request PUT 'https://dev.cg.optimizely.com/api/content/v3/types?id=MyNewSource' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic V25KQmNtUlpSNTFYaDJuSmE345UWV5eEkwWWxOUVpFhjkdWsxMDRWV1BYZkcydlcxZUluOlduSkJjbVJaUjUxWGgybkphNVFleXhJMFlsTlFaRXVrMTA0VldQWGZHMnZXMWVJbg==' \
--data '{
 "languages": ["en"],
 "contentTypes":{
   "test": {
     "contentType": [],
     "properties": {
       "Name": {
        "type": "String"
       }
     }
   }
 }
}
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Put, "https://dev.cg.optimizely.com/api/content/v3/types?id=,quang");
request.Headers.Add("Authorization", "Basic V25KQmNtUlpSNTFYaDJuSmEghjU0WdgV5eEkwWWxOUVpFdWsxMDRWV1BYZkcydlcxZUluOlduSkJjbVJaUjUxWGgybkphNVFleXhJMFlsTlFaRXVrMTA0VldQWGZHMnZXMWVJbg==");
var content = new StringContent("{\n \"languages\": [\"en\"],\n \"contentTypes\":{\n   \"test\": {\n     \"contentType\": [],\n     \"properties\": {\n       \"Name\": {\n        \"type\": \"String\"\n       }\n     }\n   }\n }\n}", null, "application/json");
request.Content = content;
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());
  • id=MyNewSource – Source name.
  • languages – Required and not empty.
  • contentTypes – Required and not empty.
  • test – Content type name.
  • contentType – Required.
  • properties – Required and not empty.

The above request creates a MyNewSource datasource and a GraphQL schema that matches the content type.

🚧

Important

If you upload a full content definition using the full content type API endpoint, all data in the content source is deleted.

Example

The following example shows how to define property types, languages, and content types for a content source containing product information. It shows the use of simple data types in addition to the ProductLanguage property type.

{
    "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"
                }
            }
        }
    }
}

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 already, it is created.

🚧

Important

If you create more content sources than your account lets you, the call will fail, and the content source will not be created.

curl --location --request PUT 'https://cg.optimizely.com/api/content/v3/types?id=com' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic V25KQmNtUlpSNTFYaDJuSmE1UWV5eEkwWWxOUVpFdWsxMDRWV1BYZkcydlcxZUluOkYwaWRhcDRPQ1ZOc0JSQTJmdVpCVDNtYXVoaVl1QWtRcDM5SHduazB2dW1XblpoZytjbmg4QnpHVU5VQlVIYTM=' \
--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 is Basic and epi-hmac:

Basic:

  • Username – AppKey
  • Password – Secret

Both the username and password must be encoded by 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.

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

Synchronize partial content type

📘

Note

Refer to the API Reference on Partial content type update for information.

You must call synchronize full content type before using this endpoint to update partial content type.

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

Example

The following example changes the Name to be searchable by adding searchable to the Name property :
"Name": { "type": "String", "searchable": true }

{
    "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, the data is being sent to the types endpoint but using POST instead of PUT. It uses the com ID to specify the target content source.

curl --location 'https://cg.optimizely.com/api/content/v3/types?id=com' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic V25KQmNtUlpSNTFYaDJuSmE1UWV5eEkwWWxOUVpFdWsxMDRWV1BYZkcydlcxZUluOkYwaWRhcDRPQ1ZOc0JSQTJmdVpCVDNtYXVoaVl1QWtRcDM5SHduazB2dW1XblpoZytjbmg4QnpHVU5VQlVIYTM=' \
--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"
                }
            }
        }
    }
}'