---
title: Examples of Content Management API
slug: cms-12/api/api-fundamentals
docTags: 
createdAt: 2026-08-07T16:45:43.000Z
---

To keep the examples short, they generally favor using integer-based content references instead of GUIDs. The following example gets content by given content URL or by a list of GUID or Reference with a given language.

- `GET /api/episerver/v3.0/content`

Be aware:

- The API implicitly uses the primary draft when changing and publishing content.
- Manipulating personalization in content areas is not currently supported. For example, you cannot change or add a specific visitor group on a specific item in a content area through the Optimizely Content Management API.
- `ContentReference` in endpoints should not include `workID` (for example, `5_5`). An exception is thrown if `workID` is included.

## A simple content sync

The simplest way to push content to the CMS is to assume the integration process always has right-of-way and that no one else is making significant changes to the same part of the content tree. With these limitations in mind, you can use `PUT` to upsert objects, which will overwrite existing content:

- `PUT /api/episerver/v3.0/contentmanagement/{contentGuid}`

```curl
curl --location --request PUT "http://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement/7fa446db-6e02-41c5-9d3a-06e1b4d75cdf" ^ 
--header "Content-Type: application/json" ^
--header "Authorization: Bearer <AUTH_TOKEN>" ^
--data-raw "{'name': 'Alloy Track','language': {'name': 'sv'},'contentType':['ProductPage'],'parentLink': {'id': 5},'status': 'CheckedOut','metaTitle': {'value': 'Alloy Track Updated'},'uniqueSellingPoints': {'value': ['Shared timeline','Project emails','To-do lists','Workflows','Status reports']}}"
```

You can rely on `PUT` to control the incoming content and specify `Published` status from the API to publish the content directly. Using the default `CheckedOut` status requires another manual or API action to publish changes. You can use the endpoint to create an existing content item in a specific language.

## A smarter content sync

Upserts are easy to work with but can be wasteful when an entire object is sent, even when a single property is updated. You can build a more efficient integration with POST and `PATCH` (instead of PUT) to determine when an object is new or changed (and which properties were changed) in the source system.

### Create content

You create a content item by POSTing an object. Use this POST endpoint to create an existing content item in a specific language.

**Endpoint** – `POST /api/episerver/v3.0/contentmanagement`

```bash
curl --location --request POST "http://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer <AUTH_TOKEN>" \
--data-raw "{'name': 'Alloy Track','language': {'name': 'sv'},'contentType': ['ProductPage'],'parentLink': {'id': 5},'status': 'CheckedOut','metaTitle': {'value': 'Alloy Track SV'},'uniqueSellingPoints': {'value': ['Shared timeline','Project emails','To-do lists','Workflows','Status reports']}}"
```

### Update content

Save changes to an existing object by PATCHing an object, which accepts a partial object and only applies changes to the properties included in the payload. For example, if the title of a content object is changed, `PATCH` can specify just that one property in its payload.

**Endpoint** – `PATCH /api/episerver/v3.0/contentmanagement/{contentReference}`

```bash
curl --location --request PATCH "http://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement/116" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer <AUTH_TOKEN>" \
--data-raw "{'name': 'Alloy Track','language': {'name': 'en'},'metaTitle': {'value': 'Alloy Track Patched'}}"
```

### PATCH guidelines

- PATCH only values for culture invariant properties in the master language. That means if you want to update content in a specific language other than the master language, then you must omit culture invariant properties.
- Pass only **Language** in the request body if the content type is localizable.
- Set route segment only for the content that is IRoutable.
- Set **StartPublish**, **StopPublish**, or **Status** only for content that is versionable.
- Set **StartPublish** when a content item is set for scheduled publishing.
- Ignore validation of content by setting the header **x-epi-validation-mode** to **minimal**.

## Translate content

When translating content to another language, you should first GET the object in the source language and use that as a template object for the translated content. To use this endpoint, clients must have at least one more privilege higher than Read privilege.

### Get source content

**Endpoint** – `GET /api/episerver/v3.0/contentmanagement/{contentReference}`

```bash
curl --location --request GET "http://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement/116" \
--header "Authorization: Bearer <AUTH_TOKEN>"
```

### Creating Translated Content

Language variations of content are treated as separate content objects with shared culture-invariant properties. That means a newly translated object is POSTed and should specify the correct target language.

**Endpoint** – `POST /api/episerver/v3.0/contentmanagement`

```bash
curl --location --request POST "http://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement/116" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer <AUTH_TOKEN>" \
--data-raw "{'name': 'Alloy Track','language': {'name': 'sv'},'contentType': ['ProductPage'],'parentLink': {'id': 5},'status': 'CheckedOut','metaTitle': {'value': 'Alloy Track SV'},'uniqueSellingPoints': {'value': ['Shared timeline','Project emails','To-do lists','Workflows','Status reports']}}"
```

**Note:** You can set values only for non-branch-specific properties in the master language. When translating content you should omit culture invariant properties.

## Move Content

The location of content in the content tree is not a mutable property of the content object. Instead of using PUT or PATCH for the object location, a separate endpoint lets you move content to another location in the hierarchy.

**Endpoint** – `POST /api/episerver/v3.0/contentmanagement/{contentGuid}/move`

```bash
curl --location --request POST "http://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement/116/move" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer <AUTH_TOKEN>" \
--data-raw "{'parentLink': {'id': 6},'routeSegment': 'new-segment'}"
```

:::hint{type="info"}
**Note**
System content items such as `RootPage` and `GlobalAssetsRoot` cannot be moved.
:::

## Delete Content

The DELETE request places content in the trash. The content is permanently deleted if you use a DELETE request on content already in the trash. You can skip the trash bin and permanently delete an object by setting the `x-epi-permanent-delete` header to true.

**Endpoint** – `DELETE /api/episerver/v3.0/contentmanagement/{contentReference}`

```bash
curl --location --request DELETE "http://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement/115" \
--header "Authorization: Bearer <AUTH_TOKEN>"
```

:::hint{type="info"}
**Note**
You cannot delete system content such as `RootPage` and `GlobalAssetsRoot`.
:::

## Create Media Content

To create a media object in CMS, send a POST multi-part form-data request with the required headers and parameters to the endpoint. The request body consists of two parts:

- One part must be named content. The body contains property values of media content and its metadata in JSON format. This is similar to the JSON value of a regular content object.
- The other part contains the media filename and its binary data. This filename must be the same as the name given in the previous part.
- If the content part and binary part exist in the request, the filename and name property in the content part need to be the same, or an exception is thrown.

**Endpoint** – `POST /api/episerver/v3.0/contentmanagement`

```bash
curl --location --request POST "https://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement" \
--header "Authorization: Bearer <AUTH_TOKEN>" \
--form "content={'name': 'sample-image.jpg', 'contentType': ['ImageFile'], 'parentLink': {'id': 7}, 'status': 'published'}" \
--form "file=@\"<PATH_TO_FILE>\""
```

## Update Media Content

Send a `PATCH` multi-part form-data request bundled with only updated data to the endpoint to partially update media content.

- If the content part and binary part exist in the request, the filename and name property in the content part must be the same. Otherwise, an exception is thrown.
- To only patch the binary data, send a `PATCH` multi-part form-data request with the binary data as a single part. The file extension should match the existing one. Only binary data is updated, and the filename is not impacted.
- To patch the media content's properties or metadata, send a `PATCH` multi-part form-data request with the updated data in the content part only without the binary part.
- When an Optimizely Content Management System (CMS) content type can be of several extensions, such as an ImageFile file extension that can be .jpg or .png, you can update from one extension to the other.

**Endpoint** – `PATCH /api/episerver/v3.0/contentmanagement/{contentReference}`

```bash
curl --location --request PATCH "https://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement/<EXISTING_CONTENT_ID_OR_GUID>" \
--header "Authorization: Bearer <AUTH_TOKEN>" \
--form "content={'name': 'another-image.jpg', 'status': 'published'}"
```

## Create or Update Media Content

The Media content can be created or updated by sending a PUT request to the endpoint.

- If the media content already exists, then this endpoint updates the content media object. In contrast to `PATCH`, full content media data is sent to the endpoint in this case.
- If it does not exist, a media content object is created. This endpoint cannot be used to update the content hierarchy.

**Endpoint** – `PUT /api/episerver/v3.0/contentmanagement/{contentGuid}`

```bash
curl --location --request PUT "https://<YOUR_DOMAIN>/api/episerver/v3.0/contentmanagement/<CONTENT_GUID>" \
--header "Authorization: Bearer <AUTH_TOKEN>" \
--form "content={'name': 'sample-image.jpg', 'contentType': ['ImageFile'], 'parentLink': {'id': 44}, 'status': 'published'}" \
--form "file=@\"<PATH_TO_FILE>\""
```
