Test Plaid Webhooks Locally (Receive Plaid Webhooks on localhost)
Test Plaid webhooks locally and receive them on localhost without deploying. Inspect the real payload, forward to your handler, and verify the signature.

You are building a Plaid integration and you need to watch your handler react to a real event. The problem hits immediately: Plaid will only POST to a public URL, and your handler is running on localhost:8080. Plaid has no way to reach it.
The usual workarounds are slow. Deploying to a staging environment for every code change kills your iteration speed. Copying a sample payload out of the docs into curl gives you a guess at the real request, not the exact headers and body Plaid actually sends. What you really want is to test Plaid webhooks locally — real events, hitting your local handler, on a URL that does not change every time you restart.
This guide shows how to do exactly that.
Why testing Plaid webhooks locally is tricky
A webhook is just an HTTP request that Plaid sends to a URL when something changes. Plaid lives on the public internet; your dev machine usually does not. It sits behind a router, a corporate firewall, or both, with no public IP and no inbound ports open.
So you need something in the middle: a public endpoint Plaid can hit that relays each request down to your laptop without you opening a single firewall port. That is what Webhook Relay does — and unlike a random tunnel URL, the endpoint is stable, so you configure Plaid once and never touch it again.
Step 1: Inspect the real payload with Webhook Bin
Before you write any handler code, find out what Plaid actually sends. Open the free Webhook Bin — no signup — and you get an instant public URL.
- Copy the Webhook Bin URL.
- Set the webhook URL in the Plaid Dashboard under Team Settings → Webhooks, or pass
webhookwhen you create an Item via the API. - Trigger a real event and inspect the captured request.
You will see the full body and every header. The body is JSON keyed by webhook_type (e.g. TRANSACTIONS) and webhook_code (e.g. SYNC_UPDATES_AVAILABLE), plus an item_id and product-specific fields. You react to the type/code, then call the Plaid API to fetch the actual data.
Now you know the exact shape of the data before writing a line of code. For more on this approach, see How to test webhooks and What is a webhook.
Step 2: Forward the events to localhost with the relay agent
Once you know the payload, route those same events into your local handler. Sign up for Webhook Relay, install the relay agent (CLI or Docker), and create a bucket — say plaid. The bucket gives you a stable public input endpoint.
Start forwarding to your local server:
relay forward --bucket plaid http://localhost:8080/webhook
The agent opens an outbound connection to Webhook Relay and streams every incoming request down to http://localhost:8080/webhook. Because the connection is outbound, there are no firewall ports to open and no public IP needed — this works from your laptop, behind a corporate proxy, or inside a Kubernetes cluster. Running in Docker? The same command works in the official webhookrelay/webhookrelayd image. Full details are in the localhost forwarding docs.
Now point the Plaid webhook at your Webhook Relay endpoint (or create it there from the start), trigger an event, and watch it arrive on localhost.
Plaid-specific configuration and quirks
A few Plaid details worth knowing:
- Where to set it: the Plaid Dashboard (Team Settings → Webhooks) for a default URL, or per-Item by passing
webhookat Item creation. - Events: webhooks are grouped by
webhook_typeandwebhook_code— e.g.TRANSACTIONS/SYNC_UPDATES_AVAILABLE. The webhook is a notification; you then call the API to pull the data. - Sandbox: use the Plaid Sandbox and
/sandbox/item/fire_webhookto trigger test webhooks into your bin while you build. - Verification: JWT/ES256, not HMAC — see the verification note below.
Step 3: Verify the Plaid webhook signature
Plaid's verification is unusual: rather than a shared-secret HMAC, it sends a JWT (JWS signed with ES256) in the Plaid-Verification header. To verify, read the JWT header's kid, fetch the matching public key from Plaid's /webhook_verification_key/get endpoint (cache it; keys rotate), validate the JWT signature, check the iat is recent, and confirm a SHA-256 of the raw request body equals the JWT's request_body_sha256 claim. Only then trust the payload.
To sanity-check an HMAC implementation, paste a captured body, your secret, and the received signature into the free HMAC signature verifier. For language-specific code and the common pitfalls (reading the body after a JSON parser has already consumed it, timing-safe comparison), read Verify a webhook signature.
Replay and iterate
This is where local development gets fast:
- Replay from Webhook Relay — past requests are stored on your bucket, so you can resend a captured event against your handler without touching Plaid at all.
- Iterate on your handler by editing code and replaying the same delivery until it behaves correctly. No commits, no pushes, no deploys just to test a single code path.
- Keep
relay forwardrunning while you work — events stream straight tolocalhostas you trigger them in Plaid.
Because the Webhook Relay endpoint is stable, you can stop and restart the agent, reboot your machine, or come back next week — the Plaid configuration never needs to change.
Get started
- Inspect the real payload in the free Webhook Bin — no signup needed.
- Create a Webhook Relay account, install the agent, and run
relay forward --bucket plaid http://localhost:8080/webhook. - Point your Plaid webhook at the stable endpoint, trigger an event, and watch it hit
localhost.
You will be testing real Plaid events against your local handler in a few minutes — no deploys, no open firewall ports, and a URL you configure exactly once.
