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

# Webhook Gateway

> Centralize webhook validation and routing from third-party providers like Stripe, Twilio, and Slack to secure your integrations and eliminate repetitive implementation.

export const domain_0 = undefined

Instead of implementing webhook validation and routing logic separately in every service, a webhook gateway provides a single, secure entry point for all third-party webhooks from providers like Stripe, Twilio, Slack, and GitHub. This centralized approach validates webhook signatures, prevents tampering, and routes authenticated requests to the appropriate internal services in production environments.

With this setup, you can:

* Validate webhook signatures from 70+ supported providers in a single place
* Route authenticated webhooks to appropriate services based on the provider
* Prevent webhook spoofing and tampering with cryptographic verification
* Standardize webhook handling across your entire infrastructure
* Apply consistent logging and monitoring to all webhook traffic

## 1. Create endpoints for your services

Start internal [Agent Endpoints](/gateway/agent-endpoints/) for the services that will handle webhooks from different providers.
You can also use one of the [SDKs](/agent-sdks) or the [Kubernetes Operator](/k8s).

For a payment service handling Stripe webhooks:

```bash theme={null}
ngrok http $PAYMENT_SERVICE_PORT --url https://payment-service.internal
```

For a notification service handling Slack webhooks:

```bash theme={null}
ngrok http $NOTIFICATION_SERVICE_PORT --url https://notification-service.internal
```

For a deployment service handling GitHub webhooks:

```bash theme={null}
ngrok http $DEPLOYMENT_SERVICE_PORT --url https://deployment-service.internal
```

## 2. Reserve a domain

Navigate to the [**Domains** section](https://dashboard.ngrok.com/domains) of the ngrok dashboard and click **New +** to reserve a free static domain like {<code>{domain_0}</code> || `https://your-service.ngrok.app`} or a [custom domain](/gateway/custom-domains/) you already own.

We'll refer to this domain as `$NGROK_DOMAIN` from here on out.

## 3. Create a Cloud Endpoint

Navigate to the [**Endpoints** section](https://dashboard.ngrok.com/endpoints?sortBy=updatedAt\&orderBy=desc) of the ngrok dashboard, then click **New +** and **Cloud Endpoint**.

In the **URL** field, enter the domain you just reserved to finish creating your [Cloud Endpoint](/gateway/cloud-endpoints/).

## 4. (Optional) Create a vault and secrets

For production environments, store your webhook secrets securely using [Secrets for Traffic Policy](/traffic-policy/secrets). This step is optional—you can also use plaintext secrets directly in your policy.

Create a vault to store your webhook secrets:

```bash theme={null}
ngrok api vaults create --name "webhook-secrets" --description "Webhook validation secrets"
```

Add your credentials to the vault, replacing the names and values, plus changing `$VAULT_ID` to match the vault ID from the response:

```bash theme={null}
# Add Stripe webhook secret
ngrok api secrets create \
  --name "stripe-secret" \
  --value "your_stripe_secret_here" \
  --vault-id "vault_2yNPzuk6GjHrx3mlOCkJK42RsdR"

# Add Slack webhook secret
ngrok api secrets create \
  --name "slack-secret" \
  --value "your_slack_verification_token_here" \
  --vault-id "vault_2yNPzuk6GjHrx3mlOCkJK42RsdR"

# Add GitHub webhook secret
ngrok api secrets create \
  --name "github-secret" \
  --value "your_github_webhook_secret_here" \
  --vault-id "vault_2yNPzuk6GjHrx3mlOCkJK42RsdR"
```

## 5. Apply Traffic Policy to your Cloud Endpoint

While viewing your new Cloud Endpoint in the dashboard, copy one of the policies below and paste it into the Traffic Policy editor.

<Tabs>
  <Tab title="Using Secrets (Recommended)">
    ```yaml theme={null}
    on_http_request:
      - expressions:
          # Route Stripe webhooks to payment service
          - "req.url.path.startsWith('/stripe')"
        actions:
          - type: verify-webhook
            config:
              provider: stripe
              secret: "${secrets.get('webhook-secrets', 'stripe-secret')}"
          - type: forward-internal
            config:
              url: https://payment-service.internal

      - expressions:
          # Route Slack webhooks to notification service
          - "req.url.path.startsWith('/slack')"
        actions:
          - type: verify-webhook
            config:
              provider: slack
              secret: "${secrets.get('webhook-secrets', 'slack-secret')}"
          - type: forward-internal
            config:
              url: https://notification-service.internal

      - expressions:
          # Route GitHub webhooks to deployment service
          - "req.url.path.startsWith('/github')"
        actions:
          - type: verify-webhook
            config:
              provider: github
              secret: "${secrets.get('webhook-secrets', 'github-secret')}"
          - type: forward-internal
            config:
              url: https://deployment-service.internal
    ```

    **What's happening here?** This policy routes incoming webhook requests based on their URL path. Each route first validates the webhook signature using secrets stored in your encrypted vault, then forwards authenticated requests to the appropriate internal service. If signature verification fails, the request is automatically rejected, protecting your services from spoofed or tampered webhooks.
  </Tab>

  <Tab title="Using plaintext secrets">
    ```yaml theme={null}
    on_http_request:
      - expressions:
          # Route Stripe webhooks to payment service
          - "req.url.path.startsWith('/stripe')"
        actions:
          - type: verify-webhook
            config:
              provider: stripe
              secret: "whsec_your_stripe_secret_here"
          - type: forward-internal
            config:
              url: https://payment-service.internal

      - expressions:
          # Route Slack webhooks to notification service
          - "req.url.path.startsWith('/slack')"
        actions:
          - type: verify-webhook
            config:
              provider: slack
              secret: "your_slack_verification_token_here"
          - type: forward-internal
            config:
              url: https://notification-service.internal

      - expressions:
          # Route GitHub webhooks to deployment service
          - "req.url.path.startsWith('/github')"
        actions:
          - type: verify-webhook
            config:
              provider: github
              secret: "your_github_webhook_secret_here"
          - type: forward-internal
            config:
              url: https://deployment-service.internal
    ```

    **What's happening here?** This policy routes incoming webhook requests based on their URL path. Each route first validates the webhook signature using plaintext secrets, then forwards authenticated requests to the appropriate internal service. If signature verification fails, the request is automatically rejected, protecting your services from spoofed or tampered webhooks.
  </Tab>
</Tabs>

## 6. Try out your endpoint

Visit the domain you reserved either in the browser or in the terminal using a tool like `curl`.
You should see the app or service at the port connected to your internal Agent Endpoint.

Configure your webhook endpoints in each provider's dashboard:

* **Stripe**: `https://$NGROK_DOMAIN/stripe`
* **Slack**: `https://$NGROK_DOMAIN/slack`
* **GitHub**: `https://$NGROK_DOMAIN/github`

When webhooks are sent from these providers, they'll be validated and routed to your internal services automatically.

## What's next?

* Read about [other gateway shapes](https://ngrok.com/blog-post/api-gateway-shapes-patterns-2025) you can build with ngrok
* View the complete list of [70+ supported webhook providers](/traffic-policy/actions/verify-webhook/#supported-providers) including Twilio, Shopify, and DocuSign
* Add the [`log` action](/traffic-policy/actions/log) to send webhook events to your observability platform for monitoring and debugging
* Use [Traffic Inspector](https://dashboard.ngrok.com/traffic-inspector) to monitor webhook delivery and troubleshoot validation failures
* Learn more about [webhook signature verification](/traffic-policy/actions/verify-webhook) and security best practices
