1

I have one product and 8 prices (4 monthly and 4 annual) When a user updates a subscription from one number to two, stripe creates an invoice and waits for the user to pay for it

And here are my two situations when I do not understand what to do

  1. The user bought a subscription to one number - the user subscribes to the second number, but leaves at the time of payment - the subscription has been updated and switched to the past_due status and is waiting for payment (the invoice has been created) Now there are two options - the user again goes to the subscription update and wants to add another number -> adds a number -> an invoice is being created -> waiting for payment -> the user pays only for the third number and his subscription becomes active for 3 numbers, but there is an unpaid invoice for the second number (this is the second screen)

  2. The user did everything the same, but after he left the payment in the second step, he still had an open invoice, when the user removes the number from the subscription (lowers the price back) - the stripe puts money on the balance for this number (which he did not pay ) - but at the same time he has an open invoice for the added number (second)

https://ibb.co/vkMZ1JX

https://ibb.co/zh7KVtq

This is how I create/update a subscription - https://gist.github.com/0ceb4ec03f9e7818a140b6a60e20b238

async createSubscription(stripeCustomerId: string, subscriptionInfo: SubscriptionInfoT) {
    return this.stripe.subscriptions.create({
      customer: stripeCustomerId,
      items: [
        {
          price: subscriptionInfo.priceId,
          quantity: subscriptionInfo.quantity,
        },
      ],
      description: Object.values(subscriptionInfo.numbers)
        .filter(n => n)
        .join(', '),
      metadata: subscriptionInfo.numbers,
      payment_behavior: 'default_incomplete',
      payment_settings: { save_default_payment_method: 'on_subscription' },
      expand: ['latest_invoice.payment_intent'],
    });
  }

async updateCustomerSubscription(subscriptionId: string, subscriptionInfo: SubscriptionInfoT) {
    const subscription = await this.stripe.subscriptions.retrieve(subscriptionId);
    return this.stripe.subscriptions.update(subscriptionId, {
      payment_behavior: 'default_incomplete',
      proration_behavior: 'always_invoice',
      description: Object.values(subscriptionInfo.numbers)
        .filter(n => n)
        .join(', '),
      items: [
        {
          id: subscription.items.data[0].id,
          price: subscriptionInfo.priceId,
          quantity: subscriptionInfo.quantity,
        },
      ],
      metadata: subscriptionInfo.numbers,
      expand: ['latest_invoice.payment_intent'],
    });
  }
  • From what you describe, a subscriptions seems to have many items (corresponding to numbers?), but in your `updateCustomerSubscription` function you always refer to the first item only (`subscription.items.data[0].id`). What if the customer changes (or removes) the second item? – Heiko Theißen Nov 05 '22 at 11:34
  • It cannot have multiple items (when a user adds or removes a number, I do an updateSubscription and change the price) - I'm not sure if this is correct, maybe I'm doing something wrong My example https://ibb.co/SdLqKWH – Alexander Dimov Nov 05 '22 at 11:46
  • @heiko-theißen I checked and realized that I am renewing the subscription exactly as shown in the documentation [subscriptions/upgrade-downgrade](https://stripe.com/docs/billing/subscriptions/upgrade-downgrade) – Alexander Dimov Nov 05 '22 at 20:54

1 Answers1

1

To fully understand what happened, you need to keep in mind that proration_behavior: 'always_invoice' will create a Proration.

For example, if a customer upgrades from a 10 USD per month subscription to a 20 USD option, they’re charged prorated amounts for the time spent on each option. Assuming the change occurred halfway through the billing period, the customer is billed an additional 5 USD: -5 USD for unused time on the initial price, and 10 USD for the remaining time on the new price.

As you see, Proration calculation contains 2 parts: the credit being given back for unused time of old Price, and the amount of new Price.

Now looking closer to your 2 situation:

  1. At the time your customer changed from 1 number to 2 numbers, the $7.99 Invoice was already created with some Proration. When your customer changed again from 2 numbers to 3 numbers, the $9.99 was (probably) also created with some Proration. To correct all the flow, you would need to make sure your Customer pays for the $7.99 Invoice, since they already have got the credit part of it.
  2. Same situation that you would want to make your Customer pay for the second Invoice, since they already have got the credit part of it.

There are a few other alternatives, most feasible one is checking for unpaid Invoice before allow to make the Subscription Update API. This will prevent both situations above from happening in the first place.

Other alternatives is to disable proration by setting proration_behavior to none to save all the headaches, then calculate any price gap manually on your own, if needed.

orakaro
  • 1,468
  • 1
  • 9
  • 9
  • Thanks for the detailed answer. That's how I imagined it, but I didn't know what to do with it. Now I have started to implement rollback subscriptions as follows. – Alexander Dimov Nov 07 '22 at 23:17
  • Example. When a user wants to buy a third number: 1. I check if the last invoice in the subscription has been paid 1.1. If the invoice is paid - I do nothing 1.2. If the invoice is not paid, then I renew the subscription without the last number (downgrade) with the flag proration_behavior: none 2. I upgrade my subscription to 3 numbers – Alexander Dimov Nov 07 '22 at 23:17
  • But it seems to me that this is a very confusing flow and I think to try switching to subscriptions with Graduated pricing (where each next issue is cheaper), it seems that this option will be less of a problem. – Alexander Dimov Nov 07 '22 at 23:22
  • My problem is that when a user has not paid for the second number, he should be able to add a third number and pay immediately, as if he is moving from one number to 3. I solved this by the fact that before each update of the psat_due subscription, I roll back the subscription to the priceId at which the subscription was paid (active) in this case - 1 number, then I do the latest_invoise - void - then I renew the subscription to 3 numbers and expect payment. But for some reason, when this happens, the user gets an invoice for the amount of 1 number.https://ibb.co/2jn1XS7 – Alexander Dimov Nov 10 '22 at 14:54