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

# Verify webhook signatures from Stripe, GitHub, and more

> Validate that incoming webhooks were sent by your provider using HMAC signature verification for Stripe, Shopify, GitHub, Slack, and custom providers.

Webhook URLs are public by default, which means anyone who discovers your endpoint URL could post arbitrary payloads to it. Signature verification solves this by checking a cryptographic signature that only your provider can produce. If the signature is missing or does not match, the actor rejects the request with a `401` response and records the failure in the captured event.

## Supported providers

| Provider | Signature header        | Algorithm                  |
| -------- | ----------------------- | -------------------------- |
| Stripe   | `Stripe-Signature`      | HMAC-SHA256 with timestamp |
| Shopify  | `X-Shopify-Hmac-Sha256` | Base64 HMAC-SHA256         |
| GitHub   | `X-Hub-Signature-256`   | `sha256=<hex>`             |
| Slack    | `X-Slack-Signature`     | `v0=<hex>` with timestamp  |
| Custom   | Configurable            | Configurable               |

## Configure signature verification

Signature verification is configured through the `signatureVerification` input object. The signing secret is stored separately in the `signatureVerificationSecret` field so it stays masked in the Apify UI.

### Stripe

```json theme={null}
{
  "signatureVerificationSecret": "whsec_your_stripe_secret",
  "signatureVerification": {
    "provider": "stripe",
    "tolerance": 300
  }
}
```

`tolerance` sets the maximum age in seconds of the request timestamp before the actor treats it as a replay attack. The default is `300` seconds (5 minutes). Accepted range is `60`–`3600`.

### Shopify

```json theme={null}
{
  "signatureVerificationSecret": "your_shopify_signing_secret",
  "signatureVerification": {
    "provider": "shopify"
  }
}
```

### GitHub

```json theme={null}
{
  "signatureVerificationSecret": "your_github_webhook_secret",
  "signatureVerification": {
    "provider": "github"
  }
}
```

### Slack

```json theme={null}
{
  "signatureVerificationSecret": "your_slack_signing_secret",
  "signatureVerification": {
    "provider": "slack",
    "tolerance": 300
  }
}
```

### Custom HMAC provider

Use `provider: "custom"` when your provider uses HMAC but is not one of the built-in presets. You must supply the header name, algorithm, and encoding. Optionally supply `timestampKey` for replay protection.

```json theme={null}
{
  "signatureVerificationSecret": "your_custom_hmac_secret",
  "signatureVerification": {
    "provider": "custom",
    "headerName": "X-My-Signature",
    "timestampKey": "X-My-Timestamp",
    "algorithm": "sha256",
    "encoding": "hex",
    "tolerance": 300
  }
}
```

| Custom field   | Values           | Description                                               |
| -------------- | ---------------- | --------------------------------------------------------- |
| `headerName`   | string           | The request header that contains the signature            |
| `timestampKey` | string           | The request header that contains the timestamp (optional) |
| `algorithm`    | `sha256`, `sha1` | HMAC algorithm; defaults to `sha256`                      |
| `encoding`     | `hex`, `base64`  | Signature encoding; defaults to `hex`                     |

## Signature result fields on captured events

Every captured event includes two fields that reflect the outcome of signature verification:

| Field               | Type    | Description                                                                                      |
| ------------------- | ------- | ------------------------------------------------------------------------------------------------ |
| `signatureValid`    | boolean | `true` if the signature matched, `false` if it failed, absent if verification was not configured |
| `signatureProvider` | string  | The provider name, e.g. `stripe`, `github`                                                       |

You can filter the `/logs` endpoint by these fields:

```bash theme={null}
# Find all events with invalid signatures
curl "https://<run-id>.runs.apify.net/logs?signatureValid=false" \
  -H "Authorization: Bearer your-key"
```

## What happens on failure

When signature verification fails, the actor:

1. Returns a `401` response to the sender
2. Records the event with `signatureValid: false`
3. Optionally sends an alert to Slack or Discord if `signature_invalid` is in your `alertOn` list

## Alert on signature failures

Add `"signature_invalid"` to `alertOn` to get notified immediately when a request fails verification:

```json theme={null}
{
  "alertOn": ["error", "5xx", "signature_invalid"],
  "alerts": {
    "slack": {
      "webhookUrl": "https://hooks.slack.com/services/T000/B000/XXXX"
    }
  }
}
```
