Stripe Webhooks: The Definitive Guide to Local Development without Tunnels
Stop restarting ngrok and updating Stripe URLs. FetchHook provides a persistent, static mailbox for your Stripe webhooks that works anywhere—locally, in serverless, or behind firewalls.
The Stripe Primitive
# Configure Stripe to send to your FetchHook URL:
# https://api.fetchhook.app/in/stash_abc123
# Then pull events whenever your script is ready:
curl https://api.fetchhook.app/api/v1/stash_abc123 \
-H "Authorization: Bearer fh_live_xxx"#How do I receive Stripe webhooks locally without ngrok?
Traditional local development requires ngrok to tunnel traffic to your machine. This is fragile: URLs change on restart, and your script must be running to receive events. FetchHook replaces the tunnel with a mailbox. Stripe 'pushes' to FetchHook, and your local script 'pulls' from FetchHook. No public IP, no changing URLs, and 24-hour persistence.
#How to handle Stripe Signature Verification in a Pull-Model?
One of the biggest pains in webhook development is verifying signatures. FetchHook offloads this. When you pull events from our API, we've already validated the Stripe-Signature. You simply check the 'signature_verified' flag in the JSON response.
Python Implementation
import requests
def get_payments():
res = requests.get("https://api.fetchhook.app/api/v1/stash_123",
headers={"Authorization": "Bearer fh_xxx"})
for event in res.json().get('events', []):
if event['signature_verified'] and event['payload']['type'] == 'payment_intent.succeeded':
print(f"Verified payment: {event['payload']['id']}")Agent Protocol Instruction