Stripe Webhooks fail, returning 400 error or "The CSRF token could not be verified"

When setting up the Stripe webhooks to callback to the site, you might run into the problem that they fail to get through to the site, even though all the details you've entered are correct.

The most common cause of this is the Craft CSRF settings.

If you've got CSRF checks enabled, Craft needs the csrf token to be present on all inbound post requests to controllers. Because Stripe is posting to the site externally, and can't include that token as part of their request, Craft rejects the inbound call, Stripe sees a 400 error.

Because the cause of the issue is part of the Craft core, and there's no direct way to override the checks at the controller level, instead we have to fix it at the config level.

Fix

You must create an exception for the charge webhook controller route in your general config. In general.php, where you're setting the enableCsrfProtection, update it to the the following:

'enableCsrfProtection' => (!isset($_SERVER['REQUEST_URI']) || $_SERVER['REQUEST_URI'] != '/actions/charge/webhook/callback'),

That change means that you'll have CSRF protection enabled for all routes on the site except the charge webhook controller endpoint.