#nerder
1 messages ยท Page 1 of 1 (latest)
hi! did you finalize the invoice? that's what creates the PI
hey no, i was under the impression that was not needed
from a previous conversation
await this.stripe.invoiceItems.create(
{
customer: customerId,
price: priceId,
},
{
stripeAccount: stripeAccountId,
},
);
const invoice = await this.stripe.invoices.create(
{
customer: customerId,
application_fee_amount: fee.amount,
expand: ['payment_intent'],
},
{
stripeAccount: stripeAccountId,
},
);
const clientSecret = (invoice.payment_intent as Stripe.PaymentIntent).client_secret;
this is my current implementation
yeah that's wrong since you have to finalize the invoice after creating it.
i create the invoiceItems
ok great
let me try real quick
btw I have another small question related to fees since we are here
why application_fee_percent is not exposed here?
as in the subscription creation API?
it just isn't, you have to use application_fee_amount instead
yeah ๐ฆ
there's no good reason for it beyond a lack of prioritisation/design focus. For one time payments, we I suppose expect you to know the amount of the payment upfront and pass an appropriate amount. Made more sense years ago when stuff like automatic tax calculation and things didn't dynamically change the amount
i can't imagine a technical reason why not to, but for sure there is something I don't know here
That's a great explaination @vestal belfry
at the moment since i'm supporting both recurring and one-off prices i calculate the fee my self
as a percentage when is for creating a sub, and as an amount when is for creating a one-off product to buy
i imagine that there are some strange things with prorate and all that things which is why subscription only expose application_fee_percent
would be very convinient tho to have application_fee_percent in the invoice API, and calculate that on your side ๐ as a feedback for the future OFC
yep I agree and that's been feedback for many years unfortunately
Btw coming back from the original issue, i've tried to finalize
but still i don't receive the payment_intent
await this.stripe.invoiceItems.create(
{
customer: customerId,
price: priceId,
},
{
stripeAccount: stripeAccountId,
},
);
let invoice = await this.stripe.invoices.create(
{
customer: customerId,
application_fee_amount: fee.amount,
expand: ['payment_intent'],
},
{
stripeAccount: stripeAccountId,
},
);
invoice = await this.stripe.invoices.finalizeInvoice(invoice.id, {
stripeAccount: stripeAccountId,
});
const clientSecret = (invoice.payment_intent as Stripe.PaymentIntent).client_secret;
i'm doing this now
the cast won't work because you didn't expand it on that call, so payment_intent is just an ID pi_xxx
I should expand it in finalizeInvoice?
you can do
stripeAccount: stripeAccountId,
});
I believe
this should all be in the docs but it's not unfortunately, the docs for one off invoices are quite bad
umm nope actually, or at least TS complains about it
it says that finalizeInvoice only accept a string as ID
well invoice = await stripe.invoices.finalizeInvoice(invoice.id, {expand:["payment_intent"]}); works at least, that's what I use in my own app
invoice = await stripe.invoices.finalizeInvoice(invoice.id, {expand:["payment_intent"]}, {stripeAccount: stripeAccountId,});
it's probably htat for Connect
ok let me try that one
ok nice, that one yes
didn't know there was an actual params option in finalizeInvoice
but as you said it, the doc might be old
in general all functions in the SDK work that way where it's stripe.foo.action(params, requestOptions)
some of them that require an ID though will be like stripe.foo.action(id, params, requestOptions)
clear
still no luck, but might be something else
know the code looks good
await this.stripe.invoiceItems.create(
{
customer: customerId,
price: priceId,
},
{
stripeAccount: stripeAccountId,
},
);
let invoice = await this.stripe.invoices.create(
{
customer: customerId,
application_fee_amount: fee.amount,
},
{
stripeAccount: stripeAccountId,
},
);
invoice = await this.stripe.invoices.finalizeInvoice(
invoice.id,
{ expand: ['payment_intent'] },
{
stripeAccount: stripeAccountId,
},
);
const clientSecret = (invoice.payment_intent as Stripe.PaymentIntent).client_secret;
seems to be related with the invoiceItems now
becuse is creating the invoice properly, and finalize it
but is an invoice for 0$
so of course no payment_intent only setup_intent
yes, if the invoice amount is less than 50c(https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts) there won't be a PaymentIntent, instead the invoice is paid immediately and the amount is added as a debit to the customer's balance , to accumulate into future invoices for them.
yes yes, i knew that. But this wasn't the intended behaviour here is just something wrong with invoiceItems not setting the price properly
now i try to change the order and pass the invoice ID explicitly
like this:
let invoice = await this.stripe.invoices.create(
{
customer: customerId,
application_fee_amount: fee.amount,
},
{
stripeAccount: stripeAccountId,
},
);
await this.stripe.invoiceItems.create(
{
customer: customerId,
invoice: invoice.id,
price: 'price_1M6YeRLAVB3C1lDIPQGDCGvF',
},
{
stripeAccount: stripeAccountId,
},
);
But i don't want to waste your time anymore
i think i can go from here
thank you som much ๐
yeah on the latest API versions you should create the invoice first, and then the items
or on older versions, use pending_invoice_item_behavior: "exclude" so you can opt into that behaviour, creating the items first and then the invoice is a pain and unreliable
actually i prefer the other way, to be explicit on to which invoice i'm adding it instead of rely on that automagic default of "the next draft invoice"
that's what I mean yes
it worked btw ๐
great