Local Stripe Webhooks Testing Guide (Laravel + ngrok or Stripe CLI)



Testing Stripe webhooks locally can be difficult when Stripe servers cannot directly access your local machine. This guide explains how to safely expose your local environment using Stripe CLI or Ngrok to test webhook events like (payment confirmations, refunds, disputes, subscription updates, and connected account verification), inspect payloads, and debug webhook issues efficiently.

You can use either the Stripe CLI or Ngrok, but you should not use both at the same time.

Feature / Use Case

Option A: Stripe CLI (Recommended)

Option B: Ngrok + Dashboard

Best For

Fast development & rapid local iteration

Testing real frontend checkouts & live redirects

Setup Speed

Blazing fast (under 2 minutes)

Moderate (requires dashboard configuration)

Key Advantage

Trigger mock events instantly via terminal

Shared team/QA links & real HTTPS simulation

Network Flow

Stripe CLI → Local server directly

Stripe → Stripe Dashboard → ngrok → Local server

Phase 1 — Start Your Local Environment

Before configuring Stripe, make sure your local backend application is up and running.

If you are using standard Laravel:

Example: php artisan serve Or Docker/Sail: ./vendor/bin/sail up

(Note: If your app runs on a different port than 8000, adjust the port numbers in the steps below accordingly).

Phase 2 — Choose Your Testing Workflow

Choose one of the following paths to route Stripe events to your machine.

OPTION A: Stripe CLI Workflow (Fastest)

The Stripe CLI bypasses the need for web browsers and dashboards by streaming events directly to your terminal.

1. Install & Authenticate the CLI

Download and install the CLI via the Official Stripe CLI Documentation. Once installed, link it to your Stripe account:

stripe login

Your browser will open automatically. Pair the session with your test mode workspace.

2. Forward Events to Your Local Server

Tell the CLI to listen for events and stream them to your backend webhook route:

stripe listen --forward-to localhost:8000/api/webhooks/stripe

With stripe listen, the flow is:

Stripe → Stripe CLI (cloud) → your local HTTP endpoint

3. Update Your Environment Variables

The terminal will output a unique local webhook signing secret starting with whsec_. Copy it and update your .env file:

STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxx

4. Trigger Test Events & Debug

Open a new terminal window to fire off mock events instantly:

# Test a standard successful checkoutstripe trigger checkout.session.completed
# Test a successful payment intent.  stripe trigger payment_intent.succeeded
# Test a refund.  stripe trigger charge.refunded


Watch your local logs or terminal output to verify signature validation, database updates, queue jobs, and idempotency protection.

This is an example from my local machine:




OPTION B: ngrok + Dashboard Workflow

Useful when you need a public HTTPS URL to test:

  • Testing real frontend checkout flows/redirects
  • External/mobile apps
  • Team-shared environments. 

1. Expose Your Local Server Using ngrok

Fire up ngrok to create a secure public tunnel to your local server port:

ngrok http 8000 

  • Laravel Sail → 80
  • Laravel artisan serve → 8000
  • Vite/dev server → 5173
  • Node.js apps → commonly 3000

Look at your terminal and copy the public HTTPS URL generated by ngrok:

Forwarding https://abcd-1234.ngrok-free.app -> http://localhost:8000

Step 2: Inspect Requests in Real Time

Open the ngrok inspection dashboard in your browser:

http://127.0.0.1:4040/inspect/http 

This helps inspect:

  • payloads,
  • headers,
  • retries,
  • response codes.

3. Configure Stripe Environment Variables

Update your local .env file with your Stripe credentials and webhook configuration.

# Stripe API Keys
STRIPE_KEY=pk_test_...
STRIPE_SECRET=sk_test_...

# Public ngrok forwarding URL
STRIPE_WEBHOOK_URL=https://abcd-1234.ngrok-free.app/api/webhooks/stripe

# Stripe webhook signing secret
STRIPE_WEBHOOK_SECRET=whsec_...


4. Register Webhook Endpoint in Stripe Dashboard

  1. Go to the Stripe Dashboard Webhooks Section. (Developers → Webhooks)

  2. Click Add Endpoint.

  3. Paste your ngrok URL combined with your webhook path into the Endpoint URL field: [https://abcd-1234.ngrok-free.app/api/webhooks/stripe](https://abcd-1234.ngrok-free.app/api/webhooks/stripe)

  4. Select the specific events your application listens for.

Select the events your application listens for (recommended)


checkout.session.completed checkout.session.async_payment_succeeded checkout.session.async_payment_failed payment_intent.succeeded payment_intent.payment_failed payment_intent.canceled charge.refunded account.updated

EventPurpose
checkout.session.completedMain payment success confirmation
checkout.session.async_payment_succeededDelayed success confirmation
checkout.session.async_payment_failedDelayed payment failure
payment_intent.succeededPayment completed
payment_intent.payment_failedPayment failed
payment_intent.canceledPayment canceled
charge.refundedRefund synchronization
account.updatedStripe Connect account updates

5. Monitor Events & Replay Webhooks

You have two powerful layers for debugging when using this workflow:

  • ngrok Inspection: Open [http://127.0.0.1:4040](http://127.0.0.1:4040) in your local browser. You can inspect exact JSON payloads, headers, response times, and status codes hitting your machine in real-time.

  • Stripe Dashboard Replay: If your local server crashes or validation fails mid-test, don't re-run the whole checkout flow. Go to your Dashboard Webhook page, click on the failed event under Event History, and click Retry/Resend to push the exact same payload back to your app.


 Read more:

Stripe Webhooks: https://ngrok.com/docs/integrations/webhooks/stripe-webhooks

Comments