#nick_deferintent-subscription
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. 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.
Adding some more context - My Payment Element is set up with this config:
mode: "subscription",
currency: "usd",
amount: 0,
paymentMethodCreation: "manual",
appearance: {},
} as StripeElementsOptionsMode;```
Hi, can I ask why you're passing along paymentMethodCreation: "manual", in the options?
Can you also share the exact integration you're using?
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?
I was curious if you were following a specific document that Stripe published.
Ah, we were mostly following this - https://docs.stripe.com/billing/subscriptions/build-subscriptions?ui=elements
However, we are using this for one time payments - https://docs.stripe.com/invoicing/integration
Thank you very much for your time, by the way.
Hm, I do not know that you're following that guide exactly. It looks like you're creating Subscription Schedules: https://docs.stripe.com/api/subscription_schedules/create#create_subscription_schedule-phases-default_payment_method with collection_method: "charge_automatically" . Can you provide the exact use case step by step so we're on the same page?
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.createand 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.
Are you wanting to handle the mante on your end explicitly?
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)
Yeah, when using Payment Elements mandate would be collected for you. Can you share the entire code with me, make sure that you do not share any sensetive information like your API key.
From looking at the code snipped you shared, you look to be using out dereffered intent method, https://docs.stripe.com/payments/accept-a-payment-deferred?platform=web&type=subscription.
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);
}
};```
Checkoutservice where intiateCheckoutFn gets hits
Taking a look, thank you for sharing the code
Let me know if you have any questions. The bulk of it is in the initiateCheckoutFn in the last file.
Of course! Take your time.
I needed to ask a teammate to look. We were able to confirm that with the Deferred intent with the ' paymentMethodCreation: "manual",' this is expected. There is a Beta, https://docs.stripe.com/payments/build-a-two-step-confirmation-confirmation-tokens that could solve this issue that you would need to request access for.
Okay, if we were to figure out how to use paymentMethodCreation: 'auto', would that potentially resolve the issue by handling mandate creation automatically?
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?
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.
if you hit this error it usually means you integrated wrong
You are supposed to
- collect payment method details client-side
- make a request to your server, create the Subscription
- confirm the underlying PaymentIntent client-side
I assumed so, but could not find any docs that helped my issue. Can you see the code I provided above?
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
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?
neither, if you follow the flow I described you never have to do anything about the Mandate, we do it for you
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?
you don't have to change that last bit. What you said in the first part works fine
Alright, I'll give it a try, thanks.
Technically you can pass mandate_data server-side when you confirm the PaymentIntent (and that should be before attaching the PaymentMethod)
The confusion on my end comes from not being able to pass anything to the PaymentIntent created by a Subscription
yeah I know but you're thinking about this the wrong way
- Create a Subscription
- Use its underlying PaymentIntent
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?
Yep it's the correct approach. Are you using trials maybe?
No, we aren't passing any trial_* params.
Can you share a Subscription id?
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
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.
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
- Create SubscriptionSchedule
- Finalize the Invoice in
latest_invoiceand expand thepayment_intent - Send client_secret to your client to call
confirmPayment()
Sweet, working on that now.
My man, it worked! Thank you so much. I'm just testing our one time payment flow now.
OMG OMG OMG congrats ๐