Testing Stripe webhooks with ngrok

January 8, 2018

I have an application that has a 30 day free trial and I need to do specific logic when an account is “activated” ie. their card gets charged for the first time.

Do I really need to build and deploy a new development server every time I want to test a webhook?

Currently, I can enter a development server for use with Stripe’s Webhooks, however it would be impossible to do locally, since entering “localhost” into the webhook URL would not resolve to your localhost.

This is where ngrok fits in. Their documentation describes it as a “Secure tunnel to localhost”. What this means is it will setup a public url, ie. https://bf2e4c96.ngrok.io which gets forwarded to your local machine. So in this case, if my application has a webhook setup at ‘webhook/stripe’, the webhook I would put into stripe is https://bf2e4c96.ngrok.io/webhook/stripe.

Now I can setup scenarios using stripe to charge my card at a later time and it will use that webhook to hit my local machine which will test the webhook logic locally. The alternative would require code to be deployed to a publicly accessible server for stripe to hit, thus making every test scenario require a commit and deploy.

The webhook built in to Laravel Cashier is:

$method = 'handle'.studly_case(str_replace('.', '_', $payload['type']));

if (method_exists($this, $method)) {
     return $this->{$method}($payload);
} else {
     return $this->missingMethod();

This allows you to create specific methods for each event you want to handle. Say for example we want to handle a Failed Payment, the Stripe event is invoice.payment_failed, thus we would create function:

public function handleInvoicePaymentFailed( $payload ) {
   // app logic if a payment fails

ngrok can also create a Valid TLS Certificate to allow you a valid https url, as stripe will validate the webhook’s certificate before sending any data.

Other examples I’ve recently encountered which have required local webhook testing include:

  • emailing a customer when a subscription payment fails
  • dispute filing alerts
  • integration with tax / accounting software

You can use Laravel Valet to set up a local ngrok tunnel to your application in one command.

valet share