#gagan-subscription-cancel

1 messages · Page 1 of 1 (latest)

pliant moatBOT
ruby copper
#

Hi 👋

What is your specific question about the Subscription webhooks?

meager slate
#

i have a few usecases. and im having trouble trying to figure out which event types to use.

#

theyre both revolving around canceling a subscription.
`//if manually canceled, dont update plan to free or set planTier to 0, until next invoice

//if canceled due to failed payment, set planTier to 0`

ruby copper
#

Okay those are just comment strings. Why do they need to be code formatted?

meager slate
#

`case 'customer.subscription.updated':
const paymentIntent = event.data.object
clientReferenceId = paymentIntent.client_reference_id
const subscriptionId = paymentIntent.subscription

            //if manually canceled, dont update plan to free and set planTier to 0, until next invoice
            const subscription = await stripe.subscriptions.update(subscriptionId, {
                cancel_at_period_end: true
            })

            //if canceled due to failed payment, set planTier to 0
            if (!paymentIntent.paid) await createPlanHelper(request, db, clientReferenceId, 0)
            break`
#

this is the code

ruby copper
#

Please descibe in words what you are trying to do

meager slate
#

if the subscription is terminated due to failed payment, set planTier to 0.

if the user manually canceled, we want to cancel subscription but provide it for the remainder of the billing month/year.

im assuming the second scenario ties into the first one. because itll automatically cancel it when its end of billing month.

#

is the
case 'customer.subscription.updated':

the correct event to use?

ruby copper
#

That event will capture both scenarios yes

#

And the updated event will include a previous_attributes hash that will show you what changed

#

You can use this to determine which scenario applies

meager slate
#

so for this code:

` //if manually canceled, dont update plan to free and set planTier to 0, until next invoice
const subscription = await stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true
})

            //if canceled due to failed payment, set planTier to 0
            if (!paymentIntent.paid && ) await createPlanHelper(request, db, clientReferenceId, 0)`

the subscription will let me know if its end of billing cycle and it wasn't paid? or will the updated.previous_attributes be of better use?

#

im trying to understand the flow. and remove any unnecessary code

ruby copper
#

This should be pretty simple to test

meager slate
#

is invoice.payment_failed called at end of billing period?

ruby copper
#

invoice.payment_failed will fire when ever an Invoice payment attempt fails

meager slate
#

so i dont want to update our internal DB until end of billing period.

ruby copper
#

That's up to you

meager slate
#

right but if i put the code in invoice.payment_failed, it will do it immediately.

#

so invoice.payment_failed is not the right event type then.

#

in a preivous chat, they told me to use stripe.subscriptions.update with cancel_at_period_end

ruby copper
#

Okay sure, that'll work. Have you tested it?

meager slate
#

no because i need to know what to use the subscription for. what variable can i use to determine if its ok to call the internal DB subscription update:

`const subscription = await stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true
})

            if (!paymentIntent.paid && ) await createPlanHelper(request, db, clientReferenceId, 0)

`

!paymentIntent.paid && <what goes here>

ruby copper
#

That is up to you. You need to test your code and determine what makes sense for you

meager slate
#

you're not understanding, im asking what the variable is that i can use from subscription update call that will tell me that its end of billing period and subscription is canceled?

ruby copper
#

You said it yourself. cancel_at_period_end == true

#

Have you looked at the cancellation_details hash?

meager slate
#

thats the a parameter im using

meager slate
ruby copper
meager slate
#

this should handle all cases then:

if (!paymentIntent.paid && subscription.cancellation_details.payment_failed) { await createPlanHelper(request, db, clientReferenceId, 0) }

#

subscription.cancellation_details.payment_failed

#

sorry:

subscription.cancellation_details.reason

ruby copper
#

Yes

meager slate
#

how do i get the enum?

#

is that a string?

ruby copper
#

I would still recommend writing tests using the Test Clocks to simulate the behavior

meager slate
#

i underrstand but testing without fully understanding what the events will do is innefficient.

#

so this may causes issues here:

        case 'customer.subscription.updated':

is called for all change cases.

we want to handle just the cancellation (user cancels, payment fails due to end of billing cycle, and switch to free plan cases).

in this code, it will call the update subscriptions function every time to cancel at period end.

ruby copper
#

Then you should inspect the Subscription object and only trigger that code if it's appropriate

meager slate
#

const subscription = await stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true
})

is inside the customer.subscription.update event.

#

so it will trigger cancellation every time.

#

what variable is in the custom.subscription.updated event that i can use to check if a switch of plan or cancellation is triggered?

pliant moatBOT
silent wind
#

gagan-subscription-cancel

#

@meager slate I'd recommend pausing the theory and just trying the API in Test mode yourself. It will be a lot easier for you to make sense of what happens exactly, look at the raw JSON in each Event and connect the dots.

#

It's important as I've seen you ask about this for a few days on multiple threads already and it would be a lot easier to just try and check how cancel_at_period_end, cancel_at, canceled_at and other properties are being set

meager slate
#

ok

#

ill give it a shot

#

but i can already see an issue and dont know how to solve it

silent wind
meager slate
#

customer.subscription.updated event is called on change (subscribed or unsubscribed).

await stripe.subscriptions.update is called with cancel_at_period_end in both cases.

silent wind
#

So what's the problem exactly? Sorry you're not really explaining what's blocking you. Really if you test this carefully in Test mode you'll see exactly what you need

meager slate
#

const subscription = await stripe.subscriptions.update(subscriptionId, { cancel_at_period_end: true })

this code needs to be wrapped in an if statement to check if status is past_due, canceled, or unpaid.

#

where do i get the status from inside event customer.subscription.updated

silent wind
#

Can you give me a concrete example of an Event you're looking at with the exact evt_123?

meager slate
#

what is evt_123?

silent wind
#

evt_123 is an example id of an Event object. I'm asking what example you're looking at so that I can show you where to look

#

@meager slate do you have that example Event id so that I can help you?

meager slate
#

i dont because im still writing the code. once i start testing it, i will send it

silent wind
#

Okay so my advice is the same I gave earlier. For now pause writing the code for a bit and focus on testing those flows end to end and looking at what happened.