# Update Automation Step

> PATCH /automations/:id/steps/:stepId — edit a step in place (type/config) on a disabled automation.

`PATCH /automations/:id/steps/:stepId`

Updates a step's `type` and/or `config` in place. The step's **graph key stays stable**, so any [connections](https://www.sendping.co/docs/automations/connections) pointing at it keep working — unlike delete-and-re-add, which drops the key and its edges. The automation must be **disabled** ([stop](https://www.sendping.co/docs/api/automations-stop) or disable it first). Returns the updated step.

The body is the same shape as [Add Step](https://www.sendping.co/docs/api/automations-add-step): `type` (required) plus the type-specific `config`. See the [Steps](https://www.sendping.co/docs/automations/steps) page for each type's config shape.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes | The automation id. |
| `stepId` | string | Yes | The id of the step to update. |

**Body parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | Yes | The step type (e.g. `send_email`, `delay`, `condition`). |
| `config` | object | No | The type-specific configuration that replaces the step's current config. |

**Node.js**

```js
import { SendPing } from 'sendping';

const mb = new SendPing('mb_xxxxxxxxx');

const { data, error } = await mb.automations.updateStep('c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd', '9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d', {
  "type": "delay",
  "config": { "duration": "2 days" }
});
console.log({ data, error });
```

**Ruby**

```ruby
require "sendping"

SendPing.api_key = "mb_xxxxxxxxx"

SendPing::Automations.update_step("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd", "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", {
  "type": "delay",
  "config": {
    "duration": "2 days"
  }
})
```

**PHP**

```php
<?php
require 'vendor/autoload.php';

use SendPing\SendPing;

$sendping = SendPing::client('mb_xxxxxxxxx');

$sendping->automations->updateStep('c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd', '9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d', [
  'type' => "delay",
  'config' => [
    'duration' => "2 days"
  ]
]);
```

**Python**

```python
import sendping

sendping.api_key = "mb_xxxxxxxxx"

sendping.Automations.update_step("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd", "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", {
  "type": "delay",
  "config": {
    "duration": "2 days"
  }
})
```

**Go**

```go
import "github.com/shekhu10/sendping-sdks/sendping-go"

client := sendping.NewClient("mb_xxxxxxxxx")

step, err := client.Automations.UpdateStep("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd", "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", &sendping.UpdateAutomationStepRequest{
    Type:   "delay",
    Config: map[string]any{"duration": "2 days"},
})
```

**Rust**

```rust
use sendping::{SendPing, UpdateAutomationStepOptions};

let mb = SendPing::new("mb_xxxxxxxxx");

let params = UpdateAutomationStepOptions::new("delay")
    .with_config(serde_json::json!({"duration":"2 days"}));
let _step = mb.automations.update_step("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd", "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", params).await?;
```

**Java**

```java
import co.sendping.SendPing;
import co.sendping.SendPingResponse;
import co.sendping.requests.UpdateAutomationStepRequest;

SendPing sendping = new SendPing("mb_xxxxxxxxx");

UpdateAutomationStepRequest request = UpdateAutomationStepRequest.builder()
        .type("delay")
        .config("duration", "2 days")
        .build();

SendPingResponse response = sendping.automations().updateStep(
        "c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd",
        "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
        request);
```

**.NET**

```csharp
using SendPing;

ISendPing sendping = SendPingClient.Create("mb_xxxxxxxxx");

var resp = await sendping.AutomationUpdateStepAsync("c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd", "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", new AutomationAddStepOptions
{
    Type = "delay",
    Config = new Dictionary<string, object?> { ["duration"] = "2 days" },
});
```

**cURL**

```bash
curl -X PATCH 'https://www.sendping.co/api/automations/c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd/steps/9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "delay",
  "config": { "duration": "2 days" }
}'
```

**CLI**

```bash
sendping automations update-step c9b16d4f-ba6c-4e2e-b044-6bf4404e57fd 9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d \
  --type 'delay' \
  --config '{"duration":"2 days"}'
```

### Response

```json
{
  "id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
  "key": "welcome",
  "type": "delay",
  "position": 0,
  "config": { "duration": "2 days" }
}
```

As with [Add Step](https://www.sendping.co/docs/api/automations-add-step), the response is the stored step row: `delay`, `add_to_segment`, `contact_update` and `contact_delete` are stored exactly as documented, while `send_email` comes back as `type: "send"` with `config.template_id`, and `wait_for_event` comes back as `type: "wait"` with `config: { event, timeout_hours, poll_minutes, timeout?, filter_rule? }` (the natural-language `timeout` is echoed back only when you sent it that way). A `condition` config is normalized on write: the documented single `{ type: "rule", field, operator, value }` is stored as `{ rules: [{ field, operator, value }], match: "all", skip_steps }`, and an `and` / `or` group is flattened to the same shape with `match: "all"` / `match: "any"` — so the response shows `rules` and `match`, not the `type` envelope you sent.

Returns `not_found` (404) if the automation or step does not exist, and `validation_error` (422) if the automation is enabled (disable it first) or the step body is invalid. See [Errors](https://www.sendping.co/docs/api/errors).
