#erikvm-subscription-events
1 messages ยท Page 1 of 1 (latest)
Hi there ๐ this is expected. When using checkout the subscription is created towards the end of the flow, and incorporates all information provided rather than doing a create followed by an update. If you were to modify the subscription later, then you'd see the customer.subscription.updated event.
The thing is, I need to use either one of them
The customer.subscription.updated provides the right status: "active" , whereas with customer.subscription.created sometimes have status: "incomplete"
I can't use both of the hooks because I'd be updating from active to incomplete sometimes..
Currently, my python code simply does this:
if event.type == "customer.subscription.updated":
upsert_subscription(event.data.object, event.type)
I used to have if event.type == customer.subscription.updated or event.type = customer.subscription.created
But that got messy because of the different status values
What do you propose I do?
It's a little tricky since I'm not exactly sure what you're trying to accomplish. What actions are you trying to trigger from these events?
The more general advice is to use the events as triggers, but then explicitly retrieve the subscription to ensure you have the most up-to-date information.
Well, in the checkout, I'm listening for the events so I can create the customer in my database so they can perform the necessary actions on my website
Ah okay - so I'll listen for, for instance
customer.subscription.created and then retrieve that with stripe.retrieve or something?
Yup:
https://stripe.com/docs/api/subscriptions/retrieve
This is usually a good idea since we can't guarantee the order that webhook events will be delivered to you.
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, when I do a retrieve - how can I guarantee that I have the updated info?
I mean, if I have an event trigger like:
if event.type == "customer.subscription.updated" or event.type == "customer.subscription.created":
# retrieve subscription status here
How can I make sure that I get the "correct" status and not just the same "incomplete"?
The retrieve function will always return the current information, if it returns a status of incomplete then that is the current status of the subscription.
Yeah so I'm stuck in the same boat then
An incomplete status means that the first payment attempt failed and additional actions are necessary.
Hmm, but to circle back a bit: help me understand, when I cancel and "re-subscribe" again in the checkout portal, a customer.subscription.updated fires
However, when I cancel and then re-subscribe WITH a promotional code, only customer.subscription.created fires
Is that by design?
Do you have example subscriptions that we could take a look at?
Do you have a sample of one with a promo code that I can compare this to? I'm trying to figure out what could be different between the flows.
Sample of what?
I can create a promo code if that's what youre asking
Or if you want I can quickly cancel the subscription, re-subscribe, and then cancel and re-subscribe with the promo code?
A sample ID of the situation you just described: a subscription you cancelled and then reactivated with a promo code and only got customer.subscription.updated
Let me run the flow real quick
Currently:
sub_1K9amWLPcnawOk5tgPAs5hku and customer cus_KpFFmFwvS1GV52
Cancelled it and the following event ran:
2021-12-22 21:22:35 <-- [200] POST http://localhost:8000/account/stripe_webhook/ [evt_1K9bKaLPcnawOk5tGemxxYWq]
I re-ran the checkout, and when re-subscribing, I added an existing promo code. These events ran:
(see attached)
However, if I were to run it WITHOUT filling in a promo code. I would see that customer.subscription.updated ran
Do you have an example event ID from that (evt_123)?
Ah, that coupon is 100% off, resulting in a $0 invoice which kind of skips some of the payment process.
These are the events running when I'm not applying any promo code (re-subbing after a cancel):
I tried with a 99% discount code as well
Still no updated trigger
Right, like toby said, the 100% off coupon skips some of the process. With the promo code, the subscription is created as active, without it the subscription is created as incomplete and is updated to active when the payment succeeds.
That is surprising about the 99% one, that should still require a payment. Do you have a subscription ID for the sub that did that or can you run this process one more time with it?
sub_1K9bWkLPcnawOk5tNEwXDV2q
Can't run it again because I don't receive an update trigger, so my sub id is different from sub_1K9bWkLPcnawOk5tNEwXDV2q
Perfect thank you.
So it looks like the coupon brought the amount owed under to $0.06 which is under our minimum chargeable amount ($0.50) so the 6 cents will just be added to the next invoice on that subscription
So hmm
Or, because this is a forever coupon, in 9 months when the amount owed is above $0.50.
Will test this to double check
Okay thanks. How can I update the subscription accordingly then, for a customer that previously cancelled?
Just making sure I understand what you are asking: you want to know when to create the customer in your database?
Well. I rely on customer.subscription.updated to create users in my DB
And when they cancel their subscriptions, I listen to customer.subscription.deleted
All fine
However, if a customer cancels their subscription and then wish to re-subscribe I want to offer them a promotional code as an incentive to come back
If they re-sub with this promo code - my DB doesn't update to the correct status, since customer.subscription.update never fires
So from my DB's point of view, their status is "canceled"
Does this make sense?
Yes, so it sounds like you will want to listen to both created and updated and need to check if the status is "active" in both.
Yeah but here's the thing: Since I cant control the order of the events. customer.subscription.create sometimes sends status "incomplete"
So how would I structure the hooks correctly?
I thought I could get away with
if event.type == 'updated' or 'event.type = 'created' # shorten here
But what happens if updated fires first, then created. Then my status goes from active -> incomplete sometimes
Couple options. You can retrieve the subscription as toby suggested earlier. If you retrieve it and the status is incomplete, then you got it first. If you get updated first and then created, retrieving the subscription in the created event will show an active status
Can you show me some pseudo code on how that works? I'm trying to understand how its different
You may not need to actually react to the incomplete status. It sounds like your DB will know that the sub was cancelled so you can just wait for a new sub to be active
Sure, please send it
So, I used to have
But that messed up the statuses
Hopefully it's quite clear, but let me know if it's not
So actually, I think the simplest way to do this would be to check the created timestamp on the webhook event and see if that is later than the latest previous update that you saw. Even if it is possible to receive updated before created. So it might be good to store that timestamp last_updated instead of timezone.now()
I think that is the most direct way to do this logic. Otherwise, it would be adding something like
if event.data.object["status"] == "incomplete":
subscription = stripe.Subscriptions.retrieve(event.data.object["id"])
if subscription.status == "completed":
return
upsert_subscription(event.data.object)```
Hmm okay thanks for the suggestion
Let me play around with it a bit and see
Is this thread reply-able in an hour or so?
Sure, we can leave it open for that long if you would like.