#j_unexpected
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/1303007881066582036
đ Have more to share? Add more details, code, screenshots, videos, etc. below.
Essentially, I'm running the following code:
const subscription = await stripe.subscriptions.retrieve(subscriptionId, {
expand: ['latest_invoice'],
});
and I get a certain object, which I then feed into a function that uses
const invoice = await stripe.invoices.retrieveUpcoming({ subscription: subscriptionId });.
When I retrieve upcoming, if the upcoming involves an item which would cause an error (the specific error being ``` Error: No such Invoice Item: 'il_tmp_1QGSFsEk6sr5GyDhqQ0tgDvf'(livemode=false)
at generateV1Error (/Users/kcobey/Documents/projects/alloy-monorepo/node_modules/.pnpm/stripe@17.0.0/node_modules/stripe/cjs/Error.js:11:20)
at res.toJSON.then.Error_js_1.StripeAPIError.message (/Users/kcobey/Documents/projects/alloy-monorepo/node_modules/.pnpm/stripe@17.0.0/node_modules/stripe/cjs/RequestSender.js:108:62)
at processTicksAndRejections (node:internal/process/task_queues:105:5)
const invoice = await stripe.invoices.retrieveUpcoming({ subscription: subscriptionId });.
returns this error-causing object
[
{
id: 'il_tmp_1QGSFsEk6sr5GyDhqQ0tgDvf',
object: 'line_item',
amount: 0,
amount_excluding_tax: 0,
currency: 'usd',
description: 'Shipping',
discount_amounts: [],
discountable: true,
discounts: [],
invoice: null,
invoice_item: 'ii_1QGSFsEk6sr5GyDhqQ0tgDvf',
livemode: false,
metadata: {},
period: { end: 1734584400, start: 1730495980 },
plan: null,
pretax_credit_amounts: [],
price: {
id: 'price_1Nf8B9Ek6sr5GyDh1fcr6iDw',
object: 'price',
active: true,
billing_scheme: 'per_unit',
created: 1692047999,
currency: 'usd',
custom_unit_amount: null,
livemode: false,
lookup_key: null,
metadata: {},
nickname: null,
product: 'prod_OS2FaTbRxF6CX6',
recurring: null,
tax_behavior: 'unspecified',
tiers_mode: null,
transform_quantity: null,
type: 'one_time',
unit_amount: 0,
unit_amount_decimal: '0'
},
proration: false,
proration_details: { credited_items: null },
quantity: 1,
subscription: 'sub_1QGSFsEk6sr5GyDhB91u9X2v',
tax_amounts: [ [Object] ],
tax_rates: [ [Object] ],
type: 'invoiceitem',
unit_amount_excluding_tax: '0'
}
]
This wasn't causing issues for us before we upgraded from Stripe 8 to latest version, so that might also be useful info RE: what might have changed here
Also, the object returned after about three minutes is an empty object, which is another thing I was curious about.
The invoice upcoming endpoint creates a temporary line item object to show what the next invoice might look like. I don't know if the objects have short lifespan and get destroyed behind the scene.
Taking a step back, what exactly are you trying to do here? More context would help think of workarounds
Just trying to remove shipping from any line items that already exist. Why does it provide a temporary line item object, is there any way to just get upcoming invoices?
The next invoice is drafted based on the billing cycle anchor. The actual invoice won't exist until subscriptions' renewal time.
Are you adding shipping as a separate line subscription item on the invoice?
If so, you should use deleted boolean to remove the subscription item from the upcoming invoice (preview) - https://docs.stripe.com/api/invoices/upcoming#upcoming_invoice-subscription_items-deleted
return;
}
const [retrievedSubscription, shipping] = await Promise.all([
retrieveSubscription(subscriptionId),
shippingMethodService.getShippingMethodByCustomerState(shippingMethodId, customer.stateAbbr),
]);
const { upcomingInvoice } = retrievedSubscription;
console.log('ping2');
if (upcomingInvoice) {
const shippingTax = await taxService.getShippingTaxRate(
customer,
shipping.stripePrice.unit_amount,
upcomingInvoice.subtotal
);
console.log('ping3');
const stripeShippingTax = shippingTax
? await stripe.taxRates.create({
display_name: 'Shipping Tax',
inclusive: false,
percentage: numberToPercent(shippingTax),
})
: undefined;
console.log('ping4');
console.log(shipping.stripePrice.id);
await stripe.subscriptions.update(retrievedSubscription.stripeSubscriptionId, {
add_invoice_items: [
{
price: shipping.stripePrice.id,
...(stripeShippingTax && { tax_rates: [stripeShippingTax.id] }),
},
],
});
}```
Sort of, it's more that we use it. to do calculations while we update (since what we're doing here is potentially updating the shipping method, this is all part of our reschedule plan)
So just to clarify, adding an invoice item to a previous/current invoice doesn't make it appear on the next invoice automatically.
Subscription Items are recurring while Invoice Items are one-off. So the upcoming invoice shouldn't really have an invoice item for shipping unless you added it explicitly.
Right... I'm beginning to see that in the logs, yeah.
There were some things we did early on as workarounds which have been kinda deprecated, obviously just good to know best practice going forward even if it means I have to really carve up our existing code
What would be the right way to handle a situation like this?
Do you mean how to handle tax with a subscription? or something else?
Okay, so, sorry that this is sort of a meta-question, but how long do these threads idle before you close them
And my other question is, let's say there is an invoice object, and it does have an explicitly set shipping. Is it necessary at all for me to remove that shipping, or is the removal function which is throwing the error essentially doing nothing useful.
Because what I'm hearing is that this function is pointed in the wrong direction, possibly at something completely temporary, and throwing errors.
Okay, so, sorry that this is sort of a meta-question, but how long do these threads idle before you close them
There's no set time but they're closed automatically based on idle time.
And my other question is, let's say there is an invoice object, and it does have an explicitly set shipping. Is it necessary at all for me to remove that shipping, or is the removal function which is throwing the error essentially doing nothing useful.
I'm not sure I understand. Whether to remove the shipping item or not is completely dependent on your integration. If you application is calculating a new shipping/tax amount on each invoice then it might make sense to NOT make the tax line item recurring and add them one off.
But if the tax line items are one-off, they shouldn't be present in the upcoming invoice any way
so there's no need to delete it in that case
additionally, the upcoming invoice endpoint is just to preview the next invoice. Removing a line item in the request to this endpoint won't remove it from the actual invoice
Got it. I think I might hop on a call with someone about our architecture here and get back to you on this, but this is already tremendously helpful.