#sameed-editz_webhooks
1 messages · Page 1 of 1 (latest)
👋 Welcome to your new thread!
⏲️ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
⏱️ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.
🔗 This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1336635325946269767
📝 Have more to share? Add more details, code, screenshots, videos, etc. below.
Hi, let me help you with this.
hii
On which object do you set the metadata?
can i send u the laravel cashier code?
public function checkout(Plan $plan)
{
if (!$plan) {
return redirect()->route('pricing');
}
/** @var \App\Models\User $user **/
$user = Auth::user();
try {
if ($plan->lifetime) {
$checkoutSession = $user->checkout($plan->stripe_plan_id, [
'success_url' => route('checkout.success') . '?session_id={CHECKOUT_SESSION_ID}', // Route to redirect to after a successful payment
'cancel_url' => route('checkout.cancel'),
'metadata' => [
'plan_id' => $plan->id,
'lifetime' => true
],
]);
} else {
$checkoutSession = $user->newSubscription('default', $plan->stripe_plan_id)
->checkout([
'success_url' => route('checkout.success') . '?session_id={CHECKOUT_SESSION_ID}', // Route to redirect to after a successful payment
'cancel_url' => route('checkout.cancel'),
'metadata' => [
'plan_id' => $plan->id,
],
]);
}
session(['checkout_session_id' => $checkoutSession->id]);
return $checkoutSession;
} catch (\Exception $e) {
Log::error('Checkout failed: ' . $e->getMessage());
return redirect()->route('pricing')->with([
'status' => 'error',
'message' => 'Checkout process failed. Please try again.',
]);
}
}
hey?
how about i explain what am i doing?
You're trying to get the metadata from the Checkout Session, right?
im trying to get the meta data on charge.succeed webhook
that i pass during the checkout session
how about i explain the code? for you
I don't need that, thanks.
okay
This means the metadata exists on the Checkout Session object.
You need to fetch the Checkout Session object, and you will be able to see the metadata.
I suggest you to listen to checkout.session.completed Event instead, which contains the Checkout Session object.
uhm it exists on checkout session object but i dont want it from there
actually the thing is in my code, i have a event listener that listens for webhook events
if (!in_array($eventType, [
'customer.subscription.created',
'customer.subscription.updated',
'customer.subscription.deleted'
])) {
return;
}
as u already know whenever a subscription is created or updated then the checkout session is also called and when i do single product checkout then the checkout session is also recieved how i can difference between the which type of checkout session i have received, i would like to see, is it a subscription checkout session or a single product checkout session
@upbeat current @left basin uhm sorry for mentioning? but...
hi! I'm taking over this thread.
okay sorry vanya
In any case you need to fetch the Checkout Session to get the metadata. If you have a Subscription ID, you can get it by calling this endpoint: https://docs.stripe.com/api/checkout/sessions/list#list_checkout_sessions-subscription
no
What do you mean?
let me explain what this part of code is doing
im using laravel 11 with mysql database
i have a plans table that have a column named lifetime as boolean and every plan have stripe price id also with it
if that plan is supposed to be a lifetime plan that would include a price id of a one-off price/fee
and my code will generate a checkout session of a product not a subscription one
and if that plan is supposed to be a subscription typa one then my code will generate a checkout session of subscription one
so now im having a problem
i have listener fro stripe webhooks that listens for stripe events
if the incoming event is a between any of these
'customer.subscription.created',
'customer.subscription.updated',
i would assume that a user bought a subscription plan or completed a subscription checkout session
what if i receive a event named as
charge.succeeded
then i would assume that user completed product typa checkout session and i would like to take the meta data passed on that checkout session to proceed to save the purchase record in my database table
but im having a problem here that charge.succeed event doesnt have any type of meta data with it
@left basin @upbeat current
if you are using Checkout Session, then the main even you should listen to is checkout.session.completed. with this event you can know what exactly the customer bought, and check the metadata stored on the Checkout Session.
brother problem is, as u know that checkout.session.completed is always gets called with any type of checkout session doesnt matter, is it a subscription typa checkout or product typa checkout
so how would i know difference then?
the payload of the event contains a full Checkout Session object. there you can see the mode of the Session (payment or subscription), and also see the exact Product/Price sold
I don't understand your question
lol
thanks
sorry for it
thank you for helping
have a nice day
brooooooooooo im tried of finding a solution
i need help
I'm happy to help. what's your question?
i already explained man
did you try what I suggested above?
the payload of the event contains a full Checkout Session object. there you can see the mode of the Session (payment or subscription), and also see the exact Product/Price sold
okay ill try this also
oh yes
it worked
it provided a mode
which indicates
is it a payment or subscription
yep 🙂
bro
when a subscription is renewed like example
3 feb is renewel date of user subscrition and user payment method is charged then what type of webhook events are called?
would the checkout.session.completed is called then at that moment?
nope, Checkout Session in only used to create new Subscriptions, not update them. to track active subscriptions, we recommend listinign to invoice.paid as mentioned here https://docs.stripe.com/billing/subscriptions/event-destinations#active-subscriptions
what
what's your question?
then what type of event should i listen?
what type of event should i listen that would include the price details and meta data on a product checkout or subscription checkout
and also when a subscription is renewed or cancel or deleted?
it depends on what you want to do.
- to track new subscriptions:
checkout.session.completed(which contains a Checkout Session in the payload) - to track recurring payments of existing subscriptions
invoice.paid(which contains an Invoice in the payload, but you can make extra API calls to retrieve the corresponding Checkout Session if needed) - to track deleted subscriptions:
customer.subscriptions.deleted(which contains a Subscription in the payload, but you can make extra API calls to retrieve the corresponding Checkout Session if needed)
hey
'customer.subscription.created',
'customer.subscription.updated',
are these gets called when a subscription is created or renewed?
I'm not sure I understand the question.
customer.subscription.created-> when subscription is createdcustomer.subscription.updated-> when subscription is updated
but if you are using Checkout Session you should ignore customer.subscription.created
okay
@carmine pulsar hey brother can u understand my code? i have some question regarding it, its laravel/php code
What's the question?
i have a stripe webhook listener
The listener only processes three specific Stripe events:
checkout.session.completed
customer.subscription.updated
customer.subscription.deleted
How It Routes Events:
If the event type is checkout.session.completed, it calls the handleCheckoutSessionCompleted() method.
If the event is either customer.subscription.updated or customer.subscription.deleted, it routes the event to the appropriate method:
handleSubscriptionUpdated() for updates.
handleSubscriptionDeleted() for deletions.
2. Handling the Checkout Session Completed Event
Method: handleCheckoutSessionCompleted()
Purpose:
This event is triggered when a customer successfully completes a Checkout session in Stripe. It carries metadata that you set during session creation.
What It Does:
Retrieves the Stripe Customer ID:
It extracts the customer ID from the session and looks up the corresponding user in your database.
Retrieves Metadata:
It checks the session's metadata to determine:
The plan_id (to identify which plan was purchased).
Whether the purchase is a lifetime purchase (by checking if lifetime is set to 'true').
Plan Lookup:
It retrieves the plan from your local database using the provided plan_id.
Processing Based on Purchase Type:
Lifetime Purchase:
If the plan is marked as lifetime:
It deletes all previous purchase records for that user.
It creates a new purchase record with an expires_at date set to a far-future date (or null if you prefer) and marks it as a lifetime purchase.
Recurring Subscription:
If the purchase is for a subscription:
It calculates a new expiration date based on the plan's duration (using your helper method).
It then creates a new purchase record with that expiration date, marking it as a recurring subscription.
- Handling the Subscription Updated Event
Method: handleSubscriptionUpdated()
Purpose:
This event is fired when a customer’s subscription is updated—this could be due to a renewal, an upgrade/downgrade, or any other change.
What It Does:
Retrieves Customer and Plan Information:
It extracts the customer ID from the subscription payload and uses it to find the user. It then extracts the price ID (assumed to be from the first item in the subscription) and looks up the corresponding plan in your database.
Extends the Subscription:
It then finds an active purchase for the user (i.e., one that has not expired) and calculates a new expiration date by adding the plan’s duration to the current expiration date. The purchase record is then updated with the new expiration date.
- Handling the Subscription Deleted Event
Method: handleSubscriptionDeleted()
Purpose:
This event is triggered when a customer's subscription is deleted or canceled.
What It Does:
Retrieves the Customer:
It obtains the customer ID from the event payload and locates the corresponding user.
Marks Purchases as Inactive:
It then updates all active purchase records for that user, marking them as inactive to reflect that the subscription is no longer in effect.
is it enough for a subscription management renewel or creation and product payments?
Sorry, that's just a huge wall of text. What's the specific issue?
ahh
actually im working with stripe with first time
and i have implemented a stripe webhook listener
that listens for 3 events
'checkout.session.completed',
'customer.subscription.updated',
'customer.subscription.deleted'
and im using the first checkout session event for first time subscription or product checkouts
and using the subscritpion updated when a subscription is renewed as far i got to know about this event and last one for when subscription ends
are there any more do i need to listen?
You should use invoice.paid instead of customer.subscription.updated
really?
but invoice.paid is always gets called even with first time subscriptions or product checkouts
.updated will fire before the recurring invoice has actually been paid though. So if you're reliant on that to provision access for users to your app then you may be giving them free access if their payment fails, for example
https://docs.stripe.com/billing/subscriptions/event-destinations#active-subscriptions
Then you need to ignore those specific events
You can check the billing_reason field on the invoice.paid payload: https://docs.stripe.com/api/invoices/object#invoice_object-billing_reason
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
so now i should use invoice.paid that have the billing reason as subscription updated? right?
Yep
can u explain these four reasons
subscription: No longer in use. Applies to subscriptions from before May 2018 where no distinction was made between updates, cycles, and thresholds.
subscription_create: A new subscription was created.
subscription_cycle: A subscription advanced into a new period.
subscription_threshold: A subscription reached a billing threshold.
subscription_update: A subscription was updated.
I think they're explained there, no?
what does it mean by cycle?
Oh, that's what you want actually
i.e when the new billing period starts (next month or whatever)
so i should only listen for this and ignore the rest
You probably want update to in scenarios where a customer may upgrade/downgrade their sub and generates a new invoice
no when it renews like at the end of billing period?
Then it'd be subscription_cycle
Should be easy enough for you to test with a clock: https://docs.stripe.com/billing/testing/test-clocks
and update one for when is it upgrade or downgrade
Yes
hey brother how to test subscriptions using this clock i cant understand it still
Did you follow the guide?
yeah i created one
Created what?
Simply creating a clock isn't enough. The end-to-end guide here explains how to advance the time to test scenarios: https://docs.stripe.com/billing/testing/test-clocks/api-advanced-usage