#nick_deferintent-subscription

1 messages ยท Page 1 of 1 (latest)

devout pikeBOT
#

๐Ÿ‘‹ 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. Thank you for your patience!

โฑ๏ธ We automatically close idle threads, which makes them read-only. Make sure you stick around to chat in realtime! If this thread is closed and you have another question you'll need to start a new thread.

๐Ÿ”— 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/1215057538853376050

๐Ÿ“ Have more to share? You can add more detail below, including code, screenshots, videos, etc.

terse harnessBOT
finite perch
#

Adding some more context - My Payment Element is set up with this config:

    mode: "subscription",
    currency: "usd",
    amount: 0,
    paymentMethodCreation: "manual",
    appearance: {},
  } as StripeElementsOptionsMode;```
twin jackal
#

Hi, can I ask why you're passing along paymentMethodCreation: "manual", in the options?

#

Can you also share the exact integration you're using?

finite perch
#

We are passing that because we are using a call to our own endpoint which gets passed the paymentMethod.id from stripe.createPaymentMethod.

I'm not sure what you mean by exact integration. What does that entail here?

twin jackal
#

I was curious if you were following a specific document that Stripe published.

finite perch
#

Thank you very much for your time, by the way.

twin jackal
finite perch
#

Correct, we are using subscription schedules. I can share the actual code if you'd like, but what we have for a subscription goes like this:

Client-side

  • User goes through the Payment Element where they enter they attach their ACH details
  • When the user hits a Submit button, we call stripe.createPaymentMethod({elements})
  • We pass that paymentMethod.id, along with a product_id that represents the billing frequency (monthly or biweekly) and some address details from the Address Element to our backend through a GraphQL mutation

Server-side

  • Now in our backend, we call stripe.customers.create and use the paymentMethod ID that was passed in.
  • Then we create the prices based on the product (i.e. billing schedule) the user chose
  • Then we create a subscription schedule using the prices
#

Once the subscriptionSchedule has been created, we were trying to retrieve the subscription and then update the paymentIntent on it with a mandate, which is where we're currently at.

twin jackal
#

Are you wanting to handle the mante on your end explicitly?

finite perch
#

No, if it can be automated. I was initially under the impression that this would be taken care of by the Payment Element, but could not confirm from the docs that I found and was not able to dig anything our of the elements object (rightfully so)

twin jackal
finite perch
#

Sure, one moment.

#

The above options object is being passed into the Elements provider here

            <Outlet context={data satisfies ResidentBalanceContextType} />
          </Elements>```

Then the Payment Element is rendered via
```<PaymentElement
            options={{
              layout: "accordion",
            }}
          />```
#

The handleSubmit fn:

    let paymentID;
    try {
      setLoading(true);
      if (elements) {
        await stripe
          ?.createPaymentMethod({
            elements,
          })
          .then(function (result) {
            console.log(result);
            if (result.error) {
              throw new Error("Could not create Payment Method");
            }
            if (result.paymentMethod) paymentID = result.paymentMethod.id;
          });
      }
      let addressDetails: object | undefined;
      const addressElement = elements?.getElement("address");
      await addressElement?.getValue().then(function (result) {
        if (result.complete) {
          const v = result.value;
          addressDetails = {
            first_name: v.firstName,
            last_name: v.lastName,
            line1: v.address.line1,
            line2: v.address.line2,
            city: v.address.city,
            state: v.address.state,
            country: v.address.country,
            postal_code: v.address.postal_code,
          };
        } else {
          throw new Error("Could not get address details from Address Element");
        }
      });

      const { data } = await initiateCheckoutMutation({
        variables: {
          input: {
            stripe_product_id,
            stripe_payment_method_id: paymentID,
            return_url: window.location.href, // unused with our current payment methods
            ...addressDetails,
          },
        },
      });

      const checkoutID = data?.initiateCheckout.checkout_id;

      if (!checkoutID) throw new Error("Checkout was unsuccessful.");
      setPaymentConfirmed(!!checkoutID);
      setLoading(false);
    } catch (error: unknown) {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      console.error("Mutation error:", error.message);
      setLoading(false);
    }
  };```
twin jackal
#

Taking a look, thank you for sharing the code

finite perch
#

Let me know if you have any questions. The bulk of it is in the initiateCheckoutFn in the last file.

twin jackal
#

No questions so far, still looking into this

#

thank you for your patience

finite perch
#

Of course! Take your time.

twin jackal
finite perch
#

Okay, if we were to figure out how to use paymentMethodCreation: 'auto', would that potentially resolve the issue by handling mandate creation automatically?

terse harnessBOT
light finch
#

nick_deferintent-subscription

#

@finite perch I don't fully get waht the problem is and why you need to pass mandate_data server-side exactly?

finite perch
#

When creating a subscription or invoice with an ACH payment method, the mandate is missing from the PaymentIntent that gets created by the subscription or invoice.

light finch
#

if you hit this error it usually means you integrated wrong

#

You are supposed to

  1. collect payment method details client-side
  2. make a request to your server, create the Subscription
  3. confirm the underlying PaymentIntent client-side
finite perch
#

I assumed so, but could not find any docs that helped my issue. Can you see the code I provided above?

light finch
#

I honestly don't understand the problem with your code, it's a lot of lines of code with no concrete questions and it's mostly client-side about your own code

finite perch
#

At what stage is the mandate_data supposed to be available on the PaymentIntent? Is that something that should be happening once the payment method details are submitted, or is that something I would need to add to the PaymentIntent before I confirm?

light finch
#

neither, if you follow the flow I described you never have to do anything about the Mandate, we do it for you

finite perch
#

Alright, so I'm going to update my code to send back the client secret once a subscription is created, and then call stripe.confirmPayment() using that secret. If that fails, it sounds like I can try changing paymentMethodCreation to auto and Stripe should handle setting up the paymentMethod. Does that sound right?

light finch
#

you don't have to change that last bit. What you said in the first part works fine

finite perch
#

Alright, I'll give it a try, thanks.

light finch
#

Technically you can pass mandate_data server-side when you confirm the PaymentIntent (and that should be before attaching the PaymentMethod)

finite perch
#

The confusion on my end comes from not being able to pass anything to the PaymentIntent created by a Subscription

light finch
#

yeah I know but you're thinking about this the wrong way

#
  1. Create a Subscription
  2. Use its underlying PaymentIntent
finite perch
#

I'm attempting to get the PaymentIntent from a Subscription by accessing the latest_invoice and getting the payment_intent field, but this is null at the time of retrieval. Is that the correct approach?

light finch
#

Yep it's the correct approach. Are you using trials maybe?

finite perch
#

No, we aren't passing any trial_* params.

light finch
#

Can you share a Subscription id?

finite perch
#

Sure, one moment

#

sub_1OrUHSIeSI2aGUBLxO6Xc1Mt

light finch
#

ahhhhhh you're using SubscriptionSchedules lol

#

SubscriptionSchedules are a bit weird, the first Invoice is not immediately finalized. So you first have to call the FinalizeInvoice API to get the PaymentIntent id

finite perch
#

Gotcha! Sorry for the lack of clarity. Let me give that a try. We were using invoices.pay to immediately pay cards instead of waiting an hour.

#

Let me give finalize a go.

light finch
#

all good, I never asked you, that's why I wanted the id to find the 2/3 potential reasons there'd be no PaymentIntent

#

but yeah

  1. Create SubscriptionSchedule
  2. Finalize the Invoice in latest_invoice and expand the payment_intent
  3. Send client_secret to your client to call confirmPayment()
finite perch
#

Sweet, working on that now.

finite perch
#

My man, it worked! Thank you so much. I'm just testing our one time payment flow now.

light finch
#

OMG OMG OMG congrats ๐Ÿ™‚

terse harnessBOT
finite perch
#

Think we're all good now.

#

Thank you very much for the help.