---
title: "Create a workflow template"
method: POST
path: "/v1/workflow-templates"
tags: ["Workflows"]
---

# Create a workflow template

`POST /v1/workflow-templates`

## Request

- Base URL: `https://api.emma.ms/external`
- URL: `https://api.emma.ms/external/v1/workflow-templates`
- Auth: HTTP bearer

This method creates a new workflow template. A workflow template is a predefined blueprint for a workflow that includes a set of tasks and their dependencies. It serves as a starting point for creating workflows, allowing users to quickly set up and execute common processes without having to define each task from scratch.

## Request body

- WorkflowTemplateCreate
  - `name` string, required: Name of the workflow template
  - `description` string, nullable: Description of the workflow template
  - `contentType` 'Shell', required: Format of the content field, only Shell is supported for now
  - `content` string, required: Content of the workflow template. For Shell contentType, it includes shell commands to execute.
  - `status` 'PUBLISHED' | 'UNPUBLISHED', required: Status of the workflow template. Can be PUBLISHED or UNPUBLISHED
  - `resourceTypes` string[]: Types of the resource. Use this instead of the deprecated resourceType. At least one of resourceTypes or resourceType is required.
  - `resourceType` 'COMPUTE' | 'SPOT_COMPUTE': Deprecated — use resourceTypes. At least one of resourceTypes or resourceType is required.
  - `resourceParams` ResourceParamCreate[], required: Parameters of the resource limitation. The parameters depend on the resource type and include parameters for compute instance.
    - `name` 'minCpuCores' | 'maxCpuCores' | 'minRamSizeGb' | 'maxRamSizeGb' | 'minVolumeSizeGb' | 'maxVolumeSizeGb', required: Name of the resource parameter, e.g. minCpuCores, minRamSizeGb, minVolumeSizeGb (and their max* counterparts).
    - `value` string, required: Value of the resource parameter
  - `tags` TagCreate[], required: List of tags assigned to the workflow template
    - `tagId` string, nullable: Existing tag id — echo it back on update to match/preserve the stored tag. Omit (or null) for a newly added tag; the backend assigns the id.
    - `key` string, required: tag key
    - `value` string, nullable: tag key value
  - `contentParams` ContentParam[], required: List of parameters extracted from the content. These parameters can be used to fill in the blanks in the content when creating a workflow from the template.
    - `id` integer, nullable: Stable server-assigned parameter id. Returned on read; echo it back on create/update so the backend matches params by id (preserves the stored value across a rename). Null for a newly added param.
    - `name` string, required: Name of the content parameter, e.g. command1, command2.
    - `defaultValue` string, nullable: Value of the content parameter. On request: actual value submitted by user (plaintext). On response: for isSecret=false — the current value; inside a version snapshot, the value as of that version (resolved by the pinned `vaultVersion`). For isSecret=true — always null (write-only, the secret is never returned). The internal Vault path is never returned.
    - `mandatory` boolean, required: Indicates whether the content parameter is mandatory to fill in when creating
    - `description` string, nullable: Human-readable description of the content parameter.
    - `isSecret` boolean, nullable: If true, the parameter value is treated as a secret: stored in Vault, never returned in responses (defaultValue is always null on read), write-only on update. If false or null — regular parameter, value is visible on read. Transitions on update: - false → true (without new defaultValue): the existing plaintext value is preserved and becomes secret-protected on subsequent reads (defaultValue returned as null, hasDefaultValue=true). - false → true (with new defaultValue): the new value is stored in Vault and protected. - true → false (without new defaultValue): the stored secret is cleared (soft-deleted from Vault); defaultValue returns null and hasDefaultValue=false. The previous secret is NEVER exposed on read. - true → false (with new defaultValue): the new value replaces the stored secret and is returned as a regular value going forward.
    - `hasDefaultValue` boolean, nullable: Response-only. True if a stored default value exists for this parameter. For secrets (defaultValue is always null on read) use this flag to detect a stored value — e.g. to show a masked placeholder in UI or to allow deploy of a mandatory secret-parameter without re-entering the value. Ignored on request.
    - `defaultValueChanged` boolean, nullable: Request-only. Set true if the user edited defaultValue in this request. For isSecret=true: false/null means "keep stored value" (Vault is not touched); true means apply the submitted defaultValue (null clears, value writes). For isSecret=false: the flag has no effect; defaultValue is applied directly (null clears the stored value, a value replaces it). Not returned in responses.
    - `vaultVersion` integer, nullable: Vault version the parameter's value is pinned to. For internal use only, ignored on write. Returned only inside a version snapshot (`WorkflowTemplateVersion.snapshot.contentParams`), where it is always present but may be `null` for a parameter with no pinned version. The live workflow template endpoints never return this field.
  - `isContentValid` boolean: Whether the content passed validation. Optional on write; defaults to true when omitted. Must be true when status is PUBLISHED.
  - `contentExecutionTimeout` integer: Maximum script execution time in minutes (1–30). Defaults to 10 when omitted.
  - `forceDeleteOldest` boolean, nullable: PUT only, ignored on POST. When `true` and the workflow template has reached the 20-version limit, the server soft-deletes the oldest non-active version as part of the save. Otherwise, the request fails with 409 CONFLICT. Ignored on POST

## Response `201`

Workflow template created successfully

- WorkflowTemplate
  - `id` integer, required: ID of the workflow template
  - `name` string, required: Name of the workflow template
  - `description` string, nullable: Description of the workflow template
  - `createdAt` string, required: Date and time of the workflow template creation (ISO-8601, UTC, with milliseconds)
  - `createdByName` string, required: Name of the user who created the workflow template
  - `createdById` integer, required: ID of the user who created the workflow template
  - `modifiedAt` string, required: Date and time when the workflow template was last edited (ISO-8601, UTC, with milliseconds)
  - `modifiedByName` string, required: Name of the user who last edited the workflow template
  - `modifiedById` integer, required: ID of the user who last edited the workflow template
  - `isDeleted` boolean, required: Indicates whether the workflow template is deleted
  - `status` 'PUBLISHED' | 'UNPUBLISHED', required: Status of the workflow template. Can be PUBLISHED or UNPUBLISHED
  - `resourceTypes` string[], required: Types of the resource.
  - `resourceType` 'COMPUTE' | 'SPOT_COMPUTE', nullable: Deprecated — use resourceTypes. Mirrors the first resource type; present for backward compatibility. Null when no resource type is set.
  - `activeVersionId` integer, nullable: ID of the active workflow version. `null` when the template has no versions — permanently so for built-in default templates (`isDefault = true`), which are excluded from versioning, and until the one-off backfill covers templates created before versioning was enabled.
  - `activeVersionName` string, nullable: Name of the active workflow version. `null` under the same conditions as `activeVersionId`.
  - `resourceParams` ResourceParam[], required: Parameters of the resource limitation. The parameters depend on the resource type and include parameters for compute instance.
    - `name` string, required: Name of the resource parameter, e.g. minCpuCores, minRamSizeGb, minVolumeSizeGb (and their max* counterparts).
    - `value` string, required: Value of the resource parameter
  - `tags` Tag[], required: List of tags assigned to the workflow template
    - `tagId` string, uuid, required: tag id
    - `key` string, required: tag key
    - `value` string, nullable: tag key value
  - `contentType` 'Shell', required: Format of the content field, only Shell is supported for now
  - `content` string, required: Content of the workflow template. For Shell contentType, it includes shell commands to execute.
  - `isContentValid` boolean, required: Indicates whether the content of the workflow template is valid. The content is validated against the contentType, e.g. for Shell contentType, the content is validated to be correct shell commands.
  - `contentParams` ContentParam[], required: List of parameters extracted from the content. These parameters can be used to fill in the blanks in the content when creating a workflow from the template.
    - `id` integer, nullable: Stable server-assigned parameter id. Returned on read; echo it back on create/update so the backend matches params by id (preserves the stored value across a rename). Null for a newly added param.
    - `name` string, required: Name of the content parameter, e.g. command1, command2.
    - `defaultValue` string, nullable: Value of the content parameter. On request: actual value submitted by user (plaintext). On response: for isSecret=false — the current value; inside a version snapshot, the value as of that version (resolved by the pinned `vaultVersion`). For isSecret=true — always null (write-only, the secret is never returned). The internal Vault path is never returned.
    - `mandatory` boolean, required: Indicates whether the content parameter is mandatory to fill in when creating
    - `description` string, nullable: Human-readable description of the content parameter.
    - `isSecret` boolean, nullable: If true, the parameter value is treated as a secret: stored in Vault, never returned in responses (defaultValue is always null on read), write-only on update. If false or null — regular parameter, value is visible on read. Transitions on update: - false → true (without new defaultValue): the existing plaintext value is preserved and becomes secret-protected on subsequent reads (defaultValue returned as null, hasDefaultValue=true). - false → true (with new defaultValue): the new value is stored in Vault and protected. - true → false (without new defaultValue): the stored secret is cleared (soft-deleted from Vault); defaultValue returns null and hasDefaultValue=false. The previous secret is NEVER exposed on read. - true → false (with new defaultValue): the new value replaces the stored secret and is returned as a regular value going forward.
    - `hasDefaultValue` boolean, nullable: Response-only. True if a stored default value exists for this parameter. For secrets (defaultValue is always null on read) use this flag to detect a stored value — e.g. to show a masked placeholder in UI or to allow deploy of a mandatory secret-parameter without re-entering the value. Ignored on request.
    - `defaultValueChanged` boolean, nullable: Request-only. Set true if the user edited defaultValue in this request. For isSecret=true: false/null means "keep stored value" (Vault is not touched); true means apply the submitted defaultValue (null clears, value writes). For isSecret=false: the flag has no effect; defaultValue is applied directly (null clears the stored value, a value replaces it). Not returned in responses.
    - `vaultVersion` integer, nullable: Vault version the parameter's value is pinned to. For internal use only, ignored on write. Returned only inside a version snapshot (`WorkflowTemplateVersion.snapshot.contentParams`), where it is always present but may be `null` for a parameter with no pinned version. The live workflow template endpoints never return this field.
  - `contentExecutionTimeout` integer, required: Maximum script execution time in minutes (1–30). Defaults to 10 when omitted on create/update.
  - `isDefault` boolean, required: Indicates whether this is a built-in default (system-provided) workflow template.

## Other responses

- `400`: Bad request. A duplicate template name within the company is also reported as `400` (creation), unlike renaming through `PUT`, which reports `409`.
- `401`: Unauthorized
- `403`: Forbidden - Access is denied
- `404`: Not found
- `500`: Internal server error
- `503`: InternalError
- `504`: Timeout

---

[API](https://skmtc.dev/emma/apis/public-emma-api.md) - [All operations](https://skmtc.dev/emma/apis/public-emma-api/llms.txt) - [OpenAPI document](https://skmtc.dev/emma/apis/public-emma-api/revisions/9e55f0920078?raw)
