#Timmmy-subscription-events

1 messages ยท Page 1 of 1 (latest)

modern void
#

It really depends on your integration/what you need, but another one that a lot of integrations listen for is invoice.paid and invoice.payment_failed to be notified of payment success/failure

shadow tulip
#

I just want to make sure users that pay 100% get access to what they paid for

#

and users that cancel should loose their access

#

CheckoutSessionCompleted != Paid right?

modern void
#

A Checkout Session completing in subscription mode typically does mean that payment has been made

shadow tulip
#

So should I give the user access in CheckoutSessionCompleted or in CustomerSubscriptionCreated

modern void
#

I would do CheckoutSessionCompleted - in general flows CustomerSubscriptionCreated does not mean that a subscription has been paid for

shadow tulip
#

CustomerSubscriptionCreated what is that used for then=

#

Sorry for all these questions

#

I just want to make sure this works haha

modern void
#

No worries at all! CustomerSubscriptionCreated tells you that a Subscription object has been created, but depending on your integration that does not necessarily mean that payment has been made since you can create a subscription with payment_behavior: default_incomplete (which won't complete payment during the creation step).

shadow tulip
#

Alright so I dont even need to have that right? (CustomerSubscriptionCreated )

#

And do I need CustomerSubscriptionUpdated if I only have one product (one package the customer can choose)

modern void
#

If you don't need it you don't have to use it - one reason why a user may choose to use CustomerSubscriptionCreated is that they want the information that is provided in that webhook event since it would be slightly different compared to what is in CheckoutSessionCompleted

#

For CustomerSubscriptionUpdated again it really is up to you and what your webhook is doing/controlling - if you need to keep track of the billing cycles as they renew then the updated event will notify you of that (and that's just one example use case) but if you don't need it at all then you don't have to use it

shadow tulip
#

Awesome thanks

#

so In theory

#

this should be enough to make sure paying customers get access

#

and not paying customers loose access

#
            switch (stripeEvent.Type)
            {
                case Events.CheckoutSessionCompleted:
                    user.StripeCustomerId = subscription.CustomerId;
                    user.SubscriptionType = "basic";
                    break;

                case Events.CustomerSubscriptionDeleted:
                    user.SubscriptionType = string.Empty;
                    break;

                default:
                    _logger.LogWarning("Unhandled event type: {0}", new { stripeEvent.Type });
                    break;
            }
modern void
#

Something you'll want to make sure you have configured is that your dashboard settings are set up so that if all payment retries fail for a subscription it automatically cancels. You can check that at https://dashboard.stripe.com/settings/billing/automatic under the "Manage failed payments for subscriptions" section for "Subscription status" you would control the behavior by selecting an option for "If all retries for a payment fail"

shadow tulip
#

like that?

modern void
#

yup! That way if all payments fail for a subscription it will automatically cancel and send the CustomerSubscriptionDeleted event

shadow tulip
#

Awesome thanks

#
 switch (stripeEvent.Type)
            {
                case Events.CheckoutSessionCompleted:
                    user.StripeCustomerId = subscription.CustomerId;
                    user.SubscriptionType = "basic";
                    break;

                case Events.CustomerSubscriptionDeleted:
                    user.SubscriptionType = string.Empty;
                    break;

                default:
                    _logger.LogWarning("Unhandled event type: {0}", new { stripeEvent.Type });
                    break;
            }`
#

this should do the trick then

#

thanks for your help

modern void
#

๐Ÿ‘ and one more thing I do want to call out - your settings are currently made to retry 4 times within 3 weeks, so a subscription won't be cancelled until 3 weeks after the failed invoice was created

shadow tulip
#

Wait what does that mean?

#

I didnt change any of these settings

modern void
#

Sorry let me clarify - if you look under "Use Smart retries for subscription" it says "Retry up to 4 times within 3 weeks". That means the last retry could happen 3 weeks after the invoice was first created. Since you subscriptions will only automatically cancel after all retries fail that means it could be three weeks until it is automatically cancelled. If you want it to happen at a faster pace then that you'd simply change the retry setting

shadow tulip
#

that makes more sense I guess

#

that way if a user doesnt pay

#

it will cancel within a week right?

modern void
#

yup! that's the idea ๐Ÿ‘

shadow tulip
#

why was 3 weeks the default lmao

#

are there any other settings I should check? ๐Ÿ˜…

modern void
#

There's so much variety in billing/subscription integrations that it's hard to pick a default that fits everyone's use case. I'd really just suggest you try the whole flow out in test mode to make sure everything behaving like you'd expect it to

shadow tulip
#

Yeah I need to figure out how to test webhooks

#

seems a bit complicated tbh

#

anyway

#

thats probably it for now

#

so thanks a lot for your help and have a good day โค๏ธ

modern void
#

๐Ÿ‘ happy to help!

shadow tulip
#

this is gonna be a bit off-topic

#

Do you just help people on this discord while working at Stripe

#

Or is there something like Discord duty ๐Ÿ˜‚

#

because you guys provide great help

modern void
#

We have a team of folks that rotate out to help here ๐Ÿ™‚

#

As an example, my shift is actually done, so @old crest is here if you happen to have any follow-ups

shadow tulip
#

Interesting, u free for the rest of the day?

#

If yes then have a nice evening ๐Ÿ˜„

modern void
#

nah, I'm at the start of my day but thank you! and i hope the rest of your integration goes well!

shadow tulip
#

Oh have a good day then, thanks ๐Ÿ‘‹

shadow tulip
#

Okay so I actually encountered a smoll problem

#
var stripeEvent = EventUtility.ParseEvent(json);
            stripeEvent = EventUtility.ConstructEvent(json,
                Request.Headers["Stripe-Signature"], endpointSecret);

            Subscription subscription;
            ApplicationUser user;

            switch (stripeEvent.Type)
            {
                case Events.CheckoutSessionCompleted:
                    subscription = stripeEvent.Data.Object as Subscription;
                    user = await _userManager.FindByIdAsync(subscription.Metadata["UserId"]);
#

subscription == null for some reason

#

stripeEvent.Data.Object is not empty btw

old crest
#

Interesting, what is it then?

shadow tulip
#

what do you man? ^^

old crest
#

What is stripeEvent.Data.Object?

#

And thank you for the assist in the main channel by the way!

shadow tulip
# old crest What is stripeEvent.Data.Object?
{<Stripe.Checkout.Session@35686241 id=cs_test_a1ZaIjXOb5M1FnXmYWn2igL22hSSHks7eQQxamyOQG1aHFbmXGSGScXM3b> JSON: {
  "id": "cs_test_a1ZaIjXOb5M1FnXmYWn2igL22hSSHks7eQQxamyOQG1aHFbmXGSGScXM3b",
  "object": "checkout.session",
  "after_expiration": null,
  "allow_promotion_codes": null,
  "amount_subtotal": 3500,
  "amount_total": 3500,
  "automatic_tax": {
    "enabled": false,
    "status": null
  },
  "billing_address_collection": null,
  "cancel_url": "https://localhost:7191/Payment/CancelProcess",
  "client_reference_id": null,
  "consent": null,
  "consent_collection": null,
  "currency": "eur",
  "customer": "cus_KwNZxk9y5bf1If",
  "customer_details": {
    "email": "my.email@protonmail.com",
    "phone": null,
    "tax_exempt": "none",
    "tax_ids": []
  },
  "customer_email": null,
  "expires_at": 1641934122,
  "line_items": null,
  "livemode": false,
  "locale": null,
  "metadata": {
    "UserId": "4ce6d793-8c43-42b9-9b3a-10d49efe97fa"
  },
  "mode": "subscription",
  "payment_intent": null,
  "payment_method_options": {
    "acss_debit": null,
    "boleto": null,
    "oxxo": null
  },
  "payment_method_types": [
    "card"
  ],
  "payment_status": "paid",
  "phone_number_collection": {
    "enabled": false
  },
  "recovered_from": null,
  "setup_intent": null,
  "shipping": null,
  "shipping_address_collection": null,
  "shipping_options": [],
  "shipping_rate": null,
  "status": "complete",
  "submit_type": null,
  "subscription": "sub_1KGUnuIqNhXOt8bgVYANh5XN",
  "success_url": "https://localhost:7191/Payment/Success?sessionId={CHECKOUT_SESSION_ID}",
  "tax_id_collection": null,
  "total_details": {
    "amount_discount": 0,
    "amount_shipping": 0,
    "amount_tax": 0,
    "breakdown": null
  },
  "url": null
}}
#

I hope that doesnt contain any secrets ๐Ÿ˜…

shadow tulip
#

Also the first part of that json looks a bit weird tbh (maybe that causes the trouble?)

old crest
#

Don't worry, that object is safe to share here.

#

And ah that makes sense. Try casting it to a Stripe.Checkout.Session

#

That object is not a subscription so it won't be able to cast to one

shadow tulip
#

Eyy it works

old crest
#

Great to hear!

shadow tulip
#

btw what object does CustomerSubscriptionDeleted return?

#

and is the object that is returned by the event always the same?

old crest
#

The type of object? Yes

shadow tulip
#

Interesting is the documentation just not up to date or does the type somehow change?

old crest
#

Do you know what doc said it should be a subscription?

#

I will put in feedback to correct it

shadow tulip
#

wait let me double check the events first

#

nvm I confused CheckoutSessionCompleted with CustomerSubscriptionCreated sorry my bad

old crest
#

Ah, glad we could clear that up

#

Depending on your needs you can definitely just listen to that event as well

shadow tulip
#

Really? I have been told that CustomerSubscriptionCreated does not always mean that the user paid

#

No worries at all! CustomerSubscriptionCreated tells you that a Subscription object has been created, but depending on your integration that does not necessarily mean that payment has been made since you can create a subscription with payment_behavior: default_incomplete (which won't complete payment during the creation step).

old crest
#

Apologies, missed that context. They were correct, the checkout session completed event makes much more sense for your scenario.

shadow tulip
#

Alright ๐Ÿ™‚

#

Well thanks a lot for your help

#

Have a good day and see you around

old crest
#

Of course, have a good day yourself

shadow tulip
#

thanks ๐Ÿ‘