Here is a silly thing that I overlooked in the documentation and only found out after contacting support.
After you've followed the approval url and gave your approval, dit you execute the payment with the REST API?
https://developer.paypal.com/docs/api/payments/#payment_execute
Webhooks are only called after you've executed the payment.
The confusing part is; there is no webhook being called, when a user approves or cancels a payment. There is only a redirect back to a return url or cancel url. So you either need to monitor the redirect back to your site and trigger the execute call then, or find another way (like polling the payment) to see the status change before calling the execute call.