> ## 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.

# Capture and inspect incoming webhook requests

> Every request sent to your webhook URL is captured in full: method, headers, query params, body, response, timing, IP, and signature state.

Every request that hits your webhook URL is captured automatically — no configuration required beyond generating your endpoints. The full request envelope is stored and made available through the `/logs` API immediately after capture, so you can inspect exactly what your webhook provider sent.

## What gets captured

Each captured event includes:

| Field                                  | Description                                                                                   |
| -------------------------------------- | --------------------------------------------------------------------------------------------- |
| `method`                               | HTTP method (`POST`, `GET`, etc.)                                                             |
| `headers`                              | All request headers (sensitive headers are redacted when `maskSensitiveData` is enabled)      |
| `query`                                | Parsed query string parameters                                                                |
| `body`                                 | Request body, parsed as a structured object when `enableJSONParsing` is on                    |
| `responseBody`                         | The response body sent back to the caller                                                     |
| `responseHeaders`                      | The response headers returned to the caller                                                   |
| `size`                                 | Body size in bytes                                                                            |
| `processingTime`                       | Server-side processing time in milliseconds (excludes any configured `responseDelayMs` delay) |
| `remoteIp`                             | Source IP address                                                                             |
| `signatureValid` / `signatureProvider` | Signature verification result, when configured                                                |
| `timestamp`                            | ISO 8601 capture time                                                                         |
| `statusCode`                           | HTTP status code returned to the caller                                                       |

## Sending requests to your webhook URL

Use any HTTP method. The path is:

```text theme={null}
ANY /webhook/:id
```

Replace `:id` with your active webhook ID (for example, `wh_demo123`).

```bash theme={null}
curl -X POST "https://<run-id>.runs.apify.net/webhook/wh_demo123" \
  -H "Content-Type: application/json" \
  -d '{"event":"payment.success","provider":"stripe","amount":9999}'
```

### Overriding the response status per request

Add `__status` as a query parameter to force a specific HTTP status code for that request only. This is useful for testing how your client handles error responses without changing the global `defaultResponseCode` setting.

```bash theme={null}
curl "https://<run-id>.runs.apify.net/webhook/wh_demo123?__status=503"
```

```json theme={null}
{
  "message": "Webhook received with status 503",
  "webhookId": "wh_demo123"
}
```

## Querying captured events

### List events: `GET /logs`

Use `/logs` to search and filter captured events. All parameters are optional.

```bash theme={null}
curl "https://<run-id>.runs.apify.net/logs?webhookId=wh_demo123&limit=50"
```

**Common filter examples:**

```text theme={null}
# Filter by webhook ID
/logs?webhookId=wh_demo123

# Filter by HTTP method
/logs?method=POST

# Filter by status code range
/logs?statusCode[gte]=400&statusCode[lte]=499

# Filter by timestamp range
/logs?startTime=2026-01-01T00:00:00Z&endTime=2026-01-02T00:00:00Z

# Filter by a field inside the JSON body
/logs?body[event]=payment.success
```

Range filters use bracket notation: `field[gte]`, `field[lte]`, `field[gt]`, `field[lt]`. Body, header, and query filters support both free-text substring search and keyed access like `body[data.id]=evt_123`.

**Response:**

```json theme={null}
{
  "count": 1,
  "total": 150,
  "items": [
    {
      "id": "evt_demo123",
      "timestamp": "2026-04-02T10:25:02.319Z",
      "webhookId": "wh_demo123",
      "requestId": "req_demo123",
      "method": "POST",
      "statusCode": 200,
      "contentType": "application/json",
      "processingTime": 10,
      "size": 61,
      "remoteIp": "203.0.113.10",
      "requestUrl": "/webhook/wh_demo123",
      "body": {
        "event": "payment.success",
        "provider": "stripe",
        "amount": 9999
      }
    }
  ],
  "nextOffset": 100,
  "nextPageUrl": "https://<run-id>.runs.apify.net/logs?webhookId=wh_demo123&limit=100&offset=100"
}
```

### Get a single event: `GET /logs/:logId`

```bash theme={null}
curl "https://<run-id>.runs.apify.net/logs/evt_demo123"
```

Returns the full event record including headers, query, body, response headers, and response body.

### Get the raw payload: `GET /logs/:logId/payload`

```bash theme={null}
curl "https://<run-id>.runs.apify.net/logs/evt_demo123/payload"
```

Returns the original stored payload with its original `Content-Type`. If the payload was offloaded to storage due to its size, it is hydrated on demand.

## JSON parsing

When `enableJSONParsing` is enabled (the default), `application/json` request bodies are automatically parsed into structured objects before storage. This lets you use keyed filters like `body[event]=payment.success` in `/logs` queries. Without this setting, the body is stored as a raw string and only substring search is available.

## Large payload handling

The `maxPayloadSize` setting controls the maximum accepted body size in bytes. Requests that exceed this limit are rejected with `413 Payload Too Large`.

For payloads that are within the accepted limit but still large, the runtime offloads the payload content to Key-Value Store rather than keeping it inline. The event remains fully queryable through `/logs`, and the payload is hydrated when you call `GET /logs/:logId/payload`.

## Capture settings reference

<ParamField query="urlCount" type="integer" default="3">
  Number of unique webhook endpoints to generate for this run. Accepted range: 1–50.
</ParamField>

<ParamField query="retentionHours" type="integer" default="24">
  How long generated webhook URLs stay active, in hours. Accepted range: 1–168. After expiry, the webhook stops accepting traffic and its logs are removed from `/logs` during the next cleanup cycle (up to 10 minutes later). Logs already pushed to the dataset are retained independently.
</ParamField>

<ParamField query="maxPayloadSize" type="integer" default="10485760">
  Maximum request body size in bytes. Requests exceeding this are rejected with `413`. Values above 100 MB are clamped. Default is 10 MB.
</ParamField>

<ParamField query="enableJSONParsing" type="boolean" default="true">
  When enabled, `application/json` bodies are parsed into structured objects for keyed search in `/logs`. When disabled, the body is stored as a raw string.
</ParamField>
