#Ludvig-Bartholdsson-subscriptions

1 messages · Page 1 of 1 (latest)

vague pebble
spiral creek
#

đź‘‹

vague pebble
#

Hello! That's a great question... let me think about this for a minute

spiral creek
#

Thanks

vague pebble
#

So I believe the only way to do this would be to have a check BEFORE the checkout session and ask the customer to provide an email address they want to checkout out with. If it's one that already has a customer object for your Stripe Account, you would take that existing customer ID and use it to create the Checkout session. Otherwise, you can pass in the email address they've entered in when you create the checkout session.

spiral creek
#

Hmm. Or maybe actually multiple people can have the same email.

How does subscriptions work in practic?

  1. Does it send like an invoice via email every month or does it just take the money of their card?

  2. What if the card has become invalid? How does the customer know when they have to update their card-details? Where does the customer do that?

vague pebble
#

Does it send like an invoice via email every month or does it just take the money of their card?

You can have either, controlled by the collection_method parameter (https://stripe.com/docs/api/subscriptions/create?lang=cli#create_subscription-collection_method). When collection_method: send_invoice we'll email the invoice to the customer which can be paid through our hosted invoice page, and when collection_method: charge_automatically we attempt to charge the customer's saved payment information

#

What if the card has become invalid? How does the customer know when they have to update their card-details? Where does the customer do that?

There are a number of settings you can enable through the dashboard (https://dashboard.stripe.com/settings/billing/automatic) that can handle things like this. For example, we have a setting that you can enable to email your customer if the recurring payment for a subscription has failed with a link to update their paymetn info

spiral creek
# vague pebble *Does it send like an invoice via email every month or does it just take the mon...

Thank you. I'm using this code snippet to create my checkout sessions.
How can I implement a collection_method in this?
Just adding it like in the link you sent me doesn't work.

$session = \Stripe\Checkout\Session::create([
  'success_url' => 'https://'. $domain .'success.html?session_id={CHECKOUT_SESSION_ID}',
  'cancel_url' => 'https://'. $domain .'canceled.html',
  'payment_method_types' => ['card'],
  'mode' => 'subscription',
  //'collection_method' => 'charge_automatically',
  'line_items' => [[
    'price' => $priceId,
    'quantity' => 1,
  ]],
]);
vague pebble
#

Ah, I forgot you were using Checkout... for Checkout the only option you have is charge_automatically, so if that's what you want then you should be all set 👍

spiral creek
vague pebble
#

under "Manage failed payments for subscriptions"

#

You should see a setting called "Send emails when card payments fail", and if you click the eye icon you can see a preview of what those emails will look like

spiral creek
#

Perfect, enabled that too.

#

What about the button on that form, does it work automatically?

#

Or do I need to code something?

vague pebble
#

When you click the "eye" button you'll see that you can specify a link - that should be your own page where users can update their payment info from

spiral creek
#

Gotcha, and is there like a template or something I can use?

#

Which apis should I use ... etc?

vague pebble
#

There are a number of different ways you could do this - you could generate a link back to the customer portal to have you customers update their payment methods from there, you could have your UI w/ elements that sets up a new payment method and sets it as the customer's new default (at invoice_settings.default_payment_method)

spiral creek
#

Is this a customer portal that will work in this case?

vague pebble
#

Yup! That's what I was referring to 🙂

spiral creek
#

I thought one way was to link directly to the .php file from the email, so you skip the client side part. Would that work or do you have a better idea?

balmy ice
#

Yes you can link directly to the customer portal or redirect to it

#

When you create the Session object it will have a url property that you can use

spiral creek
#

To create this session object I need the id of the customer and first after that it'll create the url property.

How do I even get the customer_id of the customer?

balmy ice
#

Is that helpful or are you talking about figuring out which subscription/customer this is even for?

spiral creek
balmy ice
#

Unfortunately it does not look like there is a way to customize that URL to go directly to the customer portal

#

If you listen to webhooks it may be possible to send them this email form your server with the webhook info

#

I am looking in to what we have suggested in the past for this

spiral creek
#

Thank you. I'll be back tomorrow morning (gmt+2), please keep this ticket open

balmy ice
#

Okay. I will respond here in the meantime. This thread will likely be archived by then but if you ask in #dev-help we can un-archive it again.

spiral creek
#

awesome

balmy ice
#

Hey, so unfortunately that failed payment email cannot be customized to include a link directly to your customer portal. If the goal is to have the customer to get an email about this and be linked directly from the email to your customer portal, the best way to currently do that would be to listen to the invoice.payment_failed webhook which will include the Customer id which you can then use to generate the portal link and send your own email about the failed payment.

spiral creek
#

Hello

wispy walrus
#

hello

spiral creek
#

Thank you!
So I should do like this?

checkout.session.completed = subscription started

invoice.paid = Subscription renewed

invoice.payment_failed = Subcription renewal failed (update card details)

wispy walrus
#

It looks right to me

spiral creek
#

Sweet. After the invoice payment fails, how many days does the customer have before the next try?

#

Or before the invoice gets deleted

wispy walrus
#

The invoice will be in uncollectible status but it could be paid again.

spiral creek
#

Ok good thanks.

#

Is there any webhook triggered a few days prior the due date of the invoice?

wispy walrus
spiral creek
#

Awesome!

  1. Is there any webhook event available that triggers when a card has expired?

Like this setting in the dashboard - ”Send emails about expiring cards”

  1. Which event triggers when a subscription is canceled?
spiral creek
#

Amazing

wispy walrus
spiral creek
#

Hello again!

#

New day, new problem >:)

#

This is my setup

#

Issue is that when a customer starts a subscription both checkout.session.completed AND invoice.paid gets triggered

balmy ice
#

That should be the proper behavior. What issue does that cause for you?

#

Ah, wondering how to tell these webhooks are the same event so you don't double up on the Discord message?

spiral creek
#

Yup

#

And e.g the unsuspend user part.

#

Because I noticed that with checkout.session.completed there comes alot of other webhook events aswell.
e.g
invoice.paid
payment_method.suceeded

etc

balmy ice
#

Understood, looking in to the best way to tell they are the same here.

#

Can you clarify a bit more on what is going wrong with unsuspending the user?

spiral creek
#

Nevermind regarding that. The issue is that invoice.paid triggers when checkout.session.completed trigger.

balmy ice
#

So for the session.completed event with a subscription of sub_123 will be about the same payment that as invoice.paid with sub_123 and a reason of subscription_create

spiral creek
#

Uhm wdym. Sorry

balmy ice
#

I thought the question was how to tell that session.completed and invoice.paid were about the same thing so you wouldn't double up on things when reacting to it

#

Did I misunderstand you a bit?

spiral creek
#

I think we're misunderstanding eachother.
When a new subscription is received I just want the session.completed event to trigger, not invoice.paid

#

So not both of them trigger

spiral creek
balmy ice
#

I see, looking in to that. Do you have an example id of a subscription this happened for?

spiral creek
#

e.g "sub_1JdFE5CZAbM0xWOwE3CsqbWn"

balmy ice
#

Perfect thank you

balmy ice
spiral creek
balmy ice
spiral creek
#

I know there was a tls error there, because I use stripe listen --forward-to

#

thats prob why

#

I ended up with just skipping the suspend part and I will go directly to termination.

#

with customer.subscription.deleted.

#

Btw, when is that triggered? 1 week after end-date? 1 month? 2 weeks?

nimble flint
#

hey, catching up

customer.subscription.deleted.
should be triggered when the sub is canceled , not sure I have full context though

spiral creek
#

Ok thanks

#

and regarding event invoice.payment_failed, can I see in the object what went wrong?

#

Or is the only failure expired/invalid card-details?

nimble flint
#

could be numerous things that failed the charge. Bank declining it and deciding not to honor it, bank not accepting authentication, many things

I don't recall off hand if an invoice.payment_failed event has all the things you need on it around the Charge failing, if you have an example ID I can quickly check

spiral creek
#

2 sec

#

evt_1JdGxLCZAbM0xWOw8b3EgfQs

#

Event ID

#

Made the event thru cli.

nimble flint
#

gotcha, so that Invoice has a payment_intent: pi_123 field on it, you fetch that PaymentIntent from the API and it will have a last_payment_error field on it
That will give you details on what the decline was, including a customer facing error message too

spiral creek
#

Awesome ty

#

What should I do in that case?

#

Link to the customer portal?

nimble flint
#

there's a few things you can, I would personally email the customer and bring them on to my payment page and have them pay that Invoice's PaymentIntent with a different card

I think you can also send the hosted Invoice page to the user via the hosted_invoice_url and that (iirc) has a payment page on it

and yep you can send the customer to Customer Portal to update their credit card, then you get a webhook event payment_method.attached event and then update that PaymentMethod on the Subscription default_payment_method so on the next retry, the Subscription uses that new PaymentMethod

spiral creek
#

But instead of doing this,

$session = \Stripe\Checkout\Session::create([
  'payment_method_types' => ['card'],
  'line_items' => [[
    'name' => 'Kavholm rental',
    'amount' => 1000,
    'currency' => 'sek',
    'quantity' => 1,
  ]],
  'payment_intent_data' => [
    'application_fee_amount' => 123,
    'transfer_data' => [
      'destination' => '{{CONNECTED_ACCOUNT_ID}}',
    ],
  ],
  'mode' => 'payment',
  'success_url' => 'https://example.com/success',
  'cancel_url' => 'https://example.com/failure',
]);

Can I specify just a paymentIntent id?

nimble flint
#

just to check, this is in context for paying an already created Invoice right?

spiral creek
#

Yup so the flow for my customers is like this:

subscription.session.completed = subscription started
invoice.payment_failed = renewal invoice failed

on invoice.payment_failed I will send a email/sms to them

#

And I want them to be able to pay and update their payment details on a link click

nimble flint
#

yeah so you don't want to present them Checkout in that case, you cannot link Checkout to an existing PaymentIntent

#

you can try Checkout in mode: setup that just collects card from Customer with no payment

Then you can take that new card and attach it to the Subscription and also pay the previously failing Invoice with that new PaymentMethod

spiral creek
#

Sounds good

#

So like this

#
$stripe = new \Stripe\StripeClient('');
$stripe->checkout->sessions->create([
  'success_url' => 'https://example.com/success',
  'cancel_url' => 'https://example.com/cancel',
  'mode' => 'setup',
]);
nimble flint
#

yep

spiral creek
#

Awesome

#

After that, will the paymentIntent automatically get paid?

#

(if the new card details are valid)

nimble flint
#

After that, will the paymentIntent automatically get paid?
no, you need to do 2 things after

#

with the above setup Checkout, you just collect a new card

1/ pay the customer's latest failing Invoice's payment_intent: with that PaymentMethod

2/ if 1/ succeeds, attach the PaymentMethod as the default_payment_method: on the Subscription

and done

1/ pays the current open Invoice
2/ attaches that good new card to the Subscription for new recurring charges

if 1/ fails, then you repeat the setup Checkout step and collect a new card from the Customer

spiral creek
nimble flint
#

step 1 is one additional API call, like calling
https://stripe.com/docs/api/payment_intents/confirm

what you linked for step 2 is attaching the PaymentMethod to the Customer (which you don't need to, just pass the customer: cus_123 Customer ID in your setup Checkout and that will auto-attach the PaymentMethod to the Customer)

so you do not need to do https://stripe.com/docs/api/payment_methods/attach
if you create Checkout with a Customer (one param to add in your Checkout snippet earlier)

step 2/ would actually be https://stripe.com/docs/api/subscriptions/update#update_subscription-default_payment_method

spiral creek
#

Update card-details

    $stripe = new \Stripe\StripeClient($stripe_client_key);
    $stripe->checkout->sessions->create([
      'cancel_url' => 'https://swingtrejdarna.se',
      'mode' => 'setup',
      'customer' => $object['customer']
    ]);

Step 2:
Do I need to do this if I specify customer as above?

Step 3:

$stripe = new \Stripe\StripeClient('');
$stripe->subscriptions->update(
  'subscription id',
  'default_payment_method' => 'what'
);
nimble flint
#

so renumbering as our numbers are out of sync now haha

1/ create mode: setup Checkout with a Customer
this will collect a PaymentMethod and attach it to said Customer

2/ pay the latest Invoice's PaymentIntent with new PaymentMethod

3/ after 2/, update the Subscription to make new PaymentMethod the default on that Sub going forward

spiral creek
#

haha yeah

1/

    $stripe = new \Stripe\StripeClient($stripe_client_key);
    $stripe->checkout->sessions->create([
      'cancel_url' => 'https://swingtrejdarna.se',
      'mode' => 'setup',
      'customer' => $object['customer']
    ]);

2/

$stripe->invoices->pay('in_123', ["payment_method" => "pm_123"]);

3/

$stripe->subscriptions->update(
  'sub id',
  'default_payment_method' => '????'
);

Will the first (1) step give me a pm_123 object that I can use in this step? (replacement of ????)

silver laurel
#

You listen to the checkout.session.completed event (or the redirect) so that you find the PaymentMethod on that Session and then you can call the https://stripe.com/docs/api/invoices/pay with payment_method: 'pm_123' to see if that works

Note that the SetupIntent is just an id on the Session by default, you have to use the Expand feature (https://stripe.com/docs/expand) to explicitly get the SetupIntent object and the underlying PaymentMethod id.

spiral creek
#

Like that?

silver laurel
#

yep

#

But go step by step as there are multiple sequential step: get the session, understand how to get the PM id, pay the invoice, then make it the default

spiral creek
#

How do I get the pm_123 from the first step afterwards?

silver laurel
#

what did you try?

#

Sorry I'm a bit nitpicky with this, if I give you code you won't really understand/internalize this

spiral creek
#

Yup I understand.
Give me 2sec.

silver laurel
#

take a completion Session already, and try retrieving it and expanding the setup_intent like I said. It's fine if it doesn't work, just try and then share the code and I can help tweak it

spiral creek
#

So checkout.session.completed triggers after the user is done with first step?

#

Because that will cause an issue for me

silver laurel
#

what issue will it cause exactly?

spiral creek
#

I'm using the checkout.session.completed webhook for another thing

silver laurel
#

that's only a small bit of the info. What's the issue with that? You can know in the event what it's for, look at the mode for example and if mode: 'setup' do something. You could also store the Session id in your database so that in the event you know what operation it was for

#

there's a lot you can specialize there, event adding metadata to that Session to track its "reason"

spiral creek
#

look at the mode for example and if mode: 'setup' do something
Good idea thank you.

silver laurel
#

@spiral creek are you unblocked?

spiral creek
#

Unblocked?

balmy ice
#

Did that give you the info you need to move forward?

spiral creek
#

I haven’t tried everything yet. Please wait

silver laurel
#

@spiral creek just wanted to check in before I archive this thread, are you all set?

spiral creek
#

Haven't had time to try everything yet..

#

But I think you can archive it because I'll still see everything you've mentioned