My aim is to send an email to the user when a Laravel cashier subscription is created (I use stripe checkout) but my cashier event listener isn’t able to find a user with the given stripe customer ID.
My guess is that I’m looking for the customer ID too soon in the subscription flow before it can be added by Cashier, I can see the webhook terminal output and it processes the subscription but when I debug my listener, the user query is null. (It can’t find a user with that customer id)
class StripeEventListener
{
public function handle(WebhookReceived $event): void
{
// New subscription
if ($event->payload['type'] === 'customer.subscription.created') {
$customerId = $event->payload['data']['object']['customer'];
$user = User::where('stripe_id', $customerId)->first();
Log::debug('data from listener', ['user_result' => $user, 'customer_id' => $customerId]);
if ($user) {
Mail::to($user)->queue(new NewSubscriptionMail($user));
}
}
}
}
The log has the following (from a feature test)
[2023-11-08 13:53:37] local.DEBUG: data from listener
{"user_result":null,"customer_id":"cus_Oy8Tp1jrJ8ORq9"}
As I use Stripe Checkout, my controller redirects to Stripe and it doesn’t handle any subscription creation itself, my only option is to listen for the event.
If anybody has any ideas, I’d really appreciate it.
2
Answers
In stripe you’ll need to first register the client in order to proceed with transactions, so for example in my LoginController I’ve something like this:
After the login is processed:
You can even update the balance from stripe to the user right after:
In your User model you make sure to have the data synced between stripe and your app:
Then you can perform a transaction in your controller or whenever you’re doing it:
Now you can expect for webhook events, since you’re waiting for the
customer.subscription.created
I strongly recommend that you use thecustomer.subscription.updated
event, since thecreated
it’s created before the subscription is even confirmed, so you’ll be sending emails even when is just a intent of a subscription or transaction.You can do it like this to handle more than one type of
$event
If you follow the Cashier docs, you’ll see there’s a section specifically on using Checkout to create subscriptions: https://laravel.com/docs/10.x/billing#subscription-checkouts
You should be redirecting from your controller by chaining a
checkout
call to anewSubscription
call:If you do, then Cashier creates the customer in Stripe for you (if needed) before redirected to checkout: https://github.com/laravel/cashier-stripe/blob/503d6a0ee03b4a070ee0de086eb248738debd3d7/src/Checkout.php#L80
You then also don’t need to explicitly handle checkout-related webhooks because again, Cashier’s built-in webhook controller will create the subscription records in your database based on the webhook events Stripe sends.
So if you are using Cashier, then you shouldn’t be trying to manually create checkout sessions, or manually handle subscription webhooks.