# HTTP request

Make one HTTP call per record and keep the response beside the input.

## When to use it

Make one request per input record. GET requests can execute during a dry run; write methods are skipped in that preview. Normal retries can send requests again unless the receiver recognises the configured duplicate-prevention key. The whole-step timeout and per-request timeout are distinct.

## Add and configure

1. Add **HTTP request** from the workflow step picker.
2. Give the step a recognisable name and connect its required inputs.
3. Set the options below. Nested names identify fields within an object or a list item.
4. Validate the recipe, inspect the test result, then run it on the intended data.

The step identifier used in the editor’s code view is `http_request`.

## Settings

| Setting | Accepted value | Required | Default | What it controls |
| --- | --- | --- | --- | --- |
| Concurrency (`concurrency`) | integer; minimum 1; maximum 32 | No | 4 | Maximum items or requests processed concurrently within this step. More concurrency can increase resource use and provider pressure. |
| Handler Timeout Seconds (`handler_timeout_seconds`) | number; minimum 1.0; maximum 300.0 or null | No | null | Wins over `timeout_seconds` when set. Unset → `timeout_seconds` keeps its historical double duty. |
| Headers (`headers`) | object of string or null | No | null | HTTP headers for the request. Keep credentials in a saved connection where possible. |
| Idempotency Key Template (`idempotency_key_template`) | string or null | No | null | Renders one Idempotency-Key per record from variables `${tenant_id}`, `${run_id}`, `${step_id}`, `${record_seq}`. |
| Method (`method`) | "GET" / "POST" / "PUT" / "PATCH" / "DELETE" | No | "POST" | HTTP method. Write methods can change an external service and can behave differently from reads during preview. |
| Payload Field (`payload_field`) | string or null | No | null | When set, request body is the value at `record[payload_field]` instead of the whole record. |
| Timeout Seconds (`timeout_seconds`) | number; minimum 1.0; maximum 300.0 | No | 15.0 | Deprecated alias for the per-request timeout: `handler_timeout_seconds` wins when present. The runner still reads THIS key as the step's wall-clock timeout, so set it for the whole step and `handler_timeout_seconds` for one request. |
| Url (`url`) | string | Yes | Not specified | Endpoint URL. |

## Inputs and outputs

| Direction | Port | Content | Required | Multiple records |
| --- | --- | --- | --- | --- |
| Inputs | `in` | records | Yes | Yes |
| Outputs | `out` | records | Yes | Yes |

## Effects, testing, and recovery

Can write or act on an external destination.

The declared preview behaviour is to skip this step. Configuration can affect preview behaviour; HTTP GET is a notable exception. Read [dry runs](/docs/workflows/dry-runs) before using a preview with live connections.

Duplicate prevention uses the configured or operation-bound key; an external receiver must recognise it. Do not assume that manually repeating the step is free of repeated effects.

When step caching is available, the declared cache lifetime is 300 seconds. Eligible successful results can be reused; bypass caching when the task requires a fresh read.

## Example: POST each record to a webhook, deduplicated per run

Step settings:

```json
{
  "idempotency_key_template": "${run_id}:${record_seq}",
  "method": "POST",
  "url": "https://hooks.example.com/ingest"
}
```

## Example: Send only one field of the record, with a header

Step settings:

```json
{
  "concurrency": 8,
  "headers": {
    "X-Source": "workflow"
  },
  "method": "PUT",
  "payload_field": "status",
  "timeout_seconds": 30.0,
  "url": "https://api.example.com/status"
}
```

## Check the result

Inspect the selected run’s status, counts, errors, and output records. An empty collection can be a valid result, and a completed step can contain per-record failures where the step defines that behaviour. Check the next step’s expected record shape before publishing or delivering the result.
