#gracine
1 messages ยท Page 1 of 1 (latest)
It is because I receive both event when a user upgrade to a new subscription and that causes my code to try to call Stripe::Subscription.cancel on the same sub id twice
and from my test the update is always called and I have a sync subscription function that is called for both event, so its a create or update function
So I wonder if I could just drop the customer.subscription.created from my webhook listener
Hi ๐
How are you creating subscriptions
?
And why would you cancel if the user updated?
I create the subscription by the Stripe Checkout portal
I have a Premium subscription & Pro Subscription
When a Premium user change plan to Pro, I cancel the premium subscription
At first I tried to simply update the existing subscription with the new Pro price but I ended up with too much corner cases to handle. Ex: user is on a free coupon so the API call fails due to no payment method. I found its way easier and robust to simply let the user go to the stripe checkout page and on the webhook simply cancel any remaining subscription
Why don't' you just update the Price associated with the Subscription object instead of canceling?
So if your integration creates a new subscription rather than changes the old one, why would you cancel an existing subscription on the .updated event?
only be cause I have a generic sync function
does not care if created,updated or delete
it sync my db, create or update
that is how it has been implemented, works quite well so far
I just have this specific case
but again, it not because I have a .created event that the subscription is necessary valid
the status a mean
my question was only to understand if a .created is always followed by a .updated
or if I will miss some edge case
if I do not listen to .created
this is how it looks
ok ! Hi
this is how it looks at the webhook handler side
def handle_event(event)
logger.info("On stripe webhooks - : #{event.type}")
case event.type
when 'invoice.paid', 'invoice.payment_failed'
invoice = event.data.object
::Billing::StripeEntitiesSynchronizer.new.update_billing_subscription_from_invoice(stripe_invoice: invoice)
when 'customer.subscription.created', 'customer.subscription.updated', 'customer.subscription.deleted'
stripe_subscription_id = event.data.object.id
# Refetch the subscription simply because the events can come out of order so we do not want to overwrite subscription with out of sync data
subscription = Stripe::Subscription.retrieve(stripe_subscription_id)
::Billing::StripeEntitiesSynchronizer.new.update_billing_subscription(subscription: subscription)
When you receive the updated event after the created event what is in the previous_attributes of the updated event?
I have to test I don't know, want me to find it ?
Yes that would be helpful
ok hold on
"previous_attributes"=>{"default_payment_method"=>nil, "status"=>"incomplete"}
Yep so that's the reason.
After you create the Subscription you are immediately charging that first invoice
When that is successful that changes the status and sets the default_payment_method
So that fires the customer.subscription.updated
The issue is that if that initial payment fails, neither of these things will change
I can't remember if you will see something else with the Sub change. I'd recommend testing if you fail that initial payment due to a decline
So, going back to my original question, can I safely drop the customer.subscription.created event ?
is it safe to only listen to the .updated
to have a robusting synching mechanism between Stripe & my database
Right
So you want to test what happens on a declined payment with how your integration is set up
in other words, is there a case where I will not have the .updated event fired
given all possible scenarios
I think you won't see a .updated event if the initial payment is declined, until either a retry succeeds or the Subscription moves to incomplete_expired
But if you are only ingesting data on a successful Subscription start (when the initial payment is successful) then yes you can just use the .updated event
ok, I do have this explicit listner though :
when 'invoice.paid', 'invoice.payment_failed'
I do call the same sync fonction
Ah okay then yeah that should work fine