Skip to Content
LaunchfastDocs

Testing payments locally

Dodo can't reach localhost, so your plan won't unlock after a test payment on your computer. Use a tunnel to receive webhooks while developing.

On your computer, checkout works, but the plan never unlocks: Dodo sends the webhook to a public URL, and localhost isn't one. A tunnel gives your local app a temporary public address.

Start the app

npm run dev

Start a tunnel

In a second terminal:

npx cloudflared tunnel --url http://localhost:3000

No account needed. It prints an address like https://random-words.trycloudflare.com.

Register the webhook in test mode

In Dodo, with the Live Mode switch off:

  1. Developer → Webhooks → Add endpoint.
  2. URL: https://<tunnel-address>/api/webhooks/dodo.
  3. Select all events, then Create endpoint.
  4. Copy the signing secret from the Overview tab.

Save the secret and restart

.env.local
DODO_PAYMENTS_WEBHOOK_SECRET=whsec_…

Stop npm run dev with Ctrl+C and start it again, so it reads the new value.

Pay with a test card

Open your site at localhost, buy a plan, and pay with a test card:

CardExpiryCVVResult
4242 4242 4242 424206/32123Success (US Visa)
4576 2389 1277 145006/32123Success (Indian Visa)
4000 0000 0000 000206/32123Declined
4000 0000 0000 034112/34123Pays now, fails at the next renewal

UPI in test mode: success@upi or failure@upi. More in Dodo's testing guide.

Your npm run dev terminal shows POST /api/webhooks/dodo 200, and the dashboard unlocks the plan.

Quick tunnels change address

A free Cloudflare quick tunnel gets a new address each time you start it. Update the webhook URL in Dodo each time (the secret stays the same if you edit the endpoint), or use a named tunnel or a paid ngrok domain for a fixed address.

Testing renewals, cancellations and refunds

  • Cancellation: open Manage billing on the dashboard and cancel. The dashboard shows "Cancels on [date]".
  • Failed renewal: subscribe with 4000 0000 0000 0341. The next charge fails and the subscription goes on_hold.
  • Refund: refund the payment in the Dodo dashboard. A full refund removes access from a one-time purchase.
  • Resend an event: open the endpoint in Developer → Webhooks and resend it from the delivery log. Handlers are safe to run twice.

On this page