#morey-stripe-js
1 messages ยท Page 1 of 1 (latest)
Sure, do you have more to the question?
createPaymentMethod will only tokenize the payment details and return a pm_1234 payment method
Hey yes.
What's the right way to attach a payment method using stripe.createPaymentMethod to a customer?
Using stripe.confirmCardSetup was causing my account to continually create the same card/billing info even though the info i submitted was different
confirmCardSetup is used with a Setup Intent to authenticate card ownership with your customer and authorize it for future payments
Using stripe.confirmCardSetup was causing my account to continually create the same card/billing info even though the info i submitted was different
can you explain mroe about that or some some example object IDs or code?
Hey yes, give a moment
In testing:
FE: "setup_intent_unexpected_state"
"seti_1JcEb2LXSN9kljfY94yu5dW4_secret_KGm9GxDpHJWQttqCkETqPbN9Y7KVlxZ"
BE: When trying to create a new intent with stripe.setupIntents.create
Error while Add Payment Method Details: ReferenceError: intent is not defined
BE Code that is triggered on add.
exports.addPaymentMethodDetails = functions.firestore
.document("/stripe_customers/{userId}/payment_methods/{pushId}")
.onCreate(async (snap, context) => {
try {
const paymentMethodId = snap.data().id;
const userId = context.params.userId;
// grab customer data.
const customer = await admin
.firestore()
.collection("stripe_customers")
.doc(userId)
.get();
const paymentMethod = await stripe.paymentMethods.retrieve(
paymentMethodId
);
console.log("PaymentMethod! : ", JSON.stringify(paymentMethod));
// 1. sets to the current location: "/stripe_customers/{userId}/payment_methods/{pushId}"
let setPaymentMethod = snap.ref.set(paymentMethod);
// 2. Create a new SetupIntent so the customer can add a new method next time.
let getSetupIntent = stripe.setupIntents.create({
customer: customer.customer_id,
});
console.log("getScustomeretupIntent: ", JSON.stringify(customer));
console.log("getSetupIntent: ", JSON.stringify(getSetupIntent));
// 3. Stores data to `/stripe_customers/{userId}`
const setSetupSecret = snap.ref.parent.parent.set(
{
setup_secret: intent.client_secret,
},
{ merge: true }
);
await Promise.all([setPaymentMethod, getSetupIntent, setSetupSecret]);
} catch (error) {
console.log("Error while Add Payment Method Details: ", error);
await snap.ref.set({ error: userFacingMessage(error) }, { merge: true });
}
});```
FE Code:
const handleSubmit = async (event) => {
event.preventDefault();
if (!stripe || !elements) {
return;
}
if (errorCard) {
elements.getElement("card").focus();
return;
}
const customerData = (await fs.collection("stripe_customers").doc(user.id).get()).data();
const cardElement = await elements.getElement(CardElement);
const result = await stripe.confirmCardSetup(customerData.setup_secret, {
payment_method: {
card: cardElement,
billing_details: {
name: name,
address: {
line1: address1,
line2: address2,
country: country,
city: city,
postal_code: postal,
state: state,
},
},
},
});
let { error, setupIntent } = result;
// Errors always
if (error) {
if (
error.code === "setup_intent_unexpected_state" &&
error.setup_intent?.status === "succeeded"
) {
const errSetupIntent = error.setup_intent;
const paymentMethodRef = fs
.collection("stripe_customers")
.doc(user.id)
.collection("payment_methods")
.doc();
await paymentMethodRef.set({ id: errSetupIntent.payment_method });
const paymentMethodId = paymentMethodRef.id;
// Triggers backen d
await fs.collection("stripe_customers").doc(user.id).update({
primaryPaymentMethod: paymentMethodId,
});
handleClose();
}
} else {
const paymentMethodRef = fs
.collection("stripe_customers")
.doc(user.id)
.collection("payment_methods")
.doc();
await paymentMethodRef.set({ id: setupIntent.payment_method });
const paymentMethodId = paymentMethodRef.id;
await fs.collection("stripe_customers").doc(user.id).update({
primaryPaymentMethod: paymentMethodId,
});
handleClose();
}
};
I believe it broke here in the backend
// 3. Stores data to `/stripe_customers/{userId}`
const setSetupSecret = snap.ref.parent.parent.set(
{
setup_secret: intent.client_secret,
},
{ merge: true }
);```
oh wait
if this was a variable error, I'd be embarrased ๐
ya... xD
is my flow ok though? using the right stripe functions?
*first time seriously using stripe here
hard to say, there's a lot going on and it depends on your exact business needs. I suggest retesting now and if any particular step isnt doing what you need / expect we (in particular @dusky crater ) can give you another hand
Welcome to the Stripe developer community ๐
haha thank you.
Do you know what would cause the setup_intent_unexpected_state?
Everytime I add a card, FE throws this... but also status = success.
the pm_1234 seem to always be the same PM when i try add another card,
@brittle otter hello, reading up here, can you share with me the request ID that your code is making? You'll find it on your Developer Dashboard: https://dashboard.stripe.com/test/logs/
sure, one moment
3 requests happen when I try adding a card
1st: req_0EskdHvq0BGSQq
2nd: req_bqAfmqK0lNpqzr
3rd: req_9ACHkpZl88Aizb
I'm not sure why 2nd keeps getting that same pm.
so here's the problem: https://dashboard.stripe.com/test/logs/req_0EskdHvq0BGSQq
message: "You cannot update this SetupIntent because it has already succeeded.",
that is the message in the API response
Your code already confirmed this SetupIntent before
but your code is again using this already succeeded SetupIntent's client_secret to confirm it again, which obviously won't work as the SetupIntent is already confirmed successfully
so it is a bug in your code somewhere, I would recommend you add lots of logs in your code on why your server-side is returning the old SetupIntent client_secret and not a fresh new one
Ah, so server used old setupintents.
Currently I try to save setupintents on my database for usage. Would it make more sense to generate the intents on the fly rather than save it in my bd? (was thinking about speed / less calls)
so while I understand your question and can answer it, the issue happening here is separate
if you're fetching a SetupIntent (that is in status: requires_payment_method) and is not status: succeeded , then that can be returned to your client-side to confirm
the problem here is that your backend is returning a succeeded SetupIntent to the webpage to confirm, that would be an incorrect integration
if you're fetching a SetupIntent (that is in status: requires_payment_method) and is not status: succeeded , then that can be returned to your client-side to confirm
Ah, right. succeeded means already confirm not ... call was successful. My misunderstanding
I see the problem. the seti_1234 was not changing at all. Ok I know what to do, thank you for your help @dusky crater
great! glad you found it!
I think it's fixed now :D.
req_NtaLmrxIssITUC
1 more question.
Shouldn't stripe.confirmCardSetup Auto attach the card to the customer? However, I am not seeing any cards attached after successful req
๐ Just hopping in for @dusky crater - stripe.confirmCardSetup will automatically attach only if the SetupIntent has customer set (either during creation or in a subsequent update). It looks like the setup intent used with req_NtaLmrxIssITUC doesn't have any customer specified
You can see us mention it in our api ref: https://stripe.com/docs/api/setup_intents/create#create_setup_intent-customer
Ah @rose sluice thanks. And also for jumping on real quick. I'll try that
Alot of stuff with stripe. it's kinda cool!
hey karbi, I have created the intents like this
customer: customer.customer_id,
payment_method_types: ["card"],
usage: "on_session",
});```
I did double check that customer_id was the customer id.... which in this example is: `cus_KGm9PTZCuem3uH`
But when using that intent it did not link to the customer
What's the setup intent ID?
yeah my guess is that customer.customer_id is null and so it just doesn't pass the parameter. You should print that variable, or look at the log in your Dashboard @brittle otter