Docs
Everything you need to get webhooks flowing through Latch.
What is Latch?
A webhook is an HTTP request that a third-party service sends to your server when something happens: a payment succeeds in Stripe, a push lands on GitHub, an order is placed in Shopify.
Latch sits between those services and your application. You point the provider at a Latch URL instead of your own server, and Latch captures every incoming webhook: headers, body, raw bytes, all of it. You can then inspect payloads in a live feed, compare any two events side-by-side, replay them to your local dev server, or forward them in real time using the CLI. Nothing gets lost, and you can re-send any event whenever you need to.
It's built for developers who work with webhooks regularly and are tired of losing events, writing throwaway test scripts, or setting up ngrok tunnels just to debug a payload.
Quickstart
Sign in with GitHub
Go to the homepage and click "Get Started with GitHub". Latch only asks for your public profile and email (no repo access).
Create a project
On the dashboard, give your project a name (e.g. "Stripe Checkout") and optionally set a Destination URL: that's where Replay will send events. You can change both later.
Copy your Ingest URL
Each project gets a unique URL that looks like https://your-domain/api/ingest/{projectId}. Click it to copy.
Paste it into your provider
Go to your webhook provider's settings and add the Ingest URL as the endpoint. Here's where to find it in a few common services:
- Stripe: Dashboard → Developers → Webhooks → Add endpoint
- GitHub: Repository → Settings → Webhooks → Add webhook
- Shopify: Settings → Notifications → Webhooks → Create webhook
Any service that sends an HTTP POST to a URL will work; the ones above are just the most common.
Once your provider sends its first event, it'll appear on the project's live feed within a couple of seconds.
Live Event Feed
When you open a project, you see a real-time feed of incoming webhooks on the left and a detail panel on the right.
- The green dot at the top means the SSE connection is active. If it turns red, the browser is reconnecting: events you miss during that gap are backfilled automatically.
- Search searches across headers and payload values. Type any substring (an email, an event ID, an error code) and matching events filter instantly.
- Compare mode lets you select any two events and see a side-by-side diff of their payloads, with additions and deletions highlighted. Useful for spotting schema changes between webhook versions.
- Click any event to expand it. The detail panel shows received timestamp, headers (collapsible JSON tree), payload (collapsible JSON tree or raw view), and the Replay tool.
Replay
Replay re-sends a captured webhook to a URL you choose, typically your local dev server.
- It uses the original headers and body from when the webhook was first received, so your application processes the exact same payload.
- Latch adds one extra header:
X-Webhook-Replay: true. Your code can check for this if you need to distinguish replayed events from live ones. - After replaying, the response panel shows the HTTP status code your server returned, the response body, and how long it took.
- The Destination URL defaults to whatever you set on the project, but you can override it per-replay.
CLI
The CLI forwards webhooks from Latch to your local machine in real time. It's optional: you can use the dashboard without it.
Running it
No install needed. Run it directly with npx:
Copy the full command (with your project ID and token pre-filled) from the project page on the dashboard.
Commands
| Command | What it does |
|---|---|
| tunnel <projectId> | Opens a persistent tunnel connection and forwards webhooks to your local URL in real time. Built-in alternative to ngrok. |
| listen <projectId> | Connects to the project's event stream and forwards each incoming webhook to your local URL. |
| replay <eventId> | Fetches a single event by ID and forwards it to your local URL once. Useful for re-testing a specific payload. |
Flags
| Flag | Short | Description |
|---|---|---|
| --forward-to | -f | The local URL to send webhooks to. Required. |
| --token | -t | Your project's CLI token. Falls back to the LATCH_TOKEN env var if not set. |
| --api-url | -u | The Latch server URL. Defaults to http://localhost:3000. Set this to your deployed URL in production. |
Token rotation
Each project has its own CLI token. You can rotate it from the project page on the dashboard: click "Rotate Token". After rotating, any running CLI instance using the old token will fail on its next reconnection. Copy the new token and restart the CLI.
Security
- GitHub OAuth scopes: Latch requests your public profile and email. It does not request access to your repositories or organizations.
- Project isolation: every database query is scoped to your user ID. You can only see your own projects and events.
- CLI tokens: each project has a unique token for CLI authentication. Tokens can be rotated at any time from the dashboard. Latch does not store your webhook provider's signing secrets.
- Headers are preserved: Latch stores the exact headers your provider sent, including signature headers. This means you can still verify webhook signatures in your own application code after a replay.
Troubleshooting
Common questions and how to fix them.
Make sure you pasted the full Ingest URL into your provider (including the /api/ingest/{projectId} part).
If you did, try sending a test event manually to confirm the connection works:
Some providers also won't send real events until you click a "send test" button in their dashboard (Stripe, for example).
Your CLI token was probably rotated. Go to the project page on the dashboard, click "Show Token", and copy the current one. Then restart the CLI with the new token.
Check that your Destination URL is correct and that your local server is actually running on that port. The response body in the error panel usually tells you what went wrong on your server's side.
Anything that sends an HTTP POST request to a URL. Stripe, GitHub, Shopify, Twilio, Clerk, custom services. If it sends webhooks, Latch can capture them.
No. The CLI is for forwarding events to localhost in real time. If you just want to capture, inspect, search, and replay webhooks, the dashboard does all of that on its own.
Open the project, expand "Project Settings & Danger Zone", and click Delete. This is permanent: all events and replays for that project are gone.