About receive-webhooks
receive-webhooks is a skill for receiving inbound webhooks through ngrok and verifying signatures at the edge, for local testing or production. It can forward verified requests to a local port or an internal receiver, avoiding signature-checking code in the application.
Key features
- 01Verify provider signatures at the ngrok edge
- 02Forward valid requests to a local port
- 03Forward requests to an internal receiver
- 04Route multiple providers by path
- 05Store secrets in Vault or environment variables
Use cases
- 01Debug inbound webhooks locally
- 02Keep a production receiver off the public internet
- 03Handle multiple webhook providers at one gateway
- 04Reject invalid signatures before requests reach systems
MCP support
The skill can use the ngrok MCP server to create a Vault and secrets, and query request records in the Traffic Inspector.
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ ngrok/ skills --skill receive-webhooksAfter installing, type/receive-webhooksin Claude Code to confirm it loaded.
Bundled filesreferences/providers.md
Details
From the project READMEReceive webhooks
Receive an inbound webhook, verify the provider's signature at ngrok's edge, and deliver it to the user's service - without writing verification code and, when wanted, without exposing the service publicly.
Before you start
Auth is required (ngrok-setup). This job uses a Traffic Policy - pull the verify-webhook and forward-internal mechanics, and the endpoint choice, from ngrok-engine.
Core pattern (every case)
Two actions in sequence:
verify-webhook- validate the signature (fails closed with 403 unlessenforce: false).- deliver - to a local port for testing, or
forward-internalto a private receiver for production.
on_http_request:
- actions:
- type: verify-webhook
config:
provider: stripe
secret: "${secrets.get('webhooks', 'stripe-signing-secret')}"
- type: forward-internal
config: { url: https://billing.internal }
Provider list, per-provider secret setup, replay protection, and endpoint-verification challenges: references/providers.md.
Choose the shape
- Testing / debugging locally -> agent endpoint forwarding to a local port. Fastest. Verify, then deliver to the port instead of
forward-internal. - Production / private / regulated / shared gateway -> cloud endpoint (public, always-on) running the verify+route policy, forwarding to an internal endpoint that holds the receiver off the public internet. See
ngrok-enginefor why cloud+internal here.
Apply it
Attach the policy and bring up the endpoint(s) on the user's surface - see ngrok-surfaces. The policy body is identical on every surface; only attachment differs.
Give the user the public URL to paste into the provider's webhook settings.
Worked scenarios (same mechanism, different emphasis)
- "Keep our receiver off the public internet." Cloud endpoint verifies at the edge;
forward-internalto an internal-bound receiver. No inbound firewall ports; the agent connects outbound on 443. - "Regulated / compliant delivery." Same, plus: secrets in a Vault (not plaintext), signatures verified before anything touches your systems, and you can add IP allowlists or JWT checks in the same policy. Verification fails closed.
- "One gateway for all providers." Multiple path-routed rules in one policy (
/stripe,/github, ..), each verifying its provider then forwarding to the right internal service - verification, routing, and secrets in one place instead of per-service code.
Verify it works
- Trigger a test event from the provider dashboard, or
curlwith a valid signature header. - Valid -> reaches the upstream; invalid -> 403 at the edge.
- Inspect exact headers/body of each inbound request in the agent's web inspector (default http://localhost:4040) or the dashboard Traffic Inspector.
Notes for agents
- Don't tell the user to write signature-verification code - the whole point is that
verify-webhookreplaces it. - Never hardcode the signing secret; use a Vault or env var.
- Do not ask the user to paste the signing secret into the chat, and do not accept one offered that way. Have them put it in a Vault themselves, or in an env var, and reference it from the policy. When
ngrok-surfaces("Account resources") picks the ngrok MCP server, create the vault withgw_create_vaultand the secret withgw_create_secret. The secret tool gives the user a dashboard form for the value, so no API key is needed. Otherwise use the dashboard orngrok api secrets create. Awhsec_...in a transcript is a leaked secret. - Nothing that rewrites the body may run before
verify-webhook, or the signature check breaks. - If the ngrok MCP server is connected,
gw_query_traffic_inspectorshows whether the provider's request arrived and what the endpoint returned. Check it before you debug the receiver.