> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hookpulse.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Workflow Step

> Add a webhook step to an existing workflow template

Add a webhook step to an existing workflow template. This endpoint allows you to configure individual steps within a workflow, including execution order, conditions, retry logic, and template variables.

## Base URL

All API requests should be made to:

```
https://api.hookpulse.io
```

## Example request

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.hookpulse.io/v1/api/add_workflow_step/ \
    -H "x-hookpulse-api-key: {{x-hookpulse-api-key}}" \
    -H "x-brand-uuid: {{x-brand-uuid}}" \
    -H "Content-Type: application/json" \
    -d '{
      "index": {{index}},
      "workflow_uuid": "{{workflow_uuid}}",
      "webhook_name": "{{webhook_name}}",
      "webhook_description": "{{webhook_description}}",
      "method": "{{method}}",
      "path": "{{path}}",
      "domain_uuid": "{{domain_uuid}}",
      "human_approval_required": {{human_approval_required}},
      "step_identifier": "{{step_identifier}}",
      "on_success_next_step_identifier": "{{on_success_next_step_identifier}}",
      "on_fail_next_step_identifier": "{{on_fail_next_step_identifier}}",
      "delay_to_next_step": {{delay_to_next_step}},
      "execution_condition": {
        "operator": "{{operator}}",
        "field": "{{field}}",
        "value": "{{value}}"
      },
      "retry_delay": {{retry_delay}},
      "retry_backoff_mode": "{{retry_backoff_mode}}",
      "max_retries": {{max_retries}},
      "request_timeout_in_milliseconds": {{request_timeout_in_milliseconds}},
      "request_body_json": {},
      "headers_json": {},
      "query_params_json": {}
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.hookpulse.io/v1/api/add_workflow_step/', {
    method: 'POST',
    headers: {
      'x-hookpulse-api-key': '{{x-hookpulse-api-key}}',
      'x-brand-uuid': '{{x-brand-uuid}}',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      index: {{index}},
      workflow_uuid: '{{workflow_uuid}}',
      webhook_name: '{{webhook_name}}',
      webhook_description: '{{webhook_description}}',
      method: '{{method}}',
      path: '{{path}}',
      domain_uuid: '{{domain_uuid}}',
      human_approval_required: {{human_approval_required}},
      step_identifier: '{{step_identifier}}',
      on_success_next_step_identifier: '{{on_success_next_step_identifier}}',
      on_fail_next_step_identifier: '{{on_fail_next_step_identifier}}',
      delay_to_next_step: {{delay_to_next_step}},
      execution_condition: {
        operator: '{{operator}}',
        field: '{{field}}',
        value: '{{value}}'
      },
      retry_delay: {{retry_delay}},
      retry_backoff_mode: '{{retry_backoff_mode}}',
      max_retries: {{max_retries}},
      request_timeout_in_milliseconds: {{request_timeout_in_milliseconds}},
      request_body_json: {},
      headers_json: {},
      query_params_json: {}
    })
  });

  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  url = 'https://api.hookpulse.io/v1/api/add_workflow_step/'
  headers = {
      'x-hookpulse-api-key': '{{x-hookpulse-api-key}}',
      'x-brand-uuid': '{{x-brand-uuid}}',
      'Content-Type': 'application/json'
  }
  payload = {
      'index': {{index}},
      'workflow_uuid': '{{workflow_uuid}}',
      'webhook_name': '{{webhook_name}}',
      'webhook_description': '{{webhook_description}}',
      'method': '{{method}}',
      'path': '{{path}}',
      'domain_uuid': '{{domain_uuid}}',
      'human_approval_required': {{human_approval_required}},
      'step_identifier': '{{step_identifier}}',
      'on_success_next_step_identifier': '{{on_success_next_step_identifier}}',
      'on_fail_next_step_identifier': '{{on_fail_next_step_identifier}}',
      'delay_to_next_step': {{delay_to_next_step}},
      'execution_condition': {
          'operator': '{{operator}}',
          'field': '{{field}}',
          'value': '{{value}}'
      },
      'retry_delay': {{retry_delay}},
      'retry_backoff_mode': '{{retry_backoff_mode}}',
      'max_retries': {{max_retries}},
      'request_timeout_in_milliseconds': {{request_timeout_in_milliseconds}},
      'request_body_json': {},
      'headers_json': {},
      'query_params_json': {}
  }

  response = requests.post(url, headers=headers, json=payload)
  print(response.json())
  ```

  ```ruby Ruby theme={null}
  require 'net/http'
  require 'json'
  require 'uri'

  uri = URI('https://api.hookpulse.io/v1/api/add_workflow_step/')
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(uri.path)
  request['x-hookpulse-api-key'] = '{{x-hookpulse-api-key}}'
  request['x-brand-uuid'] = '{{x-brand-uuid}}'
  request['Content-Type'] = 'application/json'
  request.body = {
    index: {{index}},
    workflow_uuid: '{{workflow_uuid}}',
    webhook_name: '{{webhook_name}}',
    webhook_description: '{{webhook_description}}',
    method: '{{method}}',
    path: '{{path}}',
    domain_uuid: '{{domain_uuid}}',
    human_approval_required: {{human_approval_required}},
    step_identifier: '{{step_identifier}}',
    on_success_next_step_identifier: '{{on_success_next_step_identifier}}',
    on_fail_next_step_identifier: '{{on_fail_next_step_identifier}}',
    delay_to_next_step: {{delay_to_next_step}},
    execution_condition: {
      operator: '{{operator}}',
      field: '{{field}}',
      value: '{{value}}'
    },
    retry_delay: {{retry_delay}},
    retry_backoff_mode: '{{retry_backoff_mode}}',
    max_retries: {{max_retries}},
    request_timeout_in_milliseconds: {{request_timeout_in_milliseconds}},
    request_body_json: {},
    headers_json: {},
    query_params_json: {}
  }.to_json

  response = http.request(request)
  puts JSON.parse(response.body)
  ```

  ```php PHP theme={null}
  <?php

  $url = 'https://api.hookpulse.io/v1/api/add_workflow_step/';
  $data = [
      'index' => {{index}},
      'workflow_uuid' => '{{workflow_uuid}}',
      'webhook_name' => '{{webhook_name}}',
      'webhook_description' => '{{webhook_description}}',
      'method' => '{{method}}',
      'path' => '{{path}}',
      'domain_uuid' => '{{domain_uuid}}',
      'human_approval_required' => {{human_approval_required}},
      'step_identifier' => '{{step_identifier}}',
      'on_success_next_step_identifier' => '{{on_success_next_step_identifier}}',
      'on_fail_next_step_identifier' => '{{on_fail_next_step_identifier}}',
      'delay_to_next_step' => {{delay_to_next_step}},
      'execution_condition' => [
          'operator' => '{{operator}}',
          'field' => '{{field}}',
          'value' => '{{value}}'
      ],
      'retry_delay' => {{retry_delay}},
      'retry_backoff_mode' => '{{retry_backoff_mode}}',
      'max_retries' => {{max_retries}},
      'request_timeout_in_milliseconds' => {{request_timeout_in_milliseconds}},
      'request_body_json' => [],
      'headers_json' => [],
      'query_params_json' => []
  ];

  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'x-hookpulse-api-key: {{x-hookpulse-api-key}}',
      'x-brand-uuid: {{x-brand-uuid}}',
      'Content-Type: application/json'
  ]);

  $response = curl_exec($ch);
  curl_close($ch);

  echo $response;
  ?>
  ```
</RequestExample>

## Request body

| Field                             | Type    | Required | Description                                                                                 |
| --------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------- |
| `index`                           | integer | Yes      | Priority index for FIFO execution order (0 is first step)                                   |
| `workflow_uuid`                   | string  | Yes      | UUID of the workflow template to add the step to                                            |
| `webhook_name`                    | string  | Yes      | Name of the webhook step                                                                    |
| `webhook_description`             | string  | Yes      | Description of the webhook step                                                             |
| `method`                          | string  | Yes      | HTTP method. Allowed values: `"GET"`, `"POST"`, `"PUT"`, `"DELETE"`, `"PATCH"`              |
| `path`                            | string  | Yes      | URL path for the webhook (supports template variables)                                      |
| `domain_uuid`                     | string  | Yes      | UUID of the domain associated with this webhook step                                        |
| `human_approval_required`         | boolean | Yes      | Whether this step requires human approval before execution                                  |
| `step_identifier`                 | string  | Yes      | Unique identifier (slug) for this step                                                      |
| `on_success_next_step_identifier` | string  | Yes      | Step identifier to execute next on success                                                  |
| `on_fail_next_step_identifier`    | string  | Yes      | Step identifier to execute next on failure                                                  |
| `delay_to_next_step`              | integer | Yes      | Delay in seconds before executing the next step                                             |
| `execution_condition`             | object  | No       | Condition that must be met for this step to execute                                         |
| `execution_condition.operator`    | string  | No       | Comparison operator: `"eq"`, `"ne"`, `"lt"`, `"gt"`, `"lte"`, `"gte"`, `"in"`, `"contains"` |
| `execution_condition.field`       | string  | No       | Field path to evaluate                                                                      |
| `execution_condition.value`       | string  | No       | Value to compare against                                                                    |
| `retry_delay`                     | integer | Yes      | Delay in seconds between retry attempts (default: 10)                                       |
| `retry_backoff_mode`              | string  | Yes      | Retry backoff strategy: `"linear"` (default) or `"exponential"`                             |
| `max_retries`                     | integer | Yes      | Maximum number of retry attempts (default: 5)                                               |
| `request_timeout_in_milliseconds` | integer | Yes      | Request timeout in milliseconds (default: 5000)                                             |
| `request_body_json`               | object  | Yes      | Request body as JSON object (supports template variables)                                   |
| `headers_json`                    | object  | Yes      | HTTP headers as JSON object (supports template variables)                                   |
| `query_params_json`               | object  | Yes      | Query parameters as JSON object (supports template variables)                               |

## Execution Order (Index)

The `index` field defines the priority and execution order for FIFO (First-In-First-Out) workflows:

* **Lower index = Higher priority**: Steps with lower index values execute first
* **Index 0**: First step to execute
* **Sequential execution**: In FIFO mode, steps execute in order based on their index
* **Concurrent mode**: Index may still be used for reference, but steps execute in parallel

## Execution Conditions

The `execution_condition` field allows you to control when a step executes based on field values:

### Supported Operators

| Operator   | Description               | Example                           |
| ---------- | ------------------------- | --------------------------------- |
| `eq`       | Equal to                  | `amount eq 100`                   |
| `ne`       | Not equal to              | `status ne "cancelled"`           |
| `lt`       | Less than                 | `quantity lt 10`                  |
| `gt`       | Greater than              | `price gt 1000`                   |
| `lte`      | Less than or equal to     | `age lte 18`                      |
| `gte`      | Greater than or equal to  | `score gte 80`                    |
| `in`       | Value in array            | `status in ["active", "pending"]` |
| `contains` | String contains substring | `email contains "@example.com"`   |

### Example Execution Condition

```json theme={null}
{
  "execution_condition": {
    "operator": "gt",
    "field": "amount",
    "value": "1000"
  }
}
```

This condition ensures the step only executes if `amount > 1000`.

## Template Variables

Workflow steps support dynamic variable substitution in `request_body_json`, `headers_json`, `query_params_json`, and `path`:

### System Secret Variables

Access secrets from the System Secret Vault:

```
{{ #key }}
```

Example:

```json theme={null}
{
  "headers_json": {
    "Authorization": "Bearer {{ #api_key }}"
  }
}
```

### Step Response Variables

Access data from previous workflow steps (FIFO mode only):

```
{{ step.response.variable }}
```

Example:

```json theme={null}
{
  "request_body_json": {
    "payment_id": "{{ step.response.payment_id }}",
    "status": "{{ step.response.status }}"
  }
}
```

### Initial Variables

Access variables from initial workflow input (FIFO mode only):

```
{{ initial.variable }}
```

Example:

```json theme={null}
{
  "request_body_json": {
    "user_id": "{{ initial.user_id }}",
    "order_total": "{{ initial.total }}"
  }
}
```

**Note**: In concurrent mode, only system secret variables (`{{ #key }}`) are available. Step response and initial variables are not supported in concurrent execution.

## Step Flow Control

### Success and Failure Paths

* **`on_success_next_step_identifier`**: Defines which step to execute next when this step succeeds
* **`on_fail_next_step_identifier`**: Defines which step to execute next when this step fails
* **`delay_to_next_step`**: Adds a delay (in seconds) before executing the next step

### Human Approval

When `human_approval_required` is `true`:

* The workflow pauses at this step
* A human must approve or deny the step before execution continues
* This provides manual intervention capabilities for critical operations

## Example response

<ResponseExample>
  ```json theme={null}
  {
    "success": true,
    "details": "Workflow webhook added successfully"
  }
  ```
</ResponseExample>

## Response fields

| Field     | Type    | Description                             |
| --------- | ------- | --------------------------------------- |
| `success` | boolean | Indicates if the request was successful |
| `details` | string  | Success message                         |

## Related Documentation

* [Workflow Template Overview](/docs/api-reference/workflow-template/overview) - Learn about workflow templates, execution modes, and features
* [Add Workflow Template](/docs/api-reference/workflow-template/add-workflow-template) - Create a new workflow template
* [System Secret Vault Overview](/docs/api-reference/system-secret-vault/overview) - Manage secrets for use in workflow steps


## OpenAPI

````yaml POST /v1/api/add_workflow_step/
openapi: 3.0.3
info:
  title: Hookpulse API
  description: >-
    Complete API documentation for Hookpulse. Build powerful integrations with
    our RESTful API.
  version: 1.0.0
  contact:
    name: Hookpulse Support
    email: care@hookpulse.io
    url: https://hookpulse.io
servers:
  - url: https://api.hookpulse.io
    description: Production server
security:
  - apiKeyAuth: []
    brandUuidAuth: []
paths:
  /v1/api/add_workflow_step/:
    post:
      description: Add a webhook step to an existing workflow template
      requestBody:
        description: Workflow step configuration
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddWorkflowStepRequest'
      responses:
        '200':
          description: Workflow step added successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AddWorkflowStepResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    AddWorkflowStepRequest:
      required:
        - index
        - workflow_uuid
        - webhook_name
        - webhook_description
        - method
        - path
        - domain_uuid
        - human_approval_required
        - step_identifier
        - on_success_next_step_identifier
        - on_fail_next_step_identifier
        - delay_to_next_step
        - retry_delay
        - retry_backoff_mode
        - max_retries
        - request_timeout_in_milliseconds
        - request_body_json
        - headers_json
        - query_params_json
      type: object
      properties:
        index:
          type: integer
          description: Priority index for FIFO execution order (0 is first)
        workflow_uuid:
          type: string
          description: UUID of the workflow template to add the step to
        webhook_name:
          type: string
          description: Name of the webhook step
        webhook_description:
          type: string
          description: Description of the webhook step
        method:
          type: string
          enum:
            - GET
            - POST
            - PUT
            - DELETE
            - PATCH
          description: HTTP method for the webhook call
        path:
          type: string
          description: URL path for the webhook (supports template variables)
        domain_uuid:
          type: string
          description: UUID of the domain associated with this webhook step
        human_approval_required:
          type: boolean
          description: Whether this step requires human approval before execution
        step_identifier:
          type: string
          description: Unique identifier (slug) for this step
        on_success_next_step_identifier:
          type: string
          description: Step identifier to execute next on success
        on_fail_next_step_identifier:
          type: string
          description: Step identifier to execute next on failure
        delay_to_next_step:
          type: integer
          description: Delay in seconds before executing the next step
        execution_condition:
          type: object
          description: Condition that must be met for this step to execute
          properties:
            operator:
              type: string
              enum:
                - eq
                - ne
                - lt
                - gt
                - lte
                - gte
                - in
                - contains
              description: Comparison operator
            field:
              type: string
              description: Field path to evaluate
            value:
              type: string
              description: Value to compare against
        retry_delay:
          type: integer
          description: 'Delay in seconds between retry attempts (default: 10)'
        retry_backoff_mode:
          type: string
          enum:
            - linear
            - exponential
          description: 'Retry backoff strategy (default: linear)'
        max_retries:
          type: integer
          description: 'Maximum number of retry attempts (default: 5)'
        request_timeout_in_milliseconds:
          type: integer
          description: 'Request timeout in milliseconds (default: 5000)'
        request_body_json:
          type: object
          description: >-
            Request body as JSON object (supports template variables: {{ #key
            }}, {{ step.response.key }}, {{ initial.key }})
        headers_json:
          type: object
          description: HTTP headers as JSON object (supports template variables)
        query_params_json:
          type: object
          description: Query parameters as JSON object (supports template variables)
    AddWorkflowStepResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Indicates if the request was successful
        details:
          type: string
          description: Success message
    Error:
      required:
        - error
        - message
      type: object
      properties:
        error:
          type: integer
          format: int32
        message:
          type: string
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-hookpulse-api-key
      description: >-
        API key for authentication. Get this from your dashboard by selecting a
        brand and going to API Keys section.
    brandUuidAuth:
      type: apiKey
      in: header
      name: x-brand-uuid
      description: >-
        Brand UUID for authentication. Get this from your dashboard after adding
        a brand - it will be displayed in the UI.

````