Stripe Connect Payment Notifications - Putting it all together

We’ve hit a snag with our Stripe Connect/S2M integration.
Can anyone please help spot what we have missed?

We have S2M Pro:

• Our custom subscription payment form is working - it triggers in Stripe creating the customer, their subscription, and linking them to the Stripe Connect Account for transfers etc.

• Our WP Admin/DB tables (wp_user and wp_usermeta) are being updated with the Stripe Customer ID, Subscription ID and our custom tables and fields are updated to track Connected Accounts - so S2M and Stripe are talking

But we cannot get the User’s S2M level/role to upgrade or downgrade when the subscription payment is made or cancelled.

We’ve tested with with standard S2M Pro forms and they work fine at creating customers, subscriptions and user level changes. So again we know that S2M and Stripe are ‘talking’. But as far as we can tell, the Pro forms cannot handle the data needs of Stripe Connect (eg. destination account, direct charges instructions etc.). So we must use our custom form. But we have this persistent problem with S2M levels not changing. We also tried trigger changes by manually cancelling subscriptions in Stripe, but no level demotion happens.

The Stripe webhook logs say the events are being sent successfully. No errors.

We figured that to make the level changes we needed custom Payment Notification and Cancellation Notification handlers, so we followed these instructions - https://s2member.com/kb-article/building-an-api-notification-handler-webhook/

We have payment notification and cancellation notification php files (coded as per the instructions, which we get no errors for) which are placed in our mu-plugins folder.

We are using the standard S2M Stripe webhook endpoint :
ourdomain.com/?s2member_pro_stripe_notify=1

And yet the User levels don’t change.

Any suggestions on what we are missing with our setup?

Here is our payment notification code:

<?php add_action('init', 's2_payment_notification'); function s2_payment_notification() { if(!empty($_GET['s2_payment_notification']) && $_GET['s2_payment_notification'] === 'yes') // ↑ In my URL, I have `?s2_payment_notification=yes`, that's what I'm looking for here. { if(!empty($_GET['user_id'])) // In my URL, I have `&user_id=%%user_id that's what I'm looking for here. { $user = $user_id; $user = new WP_User($user_id); $user->set_role("s2member_level4"); // Here I might perform any number of tasks related to this user. } exit; // We can exit here. There's no reason to continue loading WordPress in this case. } } ?>