#daria_best-practices

1 messages ยท Page 1 of 1 (latest)

crimson estuaryBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1486018795364417598

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

coral burrow
#

Additional:

We also reached out to Stripe support via email. In the first response we were advised that draft invoices can be voided directly. In the follow-up response, after we referenced the API docs, the guidance was updated - we were advised to delete draft invoices instead. However, the API docs mention that subscription invoices can't be deleted: https://docs.stripe.com/api/invoices/delete

We'd really appreciate any clarity on the recommended approach for handling draft subscription invoices in this scenario - ideally with a code example and step-by-step instructions on how to safely handle draft invoices before resuming a paused subscription.

clear valley
#

Sorry for the delay! I'm jugging a few threads and will get to this soon ๐Ÿ™

coral burrow
#

No worries, take your time!๐Ÿค

clear valley
#

Thanks for your patience and sorry you recieved conflicting advice from support. Let me see what the best approach is for handling this draft invoice if the subscription is resumed...

crimson estuaryBOT
clear valley
#

Can you provide the Subscription ID? I'd like to verify the double billing was caused by this.

plush wadi
#

Hi there! I'll be taking over for Jazz here, who needs to step away

#

As they mentioned, the first thing we really need here is to have the ID (sub_123) of the Subscription in question

coral burrow
#

sure:
sub_1T67wQBteWsT1PTPMIJmT5B6

plush wadi
#

okay, there are a very large number of updates on this Subscription relative to its lifespan, so I'm digging through that now to understand what happened, but when you described a "double billing" scenario are you referring to the two Invoices on the 18th?

#

in_1TCI3zBteWsT1PTPmpZlYKk9 and in_1TCIG8BteWsT1PTPDXAUPdK4, which is a $0 Invoice

coral burrow
plush wadi
#

There are literal dozens of requests to set and unset pause_collection over a eighteen-day span. Can you tell me a bit more about what you are trying to test here? What do you want to achieve?

coral burrow
#

We were testing pause/resume implementation in our test environment. The multiple requests are from us iterating through different scenarios: pausing, resuming, checking invoice behavior, adjusting the approach, and retrying. The goal is to implement a reliable pause/resume flow where the customer is charged correctly once upon resuming, without any draft invoices causing double billing

plush wadi
#

Any time you change the billing cycle anchor it causes Stripe to cut a new Invoice

#

Also are you aware of our test clocks feature? They are an essential feature for testing Subscription updates on a realistic cadence

coral burrow
#

We understand that changing billing_cycle_anchor creates a new invoice - that's expected. The problem is with the first invoice (the draft created at 4:14 AM while the subscription was paused).

According to the docs, invoices during pause with behavior: 'void' should be voided automatically. But in practice, they are created as drafts and stay in draft status for up to ~1 hour before being voided. If the customer resumes during this window, the draft is no longer treated as part of a paused subscription - it auto-finalizes and charges the customer.

So the customer was charged for both: the draft that should have been voided, and the new invoice from the billing cycle anchor change. We need a way to handle these draft invoices before resuming.

coral burrow
plush wadi
#

Okay, I can understand where you're confused, and I will do some testing here, but I think this is expected. Stripe optimizes for conversion, so I suspect we are in effect giving the Invoice the chance to be paid if the Subscription is resumed in the one-hour draft period.

I think if you absolutely want to guard against this behavior you have to listen for the invoice.created webhook and then look at the pause_collection value on the Subscription and then void the Invoice directly via API

#

but, I mean, this is for a weekly price. The Subscription cycles on March 11 and you get in_1T9kj8BteWsT1PTPGqniMTRn which is paid. Then you pause collection when the cycle date comes again on the 18th, the customer "renews" and you turn collection back on and in_1TCI3zBteWsT1PTPmpZlYKk9 is paid for $24. If the end intended effect is that the Customer renews the Subscription on the 18th, I don't really understand what you want to happen differently. They said they want to renew and you have a paid Invoice

coral burrow
plush wadi
#

Are you trying to account/prorate for the amount of time the Subscription was paused?

coral burrow
# plush wadi but, I mean, this is for a weekly price. The Subscription cycles on March 11 and...

Our expected flow:

  1. Customer pauses their subscription - we set pause_collection: { behavior: 'void' }
  2. A billing date arrives while the subscription is paused - the invoice is voided automatically
  3. The customer resumes sometime later, maybe next month
  4. We set billing_cycle_anchor: 'now' to start a fresh billing period
  5. A new invoice is created for the new period - the customer pays once

This works fine when there's enough time between the billing date and the resume. However, we hit an edge case: when the customer resumes shortly after the billing date (within ~1 hour), the invoice from step 2 hasn't been voided yet - it's still in draft. After resuming, that draft is no longer treated as paused, so it finalizes and charges the customer.
Combined with the new invoice from step 4, the customer is charged twice.
We need to handle this edge case

coral burrow
plush wadi
#

Okay, give me a few minutes to consider and test.

coral burrow
plush wadi
#

I'm trying to see if I can get you the behavior you want with pause_collection.behavior="keep_as_draft". I think the key point is that when you have that parameter set to "void" it doesn't turn auto-advance off, so when you update pause_collection during that 1-hour draft period, it results in the Invoice getting paid

coral burrow
#

Oh interesting! Thanks for looking into it, waiting result

plush wadi
#

It does prevent the Invoice generated while the Subscription is paused from getting paid

#

So what I did was this - paused the Subscription halfway through the trial, then advanced the test clock to the cycle date/time, though that doesn't matter if you're in keep as draft. You can then finalize and void the Invoice because auto_advance is set to true, so it won't get paid

crimson estuaryBOT
plush wadi
#

but I don't think you need it here

coral burrow
#

Thank you so much for investigating this! ๐Ÿ™

Could you confirm if this is the correct full flow:

  1. Pause with pause_collection: { behavior: 'keep_as_draft' }
  2. Billing date arrives while paused - invoice stays as draft until we act on it
  3. When customer resumes:
  • Find draft invoices for this subscription
  • Finalize them
  • Void them
  • Resume subscription with billing_cycle_anchor: 'now'
  1. Customer gets one new invoice for the new period

You mentioned auto_advance: false is not needed when finalizing here - could you clarify why? The docs say that with auto_advance: true (default), Stripe will automatically attempt payment after finalization: https://docs.stripe.com/api/invoices/finalize
We want to make sure no payment happens between finalize and void

plush wadi
coral burrow
plush wadi
#

So we don't prorate based on the amount of time the Subscription was paused, but that was already the case when you were using void.

#

which is why when you set the billing cycle anchor to now after resuming on the cycle date you get a ~$0 Invoice

coral burrow
plush wadi
#

In classic billing mode, we always cut an Invoice when you move the billing cycle anchor and you can't avoid it. we introduced "flexible" mode which has different proration behavior about a year ago in 2025-03-31.basil

coral burrow
#

Interesting! Could you point me to the docs for the flexible mode?

coral burrow
#

Thank you so much for all your help!

Is this correct flow?

  1. Pause with pause_collection: { behavior: 'keep_as_draft' }
  2. Billing date arrives while paused - invoice stays as draft until we act on it
  3. When customer resumes:
  • Find draft invoices for this subscription
  • Finalize them
  • Void them
  • Resume subscription with billing_cycle_anchor: 'now', proration_behavior: 'none'
  1. Customer gets one new invoice for the new period

Just want a final confirmation before we go to implementation. Thank you!

plush wadi
#

I mean "correct" is subjective but, yes, as I understand it this flow gets you where you want to go.

#

and Resume subscription with billing_cycle_anchor: 'now', proration_behavior: 'none' - proration behavior won't matter on this request, as I'd mentioned

coral burrow
#

Got it, thank you for the clarification! You've been a great help ๐Ÿ™
Have a nice day!