#nerder

1 messages ยท Page 1 of 1 (latest)

dark solarBOT
keen moat
#

for extra details

#
    invoice = await this.stripe.invoices.finalizeInvoice(
      invoice.id,
      { expand: ['payment_intent'] },
      {
        stripeAccount: stripeAccountId,
      },
    );

this is how i'm completing retrieve the payment_intent client secret and return it to the frontend to complete

fathom ivy
keen moat
#

nono, is not that scenario

#

i'm not looking for setup intents here

#

i'm doing a payment of an invoice with a payment method, and i want that payment method attached to the customer as soon as they have complete the payment for the first time

#

so that they can use it again in the future

fathom ivy
#

Thank you for the added details, looking

keen moat
#

with subscriptions it works properly, but i'm not sure why with invoice it doesnt

fathom ivy
#

Can you share which Setup Intent document you're using here?

keen moat
#

ill show you the code

#
  async create(accountId: AccountId, customerId: string, priceId: string, fee: Fee): Promise<Invoice> {
    const stripeAccountId = accountId.value;
    //Creating the invoice
    let invoice = await this.stripe.invoices.create(
      {
        customer: customerId,
        application_fee_amount: fee.amount,
      },
      {
        stripeAccount: stripeAccountId,
      },
    );
    //Add products to the invoice
    await this.stripe.invoiceItems.create(
      {
        invoice: invoice.id,
        customer: customerId,
        price: priceId,
      },
      {
        stripeAccount: stripeAccountId,
      },
    );

    // finalize the invoice and expand the payment_intent
    invoice = await this.stripe.invoices.finalizeInvoice(
      invoice.id,
      { expand: ['payment_intent'] },
      {
        stripeAccount: stripeAccountId,
      },
    );
    
    //extract the client secret
    const clientSecret = (invoice.payment_intent as Stripe.PaymentIntent).client_secret;

    //return it back to the frontend
    return Invoice.of(invoice.id, ClientSecret.of(clientSecret));
  }
#

this is the method i'm using to create the payment_intent

#

in the frontend instead (using flutter_stripe)

#
    await _stripe.confirmPayment(
      clientSecret,
      PaymentMethodParams.card(
        paymentMethodData: PaymentMethodData(
          billingDetails: BillingDetails(
            email: customerEmail,
            name: customerName,
          ),
        ),
        options: PaymentMethodOptions(
          setupFutureUsage: PaymentIntentsFutureUsage.OffSession,
        ),
      ),
    );
#

so basically the fronted call the API for create the invoice and wait for the secret to come back then completes the payment intent when the customer confirms

#

the payment succeed but there is not payment method attacched to the customer

fathom ivy
keen moat
#

ok, so i should listen to a webhook event and update the payment method?

#

but why this works for subscriptions instead?

#

is done by default there when you create a subscription?

fathom ivy
#

Subscription works differently.

#

Yes, you can listen to the payment intent succeeded event, and retrieve that Payment Intent to get the Payment Method id.

keen moat
#

ok ill try this

#

i've tried by the way and for some reason when creating a sub i receive payment_method.attached event and the default payment method is set automatically

#

i guess that in that case i should skip the payment_intent.succeeded event for when is coming from a subscription in order to avoid attach the default payment method again

fathom ivy
#

But that is for subscription correct? The above integration is for creating an invoice, then adding the Payment Method to the customer for a default Payment Method.

keen moat
#

yes this is correct, there should be something i don't understand because when in the fronted i setup PaymentIntentsFutureUsage.OffSession my understanding was that this is what the fronted library is calling under the hood: https://stripe.com/docs/api/payment_intents/object#payment_intent_object-setup_future_usage

#

which is the case when the payment_intent originates from a subscription.create but not from a invoice.finalize

#

now, i can "force it" with the approach you propose of setting it manually, but i feel there is something wrong

fathom ivy
#

From you client-side code, you set the up setupFutureUsage: PaymentIntentsFutureUsage.OffSession so you can charge this Payment Method later. Attach it to the customer's invoice default settings.

#

With Subscriptions, it just works.

keen moat
#

ok, i'll fix it as you propose ๐Ÿ™‚

#

sorry to be a pain, just wanted to understand why they act differenly (or at least not in the way I expected it)

keen moat
#

btw, seems the proposed solution doesnt work

#

This PaymentMethod was previously used without being attached to a Customer or was detached from a Customer, and may not be used again.

#

if I try to do this:

  await stripe.paymentMethods.attach(
    paymentMethodId,
    { customer: customerId },
    {
      stripeAccount: connectedAccountID,
    },
  );

  await stripe.customers.update(
    customerId,
    {
      email,
      invoice_settings: {
        default_payment_method: paymentMethodId,
      },
    },
    {
      stripeAccount: connectedAccountID,
    },
  );
ocean portal
#

๐Ÿ‘‹ taking over here. Gimme a few mins to go through this thread

keen moat
#

hey

#

thanks!

ocean portal
#

Can you give the PaymentMethod Id here? For easier tracking

keen moat
#

in my last was: pm_1M7UeoLAVB3C1lDIDF2PgwoE

#

this is the payment instead pi_3M7UhjLAVB3C1lDI0wp7ifab

#

i don't see something that indicated that the payment method should be used for future usage

#

hey did you manage to find anything?

ocean portal
#

Hi, sorry gimme a few mins

#

To avoid confusion let me clarify. I am looking at pm_1M7UeoLAVB3C1lDIDF2PgwoE. It's created and confirmed by in_1M7UelLAVB3C1lDIvhXK9zxw and pi_3M7UenLAVB3C1lDI1CC8Vqgl

keen moat
#

there is something quite odd here, the payment intent created by the subscription has indeed setup_future_usage: "off_session"

ocean portal
#

It's different than pi_3M7UhjLAVB3C1lDI0wp7ifab you mentioned

#

I think you probably mixed things up

keen moat
#

might be

#

this is one

#

they are all the same, all the PI created from an invoice.finalize create a PI which as setup_future_usage set as null

ocean portal
#

in_1M7UhhLAVB3C1lDIYpslJLOf

#

pm_1M7UhlLAVB3C1lDIQOcqxtaL

#

pi_3M7UhjLAVB3C1lDI0wp7ifab

keen moat
#

correct

#

check the logs from this one for instance

ocean portal
#

Okie they are tighted to cus_MrD7vzb27CmRj0

keen moat
#

you will see that the POST request that the fronted made is the same

#

but for some reason in the PI response the setup_future_usage is null

#

and if I try to set it up by myself handling payment_intent.succeeded it fails

ocean portal
#

Hey let's take a step back. By this state, what request you made after receiving payment_intent.succeeded and what is its request id? req_xxx

keen moat
#

after?

#

this 2

#
  await stripe.paymentMethods.attach(
    paymentMethodId,
    { customer: customerId },
    {
      stripeAccount: connectedAccountID,
    },
  );

  await stripe.customers.update(
    customerId,
    {
      email,
      invoice_settings: {
        default_payment_method: paymentMethodId,
      },
    },
    {
      stripeAccount: connectedAccountID,
    },
  );
#

attaching the payment method i retreive from the PI and try to set it as default

#

but it fails with: This PaymentMethod was previously used without being attached to a Customer or was detached from a Customer, and may not be used again.

#

if you want i can try another example fresh

ocean portal
#

No, let's find that errors in your request log

keen moat
#

req_WAkr5PZTLlQN1r

#

this one for instance

#

this feels like a bug in how invoice creates the payment intent underneath

ocean portal
#

Ummm let me try it myself

#

Hi I just reproduced it. You were correct that this is like a limitation on our side, that when you confirm an Invoice's PaymentIntent via frontend, the confirmed PaymentMethod is treated as an one time used PM and can't be attached to the Customer later

keen moat
#

wow

ocean portal
#

My suggestion is try to collect the PaymentMethod beforehand, via a SetupIntent

keen moat
#

i was going crazy here

#

eheh

#

๐Ÿ˜ฆ

ocean portal
#

then once you have it and attached to the Customer, then you can use it later on in Invoice without thinking of confirmation

keen moat
#

that's not ideal for how my flow works i should rethink the entire thing

ocean portal
#

Just simply set it on the Invoice's default_payment_method, or the Customer's invoice_settings.default_payment_method

keen moat
#

can't i create the payment intent myself then?

ocean portal
#

Independent of the Invoice? Yes but that wouldn't link to the Invoice

keen moat
#

oh ok

#

i can't attach a payment intent to an invoice

#

that's a pity btw

#

what about using charges?

ocean portal
#

Charges is an old API and I don't recommend it

#

Let's go with PaymentIntent

keen moat
#

ill try tomorrow, because i need to pass also the payment method

#

and i'm not sure how

#

thank you so much for your help tho

#

and in finding the issue

#

hopefully it can be solved soon