#daria_best-practices
1 messages ยท Page 1 of 1 (latest)
๐ 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.
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.
Sorry for the delay! I'm jugging a few threads and will get to this soon ๐
No worries, take your time!๐ค
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...
Can you provide the Subscription ID? I'd like to verify the double billing was caused by this.
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
sure:
sub_1T67wQBteWsT1PTPMIJmT5B6
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
you are right: the first was 4:14 AM (as draft) and then 4:27AM
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?
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
I think you likely need to pay attention to the amounts of the Invoices and not the quantity of Invoices, but you caused the second Invoice on the 18th by this request: https://dashboard.stripe.com/acct_1DHZBXBteWsT1PTP/test/logs/req_VIxfgjBV0JPJAR
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
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.
Unfortunately we only discovered test clocks today, but we'll definitely use it going forward - it looks very convenient for testing billing scenarios ๐
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
then void the Invoice directly via API
That's a problem because the invoice at that point is still in draft status. According to the API docs, void only works on finalized invoices: https://docs.stripe.com/api/invoices/void - and draft subscription invoices can't be deleted either: https://docs.stripe.com/api/invoices/delete. So we can't void it and we can't delete it
Are you trying to account/prorate for the amount of time the Subscription was paused?
Our expected flow:
- Customer pauses their subscription - we set
pause_collection: { behavior: 'void' } - A billing date arrives while the subscription is paused - the invoice is voided automatically
- The customer resumes sometime later, maybe next month
- We set
billing_cycle_anchor: 'now'to start a fresh billing period - 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
yes, we calculate the paused time and apply a credit to the customer's balance for the unused days
Okay, give me a few minutes to consider and test.
Thank you!
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
Oh interesting! Thanks for looking into it, waiting result
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
there is also an auto_advance parameter that can be passed when you finalize a draft Invoice https://docs.stripe.com/api/invoices/finalize?lang=node&api-version=2025-12-15.preview#finalize_invoice-auto_advance
but I don't think you need it here
Thank you so much for investigating this! ๐
Could you confirm if this is the correct full flow:
- Pause with
pause_collection: { behavior: 'keep_as_draft' } - Billing date arrives while paused - invoice stays as draft until we act on it
- When customer resumes:
- Find draft invoices for this subscription
- Finalize them
- Void them
- Resume subscription with
billing_cycle_anchor: 'now'
- 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
Because using pause_collection.behavior="keep_as_draft" sets auto advance to false. https://docs.stripe.com/billing/subscriptions/pause-payment#collect-payment-later
OH! Got it!!! Omg, thank you so much!
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
Thank you! Is there a way to avoid that ~$0 invoice entirely, for example by passing proration_behavior: 'none'? Or is it expected and harmless?
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
Interesting! Could you point me to the docs for the flexible mode?
Thank you so much for all your help!
Is this correct flow?
- Pause with
pause_collection: { behavior: 'keep_as_draft' } - Billing date arrives while paused - invoice stays as draft until we act on it
- When customer resumes:
- Find draft invoices for this subscription
- Finalize them
- Void them
- Resume subscription with
billing_cycle_anchor: 'now',proration_behavior: 'none'
- Customer gets one new invoice for the new period
Just want a final confirmation before we go to implementation. Thank you!
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
Got it, thank you for the clarification! You've been a great help ๐
Have a nice day!