# Update a project step

Source: https://www.jawsdeploy.net/rest-api/project-step-update | Section: Project Steps

Update step name, scope, run mode, parallelism, error handling, and properties.

`PUT /api/project/step`

Updates a step on a project. Pass only the fields to change. `propertiesJson` is a JSON-encoded string matching the step template's property schema.

Filters (`machineIdFilter`, `machineTagFilter`, `cloudTargetTagFilter`) constrain which targets the step runs on within the step's selected `environments`.

## Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `projectStepId` | body | string | yes | ID of the step. |
| `name` | body | string | no | New step name. |
| `description` | body | string | no | New description. |
| `stepTemplateId` | body | string | no | Move the step onto a step template as it stands now - another template's id to switch it, or the step's own template id to pull a newer version of it in. See below. |
| `runOn` | body | string | no | See below. |
| `errorAction` | body | string | no | See below. |
| `disabled` | body | boolean | no | Disable the step without removing it. |
| `executeCondition` | body | string | no | See below. |
| `executeConditionScript` | body | string | no | Required when `executeCondition` is `VariableCheck`: the name of the boolean variable that must resolve to true. Despite the name, it is a variable name and not a script. |
| `parallelMachines` | body | integer | no | Max machines to run on in parallel. |
| `parallelCloudTargets` | body | integer | no | Max cloud targets to run on in parallel. |
| `workerTagId` | body | string | no | Tag identifying the worker pool. |
| `environments` | body | array<string> | no | Environment IDs the step is restricted to. |
| `machineIdFilter` | body | array<string> | no | Restrict to these machine IDs. |
| `machineTagFilter` | body | array<object> | no | Tag-set filter for machines. |
| `cloudTargetTagFilter` | body | array<object> | no | Tag-set filter for cloud targets. |
| `propertiesJson` | body | string | no | JSON-encoded step property values. |
| `onStepFailure` | body | string | no | What a failed step does to the rest of the deployment. `ContinueToNextStep` (default) or `StopDeployment`. See below. |
| `runAfterStop` | body | boolean | no | Run this step even when an earlier step stopped the deployment. Defaults to `false`. See below. |
| `machineOrder` | body | string | no | The order the step works through an environment's machines. `MachineName` (default) or `TagPriority`. Parsed case-insensitively. See below. |
| `machineOrderTagIds` | body | array<string> | no | Tag IDs in priority order, highest first, used when `machineOrder` is `TagPriority`. **Only stored while the order uses it** - saving with `MachineName` order drops the list. See below. |
| `onMachineFailure` | body | string | no | What one machine failing does to the rest of the step. `ContinueToOtherMachines` (default) or `StopStep`. Neither ends the deployment - that is `onStepFailure`. See below. |
| `waitBetweenMachineGroups` | body | boolean | no | Finish every machine of one tag rank before the next rank starts. Defaults to `false`. See below. |

### Run mode

`runOn` accepts `TargetMachine`, `Worker`, or `WorkerToCloudTargets`. The value must also be included in the selected step template's `supportedRunModes`; otherwise the request returns `400`.

### Error action

`errorAction` accepts `Stop` or `Continue`. It chooses the level a script failure is logged at, and nothing else - neither value stops the deployment.

- `Stop` - a failing script is logged at `Error`, so it counts towards the deployment `ErrorCount`.
- `Continue` - a failing script is logged at `Warning`, so it counts towards `WarningCount` instead.

A failing script does not fail its step and does not fail the deployment either way. What counts as a failing script depends on the script language: PowerShell 7 (`powershell`) does not fail on exit codes, so `exit 3` only logs a warning, while PowerShell 5.1 (`powershell5`) and Python treat a non-zero process exit code as a failure. See [Get deployment status](https://www.jawsdeploy.net/rest-api/deployments-status) for the details, and for how to tell a clean run from a merely finished one.

### Execute condition

`executeCondition` accepts `Always`, `AllPreviousStepsSucceeded`, or `VariableCheck`. It is the only setting that can hold a step back because of what happened earlier in the deployment.

- `Always` - the step runs whatever came before it.
- `AllPreviousStepsSucceeded` - the step is skipped when the error counts recorded against the preceding steps add up to more than zero. Only steps whose `errorAction` is `Stop` can contribute to that sum, and the first step in a project has nothing before it, so the condition never holds it back.
- `VariableCheck` - the step runs only on the targets where the boolean variable named in `executeConditionScript` resolves to true.

A step held back by its condition is recorded as skipped, not failed, and adds nothing to `ErrorCount`.

### Stopping the deployment

`onStepFailure` accepts `ContinueToNextStep` or `StopDeployment` and defaults to `ContinueToNextStep`. This is the setting that can end a run. `errorAction`, above, is not.

- `ContinueToNextStep` - the historical behaviour. The deployment can no longer report success, but every later step is still offered, and only its own `executeCondition` holds it back.
- `StopDeployment` - no later step runs, apart from any step whose `runAfterStop` is `true`. Those still run, so a process that has to announce its own failure has somewhere to do it from. The rest are recorded as skipped, with the reason logged against them.

A step counts as failed here when its status is `Failed` or `TimedOut`, or when it recorded any errors at all. That is where `errorAction` comes back in. A failing script is counted as an error only when the step's `errorAction` is `Stop`, so a step left on `Continue` will not stop the deployment when its script fails, whatever `onStepFailure` says. Set the two together.

Values are parsed case-insensitively and returned in canonical casing. An unrecognised `onStepFailure` returns `400` with `invalid step failure policy`. Both fields are returned by [List project steps](https://www.jawsdeploy.net/rest-api/projects-steps-list), and both are copied into a release when it is created, so a change here applies to releases cut afterwards rather than to ones that already exist.

### Step templates and pinned versions

A step runs the version of its step template that it is pinned to, not whatever the template says today. A step added to a project is pinned to the template as it stands at that moment, and it stays there until something moves it.

`stepTemplateId` is what moves it. Sending it points the step at that template and pulls the template in: the step's script is replaced with the template's, the property schema is reshaped to the template's, and the pinned version becomes the template's current one. Send the id of the template the step already uses to move the step onto a newer version of it. This is the API equivalent of the **Pull template changes** button in the editor, and it is the supported way to do it - deleting the step and adding it again is not necessary.

Property values are kept wherever the property is still in the new schema and still the same kind of control. A value whose property has gone from the template goes with it. `propertiesJson` sent in the same request is applied before the pull, so the values you send are merged the same way.

Nothing moves unless there is something to move. If `stepTemplateId` names the template the step already uses and the step is already on its current version, the step is left exactly as it is. Leave `stepTemplateId` out and the template side of the step is never touched, whatever else the request changes - a rename cannot put a step onto a new script.

The pinned version is not part of any response, so there is no way to ask which steps are behind their template. Sending `stepTemplateId` on a step that is already current does nothing, so the practical answer is to send it.

Watch `runOn` when moving a step to a **different** template. If the step's run mode is not in the new template's `supportedRunModes`, passing it explicitly returns `400`, and leaving it out moves the step to the first run mode the template does support.

### Rolling a step across its machines

These four fields shape how a **standalone** step works through the machines of an environment.

A step that is a member of a [rolling group](https://www.jawsdeploy.net/rest-api/rolling-groups-list) does not use them. The group carries its own copy of the same settings and that is what the deployment runs, so setting them on a grouped step is not an error - it simply has no effect unless the step leaves the group. Note the defaults differ: a standalone step defaults `onMachineFailure` to `ContinueToOtherMachines`, a group defaults it to `StopStep`.

`machineOrder` decides the sequence:

- `MachineName` - alphabetical, case-insensitive. The default.
- `TagPriority` - a machine's rank is the index of the first tag it carries from `machineOrderTagIds`. A machine matching none of them sorts last rather than being left out. Excluding machines is what `machineIdFilter` and `machineTagFilter` are for.

`machineOrderTagIds` is kept only while the order actually uses it. Saving a step whose `machineOrder` is `MachineName` drops the tag list instead of storing it, so a later switch back to `TagPriority` starts from an empty list. That is deliberate - a stale list left lying around would silently resurrect an order you thought you had removed.

`waitBetweenMachineGroups` is the barrier. With `TagPriority`, every machine of one rank finishes before the next rank starts, which is what makes a canary rollout a rollout rather than a fast parallel run.

`onMachineFailure` decides whether the next machine starts after the step has failed on one. `ContinueToOtherMachines` is the default and the historical behaviour. `StopStep` starts no further machine. Neither ends the deployment, so set it together with `onStepFailure` - a step that stops on the first bad machine while `onStepFailure` is left at `ContinueToNextStep` still lets every later step run.

### `isRolling` is read-only

`isRolling` is **not** a field of this request - sending it does nothing. It is reported by [List project steps](https://www.jawsdeploy.net/rest-api/projects-steps-list) and [Get a release](https://www.jawsdeploy.net/rest-api/releases-details) as a summary of the two settings above: it reads `true` when `machineOrder` is not `MachineName`, **or** when `waitBetweenMachineGroups` is on.

Configure the order and the barrier, and read `isRolling` back to see what they add up to. Nothing in the deployment runner reads the stored flag.

## Errors

| Status | Meaning |
|---|---|
| 400 | Invalid `projectStepId` or validation failure. |
| 401 | Missing or invalid Basic auth credentials, or the service account lacks the required role. |
| 400 | `machineOrder` is not `MachineName` or `TagPriority` - the response reads `invalid machine order`. |
| 400 | `onMachineFailure` is not `ContinueToOtherMachines` or `StopStep` - the response reads `invalid machine failure policy`. |

Example request:

```
PUT /api/project/step HTTP/1.1
Host: app.jawsdeploy.net
Authorization: Basic <base64(serviceAccountId:apiKey)>
Content-Type: application/json

{
  "projectStepId": "ps_1",
  "errorAction": "Stop",
  "onStepFailure": "StopDeployment",
  "parallelMachines": 4
}

// a canary rollout on a standalone step
{
  "projectStepId": "ps_1",
  "machineOrder": "TagPriority",
  "machineOrderTagIds": ["canary", "web"],
  "waitBetweenMachineGroups": true,
  "onMachineFailure": "StopStep"
}
```

Example response:

```
{}
```

