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

# POST /replay/:webhookId/:itemId — replay events

> POST /replay/:webhookId/:itemId re-sends a captured event to a new URL. Includes SSRF protection, retry configuration, and added tracing headers.

`POST /replay/:webhookId/:itemId` re-sends a previously captured webhook event to a destination URL you specify. The server validates the target against SSRF rules, strips masked and transport headers, injects replay-specific headers, and returns the target's response code and body.

**Authentication:** Required when `authKey` is configured.

## Path parameters

<ParamField path="webhookId" type="string" required>
  The webhook ID that owns the captured event.
</ParamField>

<ParamField path="itemId" type="string" required>
  The log entry ID to replay. If this does not resolve to a log ID but parses as a timestamp, the handler attempts a fallback lookup by timestamp within the specified webhook.
</ParamField>

## Query parameters

<ParamField query="url" type="string" required>
  Destination URL to replay the event to. Subject to SSRF and DNS safety checks. Private networks, loopback addresses, and cloud metadata endpoints are blocked. See [Error responses](/api-reference/errors) for the full blocked-range list.
</ParamField>

## Example request

```bash theme={null}
curl -X POST \
  "https://<run-id>.runs.apify.net/replay/wh_abc123/evt_8m2L5p9xR?url=https%3A%2F%2Ftarget.example%2Fwebhook"
```

## Added headers

The server injects the following headers into every outbound replay request:

| Header                  | Value                                |
| ----------------------- | ------------------------------------ |
| `X-Apify-Replay`        | `true`                               |
| `X-Original-Webhook-Id` | The original webhook ID              |
| `Idempotency-Key`       | A unique key for this replay attempt |

## Stripped headers

Masked headers (e.g. `Authorization`, `Cookie`) and transport-managed headers (e.g. `host`, `content-length`) are removed before forwarding. The response body lists any headers that were stripped.

## Success response

```json theme={null}
{
  "status": "replayed",
  "targetUrl": "https://target.example/webhook",
  "targetResponseCode": 200,
  "targetResponseBody": "OK"
}
```

When headers were stripped, the response also includes:

```json theme={null}
{
  "status": "replayed",
  "targetUrl": "https://target.example/webhook",
  "targetResponseCode": 200,
  "targetResponseBody": "OK",
  "strippedHeaders": ["host", "content-length"]
}
```

## Error responses

**Missing destination URL:**

```json theme={null}
{
  "error": "Missing 'url' parameter"
}
```

**SSRF or DNS validation failure:**

```json theme={null}
{
  "error": "URL resolves to internal/reserved IP range"
}
```

```json theme={null}
{
  "error": "Unable to resolve hostname"
}
```

**Timeout after all retry attempts (504):**

```json theme={null}
{
  "error": "Replay Failed",
  "message": "Target destination timed out after 3 attempts (10s timeout per attempt)",
  "code": "ECONNABORTED"
}
```

## Retry and timeout settings

You can tune replay behavior in Actor input:

| Setting            | Description                                                                                       |
| ------------------ | ------------------------------------------------------------------------------------------------- |
| `replayMaxRetries` | Number of delivery attempts before marking the replay as failed                                   |
| `replayTimeoutMs`  | Per-attempt timeout in milliseconds. A dead downstream does not hang the actor beyond this value. |

When all retry attempts time out, the server returns `504 Gateway Timeout` with a machine-readable `code` field when one is available.
