# Contentstack

The destination Contentstack connector allows content to be transformed from Motation any synced to Contentstack.

## Specifics

### ID Map Report Convention

IDs in the ID map report for Contentstack uses the following convention.

```
<content-type-uid>::<content-uid>
```

### Endpoint Config

When saving an endpoint for a Contentstack repository via REST intead of the UI you must use the following key:value pairs in the payload.

* `contentRepo:contentstack`
* `contentRepoVersion:v3`

### APIs

Contentstack has both a [CDN](https://www.contentstack.com/docs/developers/apis/content-delivery-api) and [CMA](https://www.contentstack.com/docs/developers/apis/content-management-api) APIs. Access to the CMA API is required for the destination connector. The CDN can be used as well for some calls as it is more efficient for returning results. However, if tokens and URL is not set for the CDN, the CMA will be used.

### Tokens

Contentstack has two types of tokens, [delivery and management tokens](https://www.contentstack.com/docs/developers/create-tokens/overview-of-tokens/). The destination connector **requires** **a management token**. If a delivery token is provided, some calls will be made to the CDN.

### Base URL

The base URL for CMA must be provided in the adapter properties. Base URL values can be found in Contentstack's documentation ([CMA](https://www.contentstack.com/docs/developers/apis/content-management-api/#base-url), [CDN](https://www.contentstack.com/docs/developers/apis/content-delivery-api/#base-url)). The CMA base URL should always be provided.

### Mapping References

Contentstack supports a single field referencing multiple different content types. **System properties** are required to fully map a reference field to multiple content types. The key `ImpulseSync_Referenced_Content_Type_Mapping` take a JSON object as a value to map source content types to destination content types.&#x20;

i.e., If a source reference field references content from `keywords` and `news` but the destination field references `new_keywords` and `articles` you can add **system properties** to the field as follows.

```
{"ImpulseSync_Referenced_Content_Type_Mapping": {"keywords": "new_keywords"}}
```

and

```
{"ImpulseSync_Referenced_Content_Type_Mapping": {"news": "articles"}}
```

This will map the reference to `keywords` to `new_keywords` and the reference to `news` to `articles`.

Best practice is to set a system property for every referenced content type that does not exactly match. (`keywords` to `keywords` does not need a system property map but `keywords` to `news_keywords` does even if no entries currently have a reference to that content type)

**Note:** when Contentstack is the source, you can simply use the nested JSON object.&#x20;

```
{"keywords": "new_keywords"}
```

and

```
{"news": "articles"}
```

### Creating a new reference field in the content

#### Setting the content type to reference

When a reference/relationship field is created in the content through a manipulator (i.e., liquid field manipulator), you will need to add the following system property.&#x20;

```
impulse-relationship-manipulator-related-content-type
```

i.e.,&#x20;

```
{"impulse-relationship-manipulator-related-content-type": "content_type_to_reference"}
```

This will ensure the Contentstack destination's reference field will reference the content type configured in the system property.&#x20;

This only supports a single content type to be referenced.&#x20;

#### group/global nested reference field

If you are creating a reference field that is nested in a group/global field you need to add the group/global field to the content using a manipulator. i.e., the add-replace manipulator.&#x20;

This will allow the connector to set the value for the nested field appropriately in the group/global field.&#x20;

This field also needs the field system type "global\_field" or "group" as appropriate. The field type of the field is "System".&#x20;

It is suggested that this manipulator be run before the manipulator to create the reference field runs.&#x20;

An example of creating this field group/global field can be found below.&#x20;

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2F8kt9xpPFHkqui07u6Qfc%2Fimage.png?alt=media&#x26;token=252a16ec-4640-43cf-92df-9f6de7a6ecd1" alt=""><figcaption></figcaption></figure>

### Mapping Global and Group fields

#### Mapping to another global/group field

Contentstack's global and group fields require a system property to map a change in name between source and destination Contentstack stacks.

This can also allow you to map a source field that is not part of a global or group field into a destination group/global field.

A dot pathing notation is used to refer to a field **inside** a global or group field.

#### Unique ID

**Example: Unique ID for field inside Global/Group**

```
"uniqueId": "global_group_uid.inner_field_uid"
```

**Example: Unique ID for field inside nested Global/Group**

```
"uniqueId": "global_group_uid.nested_global_group_uid.inner_field_uid"
```

#### System property (not recommended)

**NOTE**: When using the system property to set a global/group field the unique ID must **not** use dot pathing ('.' in the value). Instead, the Unique ID would only be the UID of the inner most field (i.e., `inner_field_uid`). This system property is **not** the recommend mapping. Instead use the Unique ID with dot pathing as explained above.

Be aware that field to add to the content mapping is the field **inside** the global or group field. Then add the system property to that field with the uid of the destination global or group field. Mapping the global or group field directly is not supported. Instead, map the inner fields of the over arching global or group field and add the system property for the destination global/group field uid.

**Example: Global system property**

```
{"global_field": "my_destination_global_uid"}
```

**Example: Group system property**

```
{"group": "my_destination_group_uid"}
```

**Example: Nested Global/Group system property**

```
{"global_field": "my_destination_global_uid.nested_global_uid"}
```

```
{"group": "my_destination_group_uid.nested_group_uid"}
```

#### Mapping from global/group to non global/group field

When mapping from a source global or group field and the destination is not a global or group field you will need to perform two steps.

1. You will need to set the appropriate unique IDs.

The origin unique ID will include a dot pathing as stated above. And the destination will **not** include a dot pathing since there is no global/group field at the destination.

#### Example origin

```
"uniqueId": "my_source_global_uid.nested_field_uid"
```

#### Example mapping

```
"uniqueId": "unnested_field_uid"
```

1. You will need to set a system property for `global_field` or `group` as an empty string.

#### Example removing global/group field

```
{"global_field": ""}
```

```
{"group": ""}
```

### Mapping Select with Number data type

Contentstack's `Select` field type allows for either `Text` or `Number` data type. The `Text` data type is the default behavior for syncing a `Select` value. However `Number` can be forced by adding a system property to the mapping for the field. This is not required when syncing between two Contentstack systems and both the source and destination field are `Select` with data type `Number`.

**Example: Select Number data type**

```
{"data_type": "Number"}
```

### Mapping Modular Block fields

Contentstack modular block field is only supported when syncing from a source Contentstack system. To map the modular block field and it's inner fields system properties are required to be set in the content mapper for each field.

A modular block has a few parts:

1. The modular block field itself
2. The individual blocks of a modular block
3. The inner fields of each block

#### Mapping Modular Block field

To map the modular block field simply add it to the content mapper as you would a regular field.

Map the origin.uniqueId and mapping.uniqueId as appropriate.

Set `fieldType` to "System".

#### Mapping Individual Blocks

To map a change in UID of each individual block add a system property to the main modular block field created above.

If source modular block has a block with UID `sub_menu` and the destination modular block has a block with UID `main_submenu` set a system property as follows:

```
{"sub_menu": "main_submenu"}
```

Add as many system properties as required for changed blocks to the modular block field in the content mapper.

#### Mapping Inner Fields

To map a change in UID of an inner field add a **new** field to the content mapper. This field is separate from the previous modular block field.

This field should be mapped similar to a regular field, except the `uniqueIds` follow a "dot pathing" instead.

For instance, lets assume there is a modular block field `menu_items` and it has the block `sub_menu` with the field `title`. But the destination requires a map from `title` to `headline`. The following values should be used.

Origin Unique ID:

```
menu_items.sub_menu.title
```

Mapping Unique ID:

```
menu_items.sub_menu.headline
```

This dot pathing also includes the UID of the global or group a field is part of. If the field `title` is in the group `menu_group` the Origin Unique ID would be as follows:

```
menu_items.sub_menu.menu_group.title
```

Without the proper origin unique ID, the mapping will not take effect. Be careful to use the correct unique ID value for modular block fields.

This inner field mapping can have system properties for mapping group and global fields in the same way a regular field would.

i.e., if `menu_group` should be mapped to `sub_menu_group` add the following value as a system property.

```
{"group": "sub_menu_group"}
```

**NOTE**: Nested group and global fields within a modular block fields is unofficially supported. While it may work in select cases, it is likely that it will not work.

### Folders with non-alphanumeric characters

Folders that have non-alphanumeric characters in their name are not supported in Contentstack. As a result those folders will be renamed by removing the non-alphanumeric characters.

However, this will result in files in those folders to be synced to the incorrect location.

The recommended use case is to remove all non-alphanumeric characters from folder names before syncing.

### Publishing entries

To publish entries Contentstack requires an environment. When the job option `environment`is set, a request will be made to publish entries to that environment. Be careful to populate all required fields when using the `environment` option. Otherwise, Contentstack will fail to publish the entry.

### Key/Value select field

Contentstack allows for setting Key/Value pairs for the select field. The value to be used in the content is the "Value" set in Contentstack as the Key/Value pair. This specifically applies when using a Motator to adjust values. Without a valid select value set in the content, the content will not sync.

### Mapping Assets

Only one asset will be created per Motation of type `File`.

A binary field will be automatically from the Motation of type `File` will be used as the binary of the asset.

Other than the binary field, Assets have the following fields in Motation that can be mapped to.

* Title
  * Type: String
  * Unique Name: title
  * The title of the asset
* Permanent URL
  * Type: String
  * Unique Name: permanent\_url
  * The permanent url of the asset. This value will follow the rules for Contentstack uses for generating a permanent url with the value.
* Content Type
  * Type: String
  * Unique Name: content\_type
  * The content type or mime type of the asset
* Description
  * Type: Textarea
  * Unique Name: description
  * The description for the asset
* Tags
  * Type: Array
  * Unique Name: tags
  * The tags for an asset
  * Note: tags are not supported from other systems

### Ignoring a field

To ignore a field you can set the mapping unique ID to a value that does not exist and will not exist in the destination Contentstack system.

i.e., You can set the value to `completelyignoredvaluetoneverset` as seen in the following example image.

![](https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FC2TgAa2xTOYsPxlgy6i6%2Fimage.png?alt=media\&token=16110219-bdfa-4927-9532-f017925fc470)

This value set cannot exist in the destination Contentstack system during the time of the sync. Otherwise it would treat it like a regular mapping.

The value set should also not exist in the future for the destination Contentstack system. This may cause unexpected conflicts if the value used to ignore the mapping is later added as a field in the destination Contentstack system.

### URL field

The URL field can be synced into by using the "String" field type in the content mapper. However be aware that Contentstack has special rules for the URL field that may alter the destination value. Be aware of what rules are set for the field in the content type to avoid any unexpected values.

### Syncing group/global fields with multiple property

When a group or global field has the [multiple property](https://www.contentstack.com/docs/developers/create-content-types/multiple/) set in the content model in Contentstack, there are special rules to syncing and mapping these properties.

#### Convention

Group/Global fields with the multiple property expect each instance of the nested fields explicitly set. Each instance is treated as an individual field in the content. Each field unique ID expects following string value appended `--#` .

i.e., `{{group.field}}--0` , `{{group.field}}--1` , `{{group.field}}--2`

#### requirements

1. All fields nested in the group/global field **must be mapped**. Any field not mapped will be ignored by default.
2. If syncing from Contentstack to Contentstack, only `{{group.field}}--0` requires a mapping.
3. If syncing from Contentstack to Contentstack, the `mapping.uniqueId` must be `{{old-group.old-field}}->{{new-group.new-field}}`
4. If syncing from another system to Contentstack the appended number must start at 0, then iterate from there.

#### limitations

* The string value `->` cannot be part of the field unique ID.
* The string value `--#` cannot be part of the field unique ID.
* Only a single group/global field with the `multiple` property is supported. Nested group/global fields **each** with the `multiple` property **are not supported**.

### Creating a link field

Creating a link field in Contentstack destination requires being able to set multiple values to a field.&#x20;

The first value of the field is the `url` of the link field while the second value of the field is the `title` of the link field.&#x20;

The field type is `System` .&#x20;

The field system type is `link` .&#x20;

#### example

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FEZ7TSG18kiWLv2Gd1O0J%2Fimage.png?alt=media&#x26;token=9450915a-4551-4430-8e9a-c2eb491369bb" alt=""><figcaption></figcaption></figure>

#### multiple

If the link field is multiple the url and title values are paired. Meaning every odd numbered value is the `url` of the link field, and every even numbered value is the `title` of the link field.&#x20;

Additionally, the following system property must be set.&#x20;

```
{"multiple":"true"}
```

### Pickup Date time

Setting a time zone is not supported. You must provide the time for the time zone the system uses.

### Syncing folders

When syncing folders, the connector will first check if the folder exists by ID. If it does not exist by ID, then it will check by name. If the folder does not exist by name, a new folder will be created.&#x20;

If the folder does exist by ID or name , the folder will be updated. This can cause nested folders with the same name as a non nested folder to update the non-nested folder to become a nested folder. This may also cause assets that live in a folder with the same name, (but different paths at the source system) to be synced to the same folder.

### Unsupported

Syncing content types. A content type should be created prior to a sync and the content mapper used to map incoming content to the existing content type.

Syncing global field content model. The values of entries using global fields are synced but the content model of the global field is not synced. Global fields should be created prior to a sync and the content mapper used to map into global fields as documented under `Mapping Global and Group fields` section.

Nested Group/Global fields within modular block fields.

Nested Modular Block fields.

Multiple value fields.

Proper folder hierarchy from other systems.

Tags and categories.

Syncing multiple file references to a single field (i.e., strapi multiple file field to Contentstack file field). Only the first file will be set as the value.

[Additional metadata](https://www.contentstack.com/docs/content-managers/working-with-entries/additional-metadata-support-for-entries/)

Modular block fields to non modular block fields. This is not officially supported and may have unintended side effects if it does sync.

## Adapter Properties

| Property           | Purpose                                                                                                                                    |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| authToken          | The delivery token to use Contentstack's CDN API.                                                                                          |
| managementToken    | The content management token to use Contentstack's CMA API.                                                                                |
| branch             | The branch to pickup content from.                                                                                                         |
| apiKey             | The API Key for the stack to pickup content from.                                                                                          |
| CMABaseURL         | The [base URL](https://www.contentstack.com/docs/developers/apis/content-management-api/#base-url) to access Contentstack's CMA API.       |
| CDNBaseURL         | The [base URL](https://www.contentstack.com/docs/developers/apis/content-delivery-api/#base-url) to access Contentstack's CDN API.         |
| rateLimitPerSecond | It is used to control the rate at which certain operations can be executed to prevent excessive usage or abuse of resources (default: 10). |

## Job options

<table><thead><tr><th>Name</th><th>Description</th><th>Data Type</th><th>Required</th><th>Default Value</th><th data-hidden></th></tr></thead><tbody><tr><td>contentType</td><td>The content type to pickup content IDs from.</td><td>Text</td><td>No</td><td>No Default Value</td><td></td></tr><tr><td>branch</td><td>The branch to sync content to.</td><td>Text</td><td>No</td><td>No Default Value</td><td></td></tr><tr><td>environment</td><td>The environment to sync content to.</td><td>Text</td><td>No</td><td>No Default Value</td><td></td></tr><tr><td>apiKey</td><td>The API Key of the stack to sync content to.</td><td>Text</td><td>Yes</td><td>No Default Value</td><td></td></tr><tr><td>assetTitleAsID</td><td>Whether the asset title should be used as an identifier when syncing.</td><td>Boolean</td><td>No</td><td>false</td><td></td></tr><tr><td>query</td><td>A json object with values to query content to pick up. Follow the <a href="https://www.contentstack.com/docs/developers/apis/content-delivery-api/#queries">contentstack API doc on querying</a> for formatting and options. Only queries that are a value for the key "query" can be used.</td><td>Text</td><td>No</td><td></td><td></td></tr></tbody></table>

### *apiKey* Job Option

The value of the `apiKey` job option should match the API Key generated for the stack that content should be delivered into.

### *contentType* Job Option

The value of the `contentType` job option should match the Content Type UID from Contentstack for the content type being checked/synced to.

```
contentType:restraunt
```

### *branch* Job Option

The value of the `branch` job option should match the name of the branch content should be delivered to in the stack.

```
branch:mybranch
```

### *environment* Job Option

The value of the `environment` job option should match the name of the environment content should be delivered to in the stack.

```
environment:staging
```

### *assetTitleAsID* Job Option

When `assetTitleAsID` is set to true, the title of the asset will be used as an identifier when syncing the asset. Meaning if an asset already exists at the path with the same title, the existing asset will be updated and a new asset will not be created.

When `assetTitleAsID` is set to false, the title of the asset will **not** be used as an identifier when syncing the asset. Meaning if an asset already exists at the path with the same title, a new asset will be created with a duplicate title.

**Note:** When `assetTitleAsID` is set to false, due to the asynchrounous nature of Impulse, if multiple assets are synced with the same title and no asset exists in the destination with that title, there is a chance that multiple assets will be created at the destination with the same title.

```
assetTitleAsID:true
```

### *query* Job Option

The value to set is a JSON object with values that can be set for the "query" parameter key in a Contentstack CMA call. View this section of the [Contentstack API doc](https://www.contentstack.com/docs/developers/apis/content-delivery-api/#queries) for query values and options.

Because only options that are values of the "query" parameter are valid, queries such as pagination and include are not valid options.

**example using regex:**

```
{"title":{"$regex":"PROD"}}
```

## Troubleshooting
