#rcc_schedule-update
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/1415390401162117192
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- nukesforbreakfast_api, 9 hours ago, 33 messages
- nukesforbreakfast_best-practices, 14 hours ago, 30 messages
- nukesforbreakfast_api, 4 days ago, 11 messages
oops, linked the wrong doc: https://docs.stripe.com/billing/subscriptions/subscription-schedules#subscription-schedule-sub-updates
Hi, as you stated those are two independent APIs and it's expected that some behaviors are different. A work around is by creating a backdated subscription and then creating a schedule on top of that, https://docs.stripe.com/api/subscription_schedules/create?api-version=2025-07-30.preview#create_subscription_schedule-from_subscription
If the above recommendation does not work, are you able to speak why this would not work for your use case so I can share it with the product team?
So, here's the scenario:
I have a concept of a permit fee that renews annually at a lower rate than the initial permit fee cost. Let's assume this is a Commercial permit fee of $50 for the first year and $25 every year thereafter. There is also a Residential permit fee of $25 and $15 every year thereafter.
Now assume that the administrator sets this up based on a permit application received, but accidentally selects "Commercial" when it should have been "Residential". Say a month goes by before someone recognizes the mistake. I now need to update both phases to use the lower price and credit the permit holder for the difference.
Since updating the phases would cause an incorrect proration on the current active phase, I have to do one of the following:
- Update both phases but turn off prorations. Then credit the user manually outside of stripe automatic prorations.
- Update only the second phase to the correct price, but leave the first phase unchanged. Then use the subscriptions API to backdate the proration to the lower price while it is still attached to the schedule, getting the schedule and the subscription out of sync on the first phase. I believe the second phase transition will still happen normally.
I'm not sure of the full implications of the second option. I'm actively testing this in my sandbox today.
So I don't believe the suggestion would work since I need to update an already active and paid for subscription.
Why could not you create a new subscription for the 'Commercial' price for that customer and cancel the 'Residential' subscription?
If you want to keep it on the same subscription, you could also use Credit Notes, https://docs.stripe.com/invoicing/dashboard/credit-notes instead of having to manually create it outside of Stripe. The credit note balances either increases/ decreases the amount that is owned on the future invoices.
I guess that could work. What happens to the amount already paid on the old subscription?
In which of the above two flows?
so I would cancel the subscription schedule, cancelling the original Commecial subscription. I would then backdate a new Residential subscription to the original subscription date.
but I need the Commercial subscription cancellation to basically credit the entire amount already collected.
it doesn't look like I can backdate a cancellation though? https://docs.stripe.com/billing/subscriptions/cancel?dashboard-or-api=api#custom-cancel-date
You can offer a freaa trial for what ever that amount to
Or, you can create a credit note for that amount on the customer so the next invoice is lower
You can test both and see which one works best for your use case
ok. But to confirm, it's not possible to backdate a cancellation of a subscription?
no, that is not supported: https://docs.stripe.com/api/subscriptions/cancel?api-version=2025-07-30.preview
ok. Let me test some things out then.
btw, is any metadata set on subscription_schedule.phases.metadata propagated to the subscription itself, the subscription invoices, and the subscription invoice items?
We document when it's copied over: https://docs.stripe.com/metadata#copy-metadata but otherwise, no
Do subscription created invoice items not show up in stripe_client.v1.invoice_items.list(options={"stripe_account": account.id})?
invoice_items
<ListObject list at 0x70352ed0f250> JSON: {
"data": [],
"has_more": false,
"object": "list",
"url": "/v1/invoiceitems"
}
req_5SwZgWj4QQXoV1
It should, https://docs.stripe.com/api/invoiceitems/list?api-version=2025-03-31.basil surface them
Can you share the invoice item you expect here?
sure one second
>>> invoice.id
'in_1S5sG5Pfgdk4NFmKO7TDqe0L'
>>> invoice.parent.subscription_details.subscription
'sub_1S5sG4Pfgdk4NFmKpUr7M6US'
>>> invoice.lines
<ListObject list at 0x70352ed0ec60> JSON: {
"data": [
{
"amount": 5000,
"currency": "usd",
"description": "1 \u00d7 industry permit fee (at $50.00 / year)",
"discount_amounts": [],
"discountable": true,
"discounts": [],
"id": "il_1QcFLwPfgdk4NFmKhfAGNyfv",
"invoice": "in_1S5sG5Pfgdk4NFmKO7TDqe0L",
"livemode": false,
"metadata": {
"alarm_system_id": "alarmsystem_MAwOQmzCZ2JQJFeG79ohogIa1WT",
"alarm_user_id": "alarmuser_rF4lWENh9YithPNR41sccfyqkyQ",
"jurisdiction_id": "org_CNxBkQbcXA6ZLXx3oikyeKaOKaQ"
},
"object": "line_item",
"parent": {
"invoice_item_details": null,
"subscription_item_details": {
"invoice_item": null,
"proration": false,
"proration_details": {
"credited_items": null
},
"subscription": "sub_1S5sG4Pfgdk4NFmKpUr7M6US",
"subscription_item": "si_T1w8S88QnnLgzp"
},
"type": "subscription_item_details"
},
"period": {
"end": 1767225600,
"start": 1735689600
},
"pretax_credit_amounts": [],
"pricing": {
"price_details": {
"price": "price_1S5sG4Pfgdk4NFmK4X7vjfIO",
"product": "permittype_qZqPtM0edgNy7bSri6RqWwhB2nj"
},
"type": "price_details",
"unit_amount_decimal": "5000"
},
"quantity": 1,
"taxes": []
}
],
"has_more": false,
"object": "list",
"total_count": 1,
"url": "/v1/invoices/in_1S5sG5Pfgdk4NFmKO7TDqe0L/lines"
}
>>> stripe_client.v1.invoice_items.list(options={"stripe_account": account.id})
<ListObject list at 0x70352ecf6710> JSON: {
"data": [],
"has_more": false,
"object": "list",
"url": "/v1/invoiceitems"
}
>>> invoice.stripe_account
'acct_1S5sG0Pfgdk4NFmK'
>>> account.id
'acct_1S5sG0Pfgdk4NFmK'
Ok, you used Test Clocks here: https://dashboard.stripe.com/test/logs/req_PyF7TYrH8sGzfU so that might be at play. Can you create a subscription without Test Clocks please and see if that returns the item?
sure, one second
>>> subscription_schedule2 = SubscriptionScheduleFactory(
... stripe_test_client=stripe_client, stripe_account=account.id
... )
>>> stripe_client.v1.invoice_items.list(options={"stripe_account": account.id})
<ListObject list at 0x70352ed0fe80> JSON: {
"data": [],
"has_more": false,
"object": "list",
"url": "/v1/invoiceitems"
}
>>> subscription_schedule2.id
'sub_sched_1S5szVPfgdk4NFmKUlPjD3td'
>>> subscription2 = stripe_client.v1.subscriptions.retrieve(subscription_schedule2.subscription, options={"stripe_account": account.id})
>>> subscription2.id
'sub_1S5szVPfgdk4NFmKb9oXIwTh'
>>> invoice2 = stripe_client.v1.invoices.retrieve(subscription.latest_invoice, options={"stripe_account": account.id})
>>> invoice2.id
'in_1S5sG5Pfgdk4NFmKO7TDqe0L'
>>> invoice2.lines
<ListObject list at 0x70352ed25040> JSON: {
"data": [
{
"amount": 5000,
"currency": "usd",
"description": "1 \u00d7 industry permit fee (at $50.00 / year)",
"discount_amounts": [],
"discountable": true,
"discounts": [],
"id": "il_1QcFLwPfgdk4NFmKhfAGNyfv",
"invoice": "in_1S5sG5Pfgdk4NFmKO7TDqe0L",
"livemode": false,
"metadata": {
"alarm_system_id": "alarmsystem_MAwOQmzCZ2JQJFeG79ohogIa1WT",
"alarm_user_id": "alarmuser_rF4lWENh9YithPNR41sccfyqkyQ",
"jurisdiction_id": "org_CNxBkQbcXA6ZLXx3oikyeKaOKaQ"
},
"object": "line_item",
"parent": {
"invoice_item_details": null,
"subscription_item_details": {
"invoice_item": null,
"proration": false,
"proration_details": {
"credited_items": null
},
"subscription": "sub_1S5sG4Pfgdk4NFmKpUr7M6US",
"subscription_item": "si_T1w8S88QnnLgzp"
},
"type": "subscription_item_details"
},
"period": {
"end": 1767225600,
"start": 1735689600
},
"pretax_credit_amounts": [],
"pricing": {
"price_details": {
"price": "price_1S5sG4Pfgdk4NFmK4X7vjfIO",
"product": "permittype_qZqPtM0edgNy7bSri6RqWwhB2nj"
},
"type": "price_details",
"unit_amount_decimal": "5000"
},
"quantity": 1,
"taxes": []
}
],
"has_more": false,
"object": "list",
"total_count": 1,
"url": "/v1/invoices/in_1S5sG5Pfgdk4NFmKO7TDqe0L/lines"
}
Worked?
no, the invoice items list call returns nothing still
>>> stripe_client.v1.invoice_items.list(options={"stripe_account": account.id})
<ListObject list at 0x70352ed25db0> JSON: {
"data": [],
"has_more": false,
"object": "list",
"url": "/v1/invoiceitems"
}
is it because the invoice isn't finalized yet?
I tested this end to end, and I can confirm that should return invoice items from subscription invoices.
Ah potentially, can you try that?
can you confirm which api endpoint you're listing from?
sure one second
>>> stripe_client.v1.invoice_items.list(options={"stripe_account": account.id})
<ListObject list at 0x70352ed0eb20> JSON: {
"data": [],
"has_more": false,
"object": "list",
"url": "/v1/invoiceitems"
}
>>> invoice.status
'open'
>>>
Ok, I'm making the wrong call. Let me try again using https://docs.stripe.com/api/invoiceitems/list?api-version=2025-03-31.basil
yes, I'm doing a GET /v1/invoiceitems not GET /v1/invoices/:id/lines
yeah, I'm able to see what you're seeing. Let me look around to confirm what the expected behavior is.
Sorry for the confusion
np
๐ taking over and trying to grasp what you are doing (and failing for now) so give me some time
currently attempting to understand why a subscription invoice's items don't show up when listing invoice items.
yeah my colleague said the same and I don't get the wording at all ๐
InvoiceItems are special and have the id ii_12345. They are separate from an Invoice's lines called InvoiceLineItem with the id ili_1234
So if you have an Invoice for $100 with one line for the recurring Price ili_ABC that one will never appear in the List InvoiceItems API.
OK, so having a line item on an invoice != an invoice item.
yeah it's super confusing to ~everyone
so when do line items on an invoice correspond to an invoice item? Only when I manually create an invoice item?
ok, that's good to know
Is there a difference of behavior when changing a price on a subscription item through updating the subscription vs updating the subscription item directly?
is there a way to customize the description on created invoice items from a proration?
also, do test clocks prevent proration invoice items from appearing in the list endpoint?
Hmmm not sure, can you try updating it via https://docs.stripe.com/api/invoiceitems/update#update_invoiceitem-description ? I never remember if we let you change those
and no TestClocks shouldn't be relevant here. But just make a simple thing/test with no TestClock to start and confirm
ok, because I created a proration and I see pending invoice items in the dashboard but no invoice items are being returned from the API.
hmmm so maybe we ignore those if they are associated with a TestClock. Are you passing the Customer id on the List call?
no, I'm not passing anything
let me try adding the customer
ah, so now it shows them
yeah I think anything related to a TestClock in the API requires passing the TestClock or associated Customer id. Definitely confusing though ๐
So I noticed that the proration code logic creates negative unit amount invoice items, where if I did it manually I would have used credit notes. What's the difference between the two and why would one use one over the other?
๐ stepping in here
You can create/add negative Invoice Items as well.
Generally Credit Notes are meant to be used to adjust the value of a finalized Invoice.
But on creation you wouldn't generally use Credit Notes
Right, but since this use case is for crediting an overcharge because we set up the subscription on the wrong plan, I would use a credit note on the subscription invoice(s) to denote that if I was doing it manually. That sounds like the right way for the manual approach if I don't attempt to use Stripe's proration logic.
For example, we charged them $50 when it should have been on the $25/year plan. So we need to credit them the entire $50 and charge $25.
Gotcha, it might be easiest here actually to just give them a Credit Balance: https://docs.stripe.com/invoicing/customer/balance
That would just reduce the amount of the next finalized Invoice.
However if you want to be more descriptive on the Invoice then yes, a Credit Note would work.