Workflow

Fire action by ID

Fires a workflow action, specified by identifier, on a target contentlet.

Returns a map of the resultant contentlet, with an additional AUTO_ASSIGN_WORKFLOW property, which can be referenced by delegate services that handle automatically assigning workflow schemes to content with none.

Use this endpoint to fire actions that are not represented as SystemAction tokens (NEW, EDIT, PUBLISH, etc.). The two most common are Move and Copy on the System Workflow scheme.

Move action — relocates a contentlet to a new folder/host. Request body shape (note: pathToMove is a sibling of contentlet, not nested inside it):

{
  "contentlet": { "identifier": "<contentlet-identifier>" },
  "pathToMove": "//<siteHost>/<folderPath>"
}

Alternative shapes (contentlet.host+contentlet.folder, contentlet.hostFolder, path instead of pathToMove) all return 400 "The host path is not valid: null".

Copy action — clones a contentlet. Fire with ?identifier=<source-id> and an empty body (or {"contentlet": {"identifier": "<source-id>"}}). The Copy action id on the default System Workflow scheme is 963f6a04-5320-42e7-ab74-6d876d199946; retrieve it for other environments via GET /api/v1/workflow/schemes/{schemeId}/actions. ⚠️ The response entity returns the source contentlet, not the newly-created copy — locate the copy via a follow-up POST /api/content/_search ordered by modDate DESC. The copy lands in SYSTEM_HOST / SYSTEM_FOLDER; destination hints (pathToMove, host, folder, hostFolder) are silently ignored. Fire the Move action afterwards to relocate.

When chaining workflow actions or reading state back immediately after firing, pass indexPolicy=WAIT_FOR on each call. The default DEFER is asynchronous and can return stale index reads for several seconds, which can mimic server-side state bugs. For isolated one-off fires where nothing reads the result, leave the default.

Block Editor (Story Block) fields: send the value as a Markdown or HTML string — you do not need to hand-author the underlying ProseMirror/JSON document. dotCMS converts it to the Block Editor (ProseMirror JSON) structure automatically on save, so the field reads back as structured content with no editor round-trip required. A value that is already a valid Tiptap/ProseMirror JSON document is detected and stored unchanged. Example: "body": "## Intro\n\nHello **world**.".

Rich blocks in Markdown: blocks that plain Markdown cannot express are written as fenced code blocks whose info string is a dotcms-* label and whose body is a small JSON object. Example — embed a contentlet:

dotcms-content\n{"identifier": "<contentlet-id>", "languageId": 1}\n

Supported labels and payload fields (bold = required):

  • dotcms-content → embedded contentlet: identifier, languageId (default 1). The server rebuilds the full embed data from the identifier on every read.
  • dotcms-image → dotCMS-bound or decorated image: identifier or src; optional alt, title, href, target, textWrap, textAlign, languageId. Plain external images need no fence — standard ![alt](url "title") works.
  • dotcms-video → video: identifier or src; optional mimeType, width, height, languageId.
  • dotcms-youtube → YouTube embed: src; optional start (seconds), width, height.
  • dotcms-grid → layout grid: the verbatim gridBlock node JSON ({"type":"gridBlock","attrs":{"columns":[n,n]},"content":[…two gridColumn nodes…]}).
  • dotcms-node → any other node type verbatim ({"type": "<nodeType>", …}) — the fallback for custom blocks.

Rich blocks in HTML: the same labels are namespaced custom elements. Scalar payloads ride as attributes with hyphenated names (HTML lowercases attribute names, so languageId is spelled language-id, mimeType is mime-type): <dotcms-content identifier="<contentlet-id>" language-id="1"></dotcms-content>. dotcms-ai, dotcms-grid and dotcms-node take the same JSON object as the element's text body instead (HTML-escape < and & inside JSON string values). Always write an explicit closing tag — HTML parsing ignores the / in <dotcms-video … /> and would swallow the content after it. Both carriers produce identical stored documents.

Block styling (e.g. text alignment) is set by an HTML comment on its own line immediately before the block it decorates, in Markdown and HTML alike: <!-- dotcms:attrs {"textAlign":"center"} -->.

A Markdown/HTML write fully replaces the stored document; when stored rich blocks are not carried over in the submitted value, the save still succeeds and an advisory warning listing the replaced blocks is returned in the response messages field — carry the blocks over as fences or elements to preserve them. An invalid payload degrades to an ordinary code block (or is dropped when it carries no text to keep), never an error.

put/api/v1/workflow/actions/{actionId}/fire

Request

Path parameters

actionIdstring required

Identifier of a workflow action.

Example value: b9d89c80-3d88-4311-8365-187323c96436 (Default system workflow "Publish" action)

Query parameters

inodestring

Inode of the target content.

identifierstring

Identifier of target content.

indexPolicy'DEFER' | 'WAIT_FOR' | 'FORCE'

Determines how target content is indexed.

ValueDescription
DEFERContent will be indexed asynchronously, outside of the current process. Valid content will finish the method in process and be returned before the content becomes visible in the index. This is the default index policy; it is resource-friendly and well-suited to batch processing.
WAIT_FORThe API call will not return from the content check process until the content has been indexed. Ensures content is promptly available for searching.
FORCEForces Elasticsearch to index the content immediately.<br>Caution: Using this value may cause system performance issues; it is not recommended for general use, though may be useful for testing purposes.
languagestring

Language version of target content.

Request body

commentsstring

Optional comment recorded on the workflow task history.

assignstring

User or role ID to assign the task to (used by actions that reassign).

publishDatestring

Publish date for the 'Publish' step, in the content type's configured date format.

publishTimestring

Publish time for the 'Publish' step, in the content type's configured time format.

expireDatestring

Expiration date, in the content type's configured date format.

expireTimestring

Expiration time, in the content type's configured time format.

neverExpirestring

Set to 'true' to mark the content as never expiring.

whereToSendstring

Push-publishing target environment(s) for a 'Push Publish' action.

filterKeystring

Push-publishing filter key for a 'Push Publish' action.

querystring

Lucene query selecting the content to act on, as an alternative to 'contentlet'.

pathToMovestring

Target folder path for a 'Move' action.

timezoneIdstring

Timezone ID (e.g. 'America/New_York') used to interpret the publish/expire date-times.

individualPermissionsobject

Per-content individual permissions to apply, keyed by permission type (READ, WRITE, PUBLISH, etc.) to a list of user/role IDs.

iwantTostring
contentletobject

The contentlet to create or edit, as a flat map of field-variable names to values. Polymorphic: the allowed fields depend on the content type.

System fields (all content):

  • contentType (string) — the content type's variable name (e.g. 'webPageContent'). Required when creating.
  • languageId (number) — language ID; defaults to the system default language when omitted.
  • contentHost (string) — host (site) identifier the content belongs to, or hostFolder (string) — a folder identifier. Supply one of these.
  • inode / identifier (string) — include the existing identifier (and optionally inode) to edit existing content; omit both to create new.

⚠️ Do not set host — use contentHost (host id) or hostFolder (folder id) instead.

Host defaulting (common wrong-host trap): if you omit contentHost/hostFolder when creating, the content does NOT go to the current/default site — it inherits the content type's own host, which is SYSTEM_HOST unless the type was explicitly created on a site. So content of a SYSTEM_HOST content type silently lands on SYSTEM_HOST, where it is invisible to another site's URL-maps and to host-scoped searches (+conHost:<siteId>). Always pass contentHost:<siteId> (the site identifier UUID, not the hostname) to place content on a specific site.

Constant fields are content-type configuration, not contentlet data. Fields whose clazz is ImmutableConstantField are shared by the content type. Keys for them in this contentlet map are silently ignored even when the workflow response is HTTP 200/live. For example, a WIDGET's widgetCode must be written to the field's values property via the content-type field API, not included in a widget contentlet.

Pages (contentType: 'htmlpageasset') additionally use:

  • title (string) — the page title.
  • url (string) — the page name (the last URL segment) within hostFolder.
  • template (string) — identifier of the template to render the page.
  • cachettl (number) — page cache time-to-live in seconds.
  • sortOrder (number) — sort order within the folder.

Note: there is no dedicated page-create endpoint — pages are created by firing an action with an htmlpageasset contentlet.

Example request

{
  "contentlet": {
    "contentType": "htmlpageasset",
    "languageId": 1,
    "hostFolder": "48190c8c-42c4-46af-8d1a-0cd5db894797",
    "title": "My Page",
    "url": "my-page",
    "template": "8e63a9c0-...",
    "cachettl": 15,
    "sortOrder": 0
  }
}

Response

Fired action successfully

entityobject
i18nMessagesMapobject
permissionsstring[]

Changes

No recorded changes to this operation across all 2 revisions of this API.