The Content Workflow API allows you to perform an available lifecycle or workflow action on a content object, things like saving, updating, translating, archiving and deleting. The API allows you to specify a specific workflow action you would like to perform or you can call a standard content lifecycle action.
There are 3 main Content Workflow API endpoints that should be used for all content operations.
Content Workflow | Description | |
---|---|---|
Content Lifecycle Actions | Executes the specified content lifecycle action. You can map each of these content lifecycle events to specific workflow actions. Default Workflow Action for the content (as specified in the Content Type of the content). These default lifecycle actions can be one of the following: NEW, EDIT, PUBLISH, UNPUBLISH, ARCHIVE, UNARCHIVE, DELETE or DESTROY. | |
Fire Workflow Action by Name | Executes the Workflow Action specified by name in the request body. | |
Fire Workflow Action by Id | Executes the Workflow Action specified in the URI. |
Content Lifecycle Actions
The default fire /api/v1/workflow/actions/default/fire/_{defaultAction}_
api gives developers consistent endpoints to perform standard content lifecycle operations. Importantly (and optionally) each of these DEFAULT actions can map content lifecycle action to a specific workflow action, which can be modified to perform additional processing. dotCMS administrators can set a workflow's Default Actions that execute when a content object is PUT against these endpoints. If there is no default lifecycle action specified for content type or the content types workflow, the content will perform the standard content lifecycle event - SAVE/PUBLISH/UNPUBLISH/DELETE and return normally
Available Lifecycle Actions
Lifecycle Action | Use when |
---|---|
NEW | Creating new content |
EDIT | Editing content |
PUBLISH | Publishing content |
UNPUBLISH | Unpublishing content |
ARCHIVE | Archiving content |
UNARCHIVE | Unarchiving content |
DELETE | Deleting all versions of a content in a single specified language |
DESTROY | Deleting all versions of a content in ALL languages |
All lifecycle actions are called by lifecycle action name, e.g.
PUT /api/v1/workflow/actions/default/fire/SAVE {...}
PUT /api/v1/workflow/actions/default/fire/EDIT {...}
PUT /api/v1/workflow/actions/default/fire/PUBLISH {...}
PUT /api/v1/workflow/actions/default/fire/UNPUBLISH {...}
PUT /api/v1/workflow/actions/default/fire/ARCHIVE {...}
PUT /api/v1/workflow/actions/default/fire/UNARCHIVE {...}
PUT /api/v1/workflow/actions/default/fire/DELETE {...}
PUT /api/v1/workflow/actions/default/fire/DESTROY {...}
All lifecycle actions can take a {contentlet:xxxx}
body that will be persisted when the default action is called (the body is required when calling NEW and EDIT).
Mapping Lifecycle to Workflow Actions
To map content lifecycle actions to specific workflow actions, navigate to the workflow you would like to edit/map and click the “Default Actions” button.
Example: New Content
PUT /actions/default/fire/NEW
{
"contentlet": {
"contentType":"webPageContent",
"title":"Amazing Content",
"siteOrFolder":"demo.dotcms.com",
"body": "<h1>This content is amazing</h1><div>but not this</div>",
"languageId": "1"
}
}
Example: Publishing
PUT /actions/default/fire/PUBLISH
{
"contentlet": {
"contentType":"webPageContent",
"title":"Published Content",
"siteOrFolder":"demo.dotcms.com",
"body": "<h1>This content is amazing</h1><div>but not this</div>",
"languageId": "1"
}
}
Example: Unpubishing
PUT /actions/default/fire/UNPUBLISH?identifier=e5b3e417-b0c9-450c-87ba-dda0e2782cb3
Example: Archiving
PUT /api/v1/workflow/actions/default/fire/ARCHIVE
{
"contentlet": {
"identifier":"e5b3e417-b0c9-450c-87ba-dda0e2782cb3",
"contentType":"webPageContent",
"title":"ARCHIVED Content",
"contentHost":"default",
"body": "I'M ARCHIVED!",
"languageId": "1"
}
}
Example: Multiple Contents
Many of these endpoints take multiple content obects as an array, and will perform the same Lifecycle action on the list of contents.
POST /actions/default/fire/PUBLISH
{
"contentlets":[
{
"contentType":"Test1",
"title":"Content1",
"languageId": "1",
"body":"Body Content1"
},
{
"contentType":"Test1",
"title":"Content2",
"languageId": "1",
"body":"Body Content2"
},
{
"contentType":"Test1",
"title":"Content3",
"languageId": "1",
"body":"Body Content3"
}
]
}
Example: PATCHING Update
The EDIT
and PUBLISH
content lifecycle events can be used to modify specific fields on multiple pieces of content simultaneously. In order to do this, you use the HTTP PATCH
method and specify a content query that will return the list of content to update and then field/values that you would like to update. Below is an psuedo-code example:
PATCH actions/default/fire/PUBLISH
{
"comments":"Publish an existing Generic content",
"query":"+contentType:webPageContent AND title:\"Test Merge Content\"",
"contentlet": {
"title":"Test Merge Content Published"
}
}
Fire by Name or ID
PUT /api/v1/workflow/actions/fire {"actionName": "save"...}
PUT /api/v1/workflow/actions/{actionId}/fire
The fire
endpoint expects data in the body of the request with the JSON name "contentlet"
, which includes a list of the fields of the content and a “name” field which specifies the name of the application accessing the endpoint (for logging purposes).
If you wish to specify the Workflow Action via the action name, you must include an actionname
field as well. This field is not required when specifying the Workflow Action identifier in the URL.
This method allows you to post content and specify a workflow action that you want to fire it through.
Example: Save by actionName
PUT /api/v1/workflow/actions/fire
{
"actionName": "save", // workflow action name or action id
"comments": "saving content",
"contentlet": {
"contentType":"myBlog",
"title":"Amazing Content",
"urlTitle": "amazing-content",
"siteOrFolder":"demo.dotcms.com",
"publishDate":"2019-12-18 10:00:00",
"tags": "tag one, tag two",
"body": "<h1>This content is amazing</h1><div>but not this</div>",
"languageId": "1"
}
}
Example: Update by actionName
To update content via the api, the identifier and language id are required.
PUT /api/v1/workflow/actions/fire
{
"actionName": "save", // workflow action name or action id
"comments": "saving content", // include a workflow comment
"contentlet": {
"identifier":"fec7b960-a8bf-4f14-a22b-0d94caf217f0" // the identifier of the content you are updating
"title":"Amazing Content Again",
"urlTitle": "my-second-url-title",
"siteOrFolder":"demo.dotcms.com",
"publishDate":"2019-12-18 11:00:00",
"tags": "tag one, tag two",
"body": "<h1>This is an EDITED content<h2><div>but not this</div>",
"languageId": "1"
}
}
Example: Just Fire A Workflow
Some workflow actions do not change/modify the content and rather do other things with them. For example, sending a content object to a translation step. In this case, you can specify the content by Id as a query parameter and the workflow action in the body of the request.
PUT /api/v1/workflow/actions/fire?identifier=fec7b960-a8bf-4f14-a22b-0d94caf217f0
{
"actionName": "Publish",
"comments": "publishing content"
}
Additionally, you can specify which workflow action to fire in the URI - this is useful when you are firing a specific Workflow Action that you know beforehand. You can also specify the workflow action you wish to fire using a Shorty version of the id, e.g. a22b0d94ca
vs a22b0d94-caf21-4f14-a22b-0d94caf217f0
Example: Update by Id
PUT /api/v1/workflow/actions/a22b0d94caf217f0/fire // workflow action id
{
"comments": "saving content", // include a workflow comment
"contentlet": {
"identifier":"fec7b960-a8bf-4f14-a22b-0d94caf217f0" // the identifier of the content you are updating
"title":"Amazing Content Again",
"urlTitle": "my-second-url-title",
"siteOrFolder":"demo.dotcms.com",
"publishDate":"2019-12-18 11:00:00",
"tags": "tag one, tag two",
"body": "<h1>This is an EDITED content<h2><div>but not this</div>",
"languageId": "1"
}
}
Files / Multipart Form Data
Sending multipart/form-data is supported, and is generally required in order to send file content for Binary fields, unless creating Binary content via string.
Content Type Header
The format of the content should be specified in the Content-Type
header. Supported Content-Types include:
- application/json
- application/x-www-form-urlencoded
For more information on submitting content using these content types, please see Data Formats, below.
Auth & Anonymous Access
This API supports the same REST authentication methods as other REST APIs in dotCMS. Please read the REST API Authentication documentation for details on the different methods and how to use them when saving content using the REST API.
By default dotCMS respects the permissions set on the content type that is being persisted. This means that all users, anonymous or otherwise, may save content via the REST API if they have permissions on the content type and or site they are saving content to.
Anonymous access can be limited by assigning the system configuration property, such as by environment variables:
CONTENT_APIS_ALLOW_ANONYMOUS=WRITE
Possible values are NONE
| READ
| WRITE
.
The CONTENT_APIS_ALLOW_ANONYMOUS
controls what level of access to grant ANONYMOUS (not logged in) visitors to dotCMS Content apis. This property is only respected by the APIs that have to do with mananging content in the dotCMS content store. For anonymous content submittal to work (form builder, contentAPI) CONTENT_APIS_ALLOW_ANONYMOUS
needs to be set to WRITE, otherwise users will need to authenticate before subitting content
- Set permissions to allow the CMS Anonymous user to save content of the appropriate Content Types.
- Grant Add to permissions to the CMS Anonymous role on the Site where the content will be saved using the REST API.
- Grant Edit permissions to the CMS Anonymous role on each Content Type which will be added or updated via the REST API.
For more configuration on how access to the REST API can be controlled via configuration, please see the REST API Authentication documentation.
Data Formats
You may submit data via the Content REST API using either JSON or FORM. The following examples demonstrate ways to submit content via the REST API using JSON, and Form UrlEncoded formats, both to create new content and to update existing content.
Field Types
The following examples demonstrate how to send content for several additional types of Content Type fields.
Field Value Formats
All field values are passed in the json object as strings. Below is a list of field types in dotCMS and the supported formats for each type:
Field Type | Supported Formats |
---|---|
Binary | Please see Binary Fields, below. |
Category | A string containing a comma separated list of Category ids, Category keys, or Category variable names.(e.g. "investing,research,wealthManagement" ). Please see Categories, below. |
Checkbox, Multi-Select | A string containing a comma separated list of selected values (the strings to the right of the pipe (\ |
Constant Field, Hidden Field | Should not be submitted with the content item. (These are filled in automatically by dotCMS). |
Custom Field | A string containing the field value (as formatted by your Custom Field code). |
Date, Time, Date and Time | yyyy-MM-dd HH:mm:ss , yyyy-MM-dd HH:mm , d-MMM-yy , MMM-yy , MMMM-yy , d-MMM , dd-MMM-yyyy , MM/dd/yyyy hh:mm:ss aa , MM/dd/yyyy hh:mm aa , MM/dd/yy HH:mm:ss , MM/dd/yy HH:mm:ss , MM/dd/yy HH:mm , MM/dd/yy hh:mm:ss aa , MM/dd/yy hh:mm:ss , MM/dd/yyyy HH:mm:ss , MM/dd/yyyy HH:mm , MMMM dd, yyyy , M/d/y , M/d , EEEE, MMMM dd, yyyy , MM/dd/yyyy , hh:mm:ss aa , hh:mm aa , HH:mm:ss , HH:mm , yyyy-MM-dd . Note: You may use formats that only include the date or time for Date and Time fields, but you may not use a format which includes both the date and time for Date fields or Time fields. |
File, Image | The path to the related file, starting with the hostname (e.g. "//demo.dotcms.com/images/photos/The-Gherkin-London-England.jpg" ). |
Key/Value | Please see Key/Value Pair Fields, below. |
Radio, Select | A string containing the selected value for the field (the string to the right of the pipe (\ |
Relationship | Please see Relationships, below. |
Site or Folder | A string representing the host (e.g. "demo.dotcms.com" ), a folder (for the host the user is on) (e.g. "/images/photos" ), or a combination of host and folder (e.g. "demo.dotcms.com:/images/photos/" . |
Tag | A comma separated list of tag values (e.g. "investment,banking,europe" ). |
Text | A string containing the field value. |
Textarea | A string containing the field value. Non-printing characters should be escaped using HTML escape codes (e.g. %0D%0A for carriage-return line-feed). |
WYSIWYG | A string containing the field value, containing HTML formatting. Non-printing characters should be escaped using HTML escape codes (e.g. %0D%0A for carriage-return line-feed). |
Categories
Categories can be specified using a comma separated list. Each item in the list will be checked first to see if it matches a Category inode, then to see if it matches a Category key, and finally to see if it matches a Category variable name. If any of these are matched, the appropriate Category will be set for the content item.
The following example adds a News content item on the dotCMS demo site (uploading categories variable names):
Example: Categories
PUT /api/v1/workflow/actions/default/fire/PUBLISH
{
"contentlet": {
contentType:"webPageContent",
languageId:1,
urlTitle:"a-new-news-item",
hostfolder:"demo.dotcms.com",
title:"A new news item",
byline: "this is a new story",
sysPublishDate: "2013-07-01 00:00:00",
story: "this is a new story uploaded from cURL",
topic: "investing,banking,research"
}
}
Binary Fields
Files can be uploaded into Binary fields using multipart/form-data.
- Portions of the API call using JSON, XML or Form UrlEncoded data are interpreted as normal field values.
- Portions of the API call using a
Content-Disposition
header are added as Binary field values.
Single or multiple binary files can be uploaded as part of a piece of content. Regardless of which method is used, all required binary fields on the Content Type must be submitted.
Uploading a Single Binary File
The following curl command submits a single binary image to a File Asset type of content using the REST API. Note the JSON portion of the API call to set the regular field values, and the file included using @
(which will submit the specified file to the first Binary field in the Content Type).
Example: New Binary Asset
curl --location --request PUT 'http://localhost:8082/api/v1/workflow/actions/default/fire/NEW?language=1589383514071' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic XXXXXXXXXXXXXXXXX==' \
--form 'file=@testpdf.pdf' \
--form 'json={
"contentlet": {
"contentType":"PDFDotAsset",
"title":"Test1",
"contentHost":"demo.dotcms.com"
}
}
'
Uploading Multiple Binary Fields
The following curl command submits a File Asset using the REST API with two binary fields. The names of the two fields are fileAsset
and image2
. Note the JSON portion of the API call to set the regular field values, and the file included using @
(which will submit the specified file to the Binary fields in the order expressed using in the binaryFields
parameter that has been added to the curl command).
Important Note: Notice that the binaryFields
parameter is ordering the submit of the files to the fields in the content. When using the binaryFields
parameter:
- The order of the fields submitted to the parameter determines which fields the binary files will be uploaded.
- Non-required binary fields may be omitted — e.g., if the Content Type has 4 non-required binary fields, supplying the names of only the 2nd and 3rd fields to the
binaryFields
parameter will upload only two binary files to those specified fields and leave the other two Binary fields empty. - The number of fields supplied to the
binaryFields
parameter must match the number of files that are appended at the end of the REST API submit. - The names of each binary field will match the file name specified in the REST API submit. More flexibility on multiple binary field naming will added in a future dotCMS version.
The curl command below uses the binaryFields
parameter two upload two files to a new contentlet of the File Asset type. The order of the fields supplied to the parameter, in the example provided below, determines which fields the appended files will be uploaded to respectively i.e., test1.png
will be uploaded to the fileAsset
field, and test2.png
will be uploaded to the image2
field.
Example: Multiple Binary Assets
curl -XPUT 'http://local.dotcms.site:8443/api/v1/workflow/actions/default/fire/PUBLISH' \
--header 'Authorization: Bearer XXXXXXXXXXXXXX==' \
--header 'Content-Type: application/json' \
--form 'json="{
\"contentlet\": {
\"stInode\": \"49f7f5904c2c10d3a4ada6b2e9cc2fc1\",
\"title\":\"Test\",
\"hostFolder\":\"demo.dotcms.com\"
},
\"binaryFields\": [
\"fileAsset\",\"image2\"
]
}"' \
--form 'file=@"/Users/erickg/Pictures/test1.png"' \
--form 'file=@"/Users/erickg/Pictures/test2.png"'
Creating Binary Content Via String
Beginning with dotCMS 23.06, it is possible to populate a Binary field using only a string, thereby bypassing the multi-part process. Please note that this technique applies only to plaintext-type target files — e.g., JSON, XML, TXT, VTL, HTML, etc. Attempting to encode raw binary data as, e.g., a base-64 string and transmit it in this same fashion may fail.
For example, the following will create a plaintext File Asset:
Example: New Text Binary Asset
curl -XPUT 'http://local.dotcms.site:8443/api/v1/workflow/actions/default/fire/PUBLISH' \
--header 'Authorization: Bearer XXXXXXXXXXXXXX==' \
--header 'Content-Type: application/json' \
--data-raw '{
"contentlet": {
"hostFolder":"default",
"title": "greatings.txt",
"fileName": "greatings.txt",
"fileAsset": {
"fileName": "greatings.txt",
"content": "Hello dotCMS!"
},
"contentType": "FileAsset"
}
}'
Key/Value Fields
In the following example, a Key/Value pair field on a Content Type called “Television” has the Velocity variable name of “productSpecifications”. As shown in the example below, keys and values can be sent via REST API using the following form: fieldVelocityVariableName:{"mykey1:"myValue1","mykey2:"myValue2",... etc.}
. Note the handling of the “productSpecifications” key/value pair field.
Example: Key/Value
curl -XPUT 'http://local.dotcms.site:8443/api/v1/workflow/actions/default/fire/PUBLISH' \
--header 'Authorization: Bearer XXXXXXXXXXXXXX==' \
--header 'Content-Type: application/json' \
-d '{
"contentlet":
{
contentType:"Television",
languageId:1,
contentHost:"demo.dotcms.com",
brandAndModel:"Samsung UN65JS9500",
resolution:"Ultra HD",
screenSizeinches:"65",
productSpecifications:{"Refresh Rate":"240 CMR (Effective)","Backlight":"LED","Smart Functionality":"Yes - Built in Wifi","Inputs":"2 HDMI, 2 USB"}
}
}'
Relationships
The examples below show how to submit related content via REST API using one-sided relationship fields. This methodology works for One-to-One, One-to-Many, or Many-to-Many relationships.
Submiting Related Content
To relate content, you must specify the variable name of the Relationship field, and set the value to a string with one or more lucene queries and/or content identifiers, separated by commas. For content that already has existing relationships, you may delete, replace, or preserve the existing relationships by passing the appropriate value to the Relationship field, as follows:
Information Passed to the Relationship Field | Results |
---|---|
Empty String (e.g. "" ) | Remove all existing relationships (if any). |
String of queries/ids (separated by commas) | Replace existing relationships (if any) with the specified relationships. |
No relationship field passed | Preserve (make no changes to) existing relationships (if any). |
When submiting related content via the REST API, use the following format:
Relate a single piece of content by identifier
{relationship field velocity variable name}:"{identifier}"
Relate a multiple pieces of content by identifier
{relationship field velocity variable name}:"{identifier,identifier,...}"
Relate one or more pieces of content using a lucene query
{relationship field velocity variable name}:"{lucene query}"
Relate one or more pieces of content using a comma separated list of lucene queries and identifiers
{relationship field velocity variable name}:"{lucene query},{identifier},{lucene query},{identifier}"
Examples: Related Content
Create New Employee with Query for Location Identifier
curl -XPUT 'http://local.dotcms.site:8443/api/v1/workflow/actions/default/fire/PUBLISH' \
--header 'Authorization: Bearer XXXXXXXXXXXXXX==' \
--header 'Content-Type: application/json' -d '{
"contentlet": {
contentType:"Employee",
languageId:1,
firstName:"Dean",
lastName:"Gonzalez",
gender:"male",
jobTitle:"General Manager",
email:"dean@dotcms.com",
location:"+identifier:0c69da5c-2a05-452f-9305-3be6926d5079"
}
}'
Create New Employee with Lucene Query for “South America” as Location Office Name
curl -XPUT 'http://local.dotcms.site:8443/api/v1/workflow/actions/default/fire/NEW' \
--header 'Authorization: Bearer XXXXXXXXXXXXXX==' \
--header 'Content-Type: application/json' -d '{
"contentlet": {
contentType:"Employee",
languageId:1,
firstName:"New",
lastName:"Person",
gender:"male",
jobTitle:"General Manager",
email:"person@dotcms.com",
location:"+contentType:Location +Location.title:\"South America\""
}
}'
Submit new Location and Relate to Many Employees with Job Title of President
curl -XPUT 'http://local.dotcms.site:8443/api/v1/workflow/actions/default/fire/NEW' \
--header 'Authorization: Bearer XXXXXXXXXXXXXX==' \
--header 'Content-Type: application/json' -d '{
"contentlet": {
contentType:"Location",
host1:"48190c8c-42c4-46af-8d1a-0cd5db894797",
languageId:1,
title:"Melbourne Office",
country:"Australia",
address1:"1122 Aussie Avenue",
city:"Melbourne",
segment:"banking,investing",
description:"Melbourne Australia Office",
employees:"+contentType:Employee +Employee.jobTitle:President*"
}
}'
Submit new Location and Relate to Many Employees with Job Title of President and an Employee Identifier
curl -XPUT 'http://local.dotcms.site:8443/api/v1/workflow/actions/default/fire/PUBLISH' \
--header 'Authorization: Bearer XXXXXXXXXXXXXX==' \
--header 'Content-Type: application/json' -d '{
"contentlet": {
contentType:"Location",
host1:"48190c8c-42c4-46af-8d1a-0cd5db894797",
languageId:1,
title:"Melbourne Office",
country:"Australia",
address1:"1122 Aussie Avenue",
city:"Melbourne",
segment:"banking,investing",
description:"Melbourne Australia Office",
employees:"+contentType:Employee +Employee.jobTitle:President*,37f93fcb-6124-46af-83b4-9ece6c1c5380"
}
}'
Update an Employees Passing Employee Identifier and Identifier of Office Location to the Location Field
Please note that the employee's relationship to ANY current office location would be replaced by the new office location being passed to the relationship field
curl -XPUT 'http://local.dotcms.site:8443/api/v1/workflow/actions/default/fire/PUBLISH' \
--header 'Authorization: Bearer XXXXXXXXXXXXXX==' \
--header 'Content-Type: application/json' -d '{
"contentlet": {
contentType:"Employee",
identifier:"74ebbf55-2821-4b51-8e66-78d54c839991",
location:"6f19f0a0-f407-4f4c-8c01-58daf6659321"
}
}'