#alx-paymentintent-statemachine
1 messages · Page 1 of 1 (latest)
Sorry if I am missing something out :sorry:
Can you give me the payment Intent ID you're working with?
👍 let me take a look
Yeah so that payment intent hasn't actually been confirmed - you need to actually confirm a payment intent in order to complete the payment process
Thank you
Now I get
'You cannot confirm this PaymentIntent because it's missing a payment method. You can either update the PaymentIntent with a payment method and then confirm it again, or confirm it again directly with a payment method.'
req_gkBrgKdzz1TIXs
So when do I add the Payment Method?
Yes, they are collected
I'm sorry but I need a bit more details in your answers. They are collected how or where? What doc are you following? What part of our API/products are you using?
I am sorry, I will try and be more clearer. So before a Job Poster can pay for job, he needs to add a payment method to his account. This payment method is created by
stripe.PaymentMethod.attach(
payment_method_id,
customer=stripe_customer_id,
stripe_account=stripe_account_id,
)
where payment_method_id is created by the frontend
const { paymentMethod, error } = await createPaymentMethod({
paymentMethodType: "Card",
billing_details: {
name: firstName + " " + lastName,
},
});
and then sent to backend and stored in the database.
Then when Job poster wishes to make a payment he makes a POST request and executes these lines of code
payment_intent = stripe.PaymentIntent.create(
amount=int(Decimal(str(offer.price)) * Decimal("1.2") * Decimal("100")),
currency="ron",
transfer_group="Task" + str(offer.job.id),
)
payment_intent_confirm = stripe.PaymentIntent.confirm(
payment_intent["id"],
)
So there is an error somewhere that the Payment Intent doesn't know who to charge. So my question is how do I tell? Or my reasoning might be wrong. Thank you very much for your input koopajah
Okay so first you should never do the first part. If you collect card details for future payments you should use SetupIntents instead: https://stripe.com/docs/payments/save-and-reuse
As for the second part, when you try to charge a previously saved PaymentMethod, you have to be explicit about that PaymentMethod. When you create or confirm the PaymentIntent you have to pass payment_method: 'pm_123456'. It's not going to "magically" use one on the customer
Does that make sense?
For the second part (PaymentIntent.confirm), I added the Payment Method the one saved in the database, but that will still throw an error
No such PaymentMethod: 'pm_1Ng9u3ImeIzgmIyFekKoPue4'; It's possible this PaymentMethod exists on one of your connected accounts, in which case you should retry this request on that connected account. Learn more at
req_AQzgPn2dl4RziG
yeah I think you have some problem with your setup and you're mixing up transactions on your own account and transactions on connected accounts
You seem to have created that PaymentMethod on one of your connected accounts, but trying to use it on the platform. That will never work
This is the payment flow
So that Payment Method should be attached to ?
There's a fundamental flow of funds decision to make first before building anything
1/ What type of connected accounts are you using? Standard, Custom or Express?
Express
2/ What type of flow of funds are you using? https://stripe.com/docs/connect/charges
With Express you should ~always use Destination Charges, is that the case?
Yes, that is the case
Okay so then everything should happen on your platform. That's where the Customer, PaymentMethod, PaymentIntent, etc. are all created
Yes, during their account registration I create these
# Create a Stripe Customer
customer = stripe.Customer.create(
email=self.user.email,
name=self.user.first_name + " " + self.user.last_name,
)
self.stripe_customer_id = customer.id
# Create a Stripe Connect Account
account = stripe.Account.create(
type="express",
country="RO",
email=self.user.email,
)
self.stripe_account_id = account.id
# Create Account Link, below is for Identity Verification
account_link = stripe.AccountLink.create(
account=account.id,
refresh_url=f"https://taskuri.ro/reauth?accountid={self.stripe_account_id}",
return_url=f"https://taskuri.ro/stripe-account-linked?account_id={self.user.id}",
type="account_onboarding",
)
self.stripe_account_link_url = account_link.url
I am sorry, if you don't want me to paste code, i just maybe think you will catch something that I won't
totally fine to paste code, makes it easier to align
So right now this is for "onboarding" the job poster right? This is mostly fine and not relevant to the issue you were having earlier
Yes, so this is preparing the account incase it needs to be a worker or a job poster. The exact model is with Airtasker, thumbtack, and taskrabbit
Once, these are created if it is a job poster and got an offer, he accepts and pays for the job offer. In order to pay he needs to do PaymentIntent.create and PaymentIntent.confirm. But in order to execute PaymentIntent he needs to have a payment method. He then adds the PM and i get a pm ID (pm_1Ng9u3ImeIzgmIyFekKoPue4). Then he goes back to the payment page and clicks to pay and executes the PaymentIntent.create and PaymentIntent.confirm again to which I get the error I mentioned earlier.
How do you collect their card details for the payment exactly? What does that part of the code looks like
<StripeProvider
publishableKey="pk_test_51NK4IJIBT6PXARQEdPEoav5CDtEap0vzSTHrCwJQvOtf6seOjg4F3aOWigRkzlwCGc6gFVM48hHv494Yi89BmJXy00Ll8EOp2k"
urlScheme="your-url-scheme" // required for 3D Secure and bank redirects
stripeAccountId={stripe_account_id}
>
<CardField
postalCodeEnabled={false}
onFormComplete={(cardDetails) => {
setCard(cardDetails);
}}
style={{ height: 200 }}
/>
</StripeProvider>
two sec
button underneath
<Pressable
style={{
backgroundColor: "#069669",
padding: 15,
borderRadius: 20,
}}
onPress={handleAddPM}
>
<Text style={{ color: "#fff", textAlign: "center", fontSize: 16 }}>
Add card
</Text>
</Pressable>
handleAddPM
const handleAddPM = async () => {
const { paymentMethod, error } = await createPaymentMethod({
paymentMethodType: "Card",
billing_details: {
name: firstName + " " + lastName,
},
});
const access_token = await getToken();
if (error) {
console.log("Error after access_token:", error);
} else {
fetch(`${EXPO_PUBLIC_API_URL}/api/me/add-payment-method/`, {
method: "PUT",
headers: {
AuthorizationX: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ paymentMethodId: paymentMethod.id }),
})
.then(
setStripePmId(paymentMethod.id),
Alert.alert("Cardul a fost adăugat cu succes!")
)
.catch(console.log("Error adding payment method: ", error.message));
}
};
publishableKey="pk_test_51NK4IJIBT6PXARQEdPEoav5CDtEap0vzSTHrCwJQvOtf6seOjg4F3aOWigRkzlwCGc6gFVM48hHv494Yi89BmJXy00Ll8EOp2k"
urlScheme="your-url-scheme" // required for 3D Secure and bank redirects
stripeAccountId={stripe_account_id}
>```
why are you passing the stripeAccountId here?
I am not sure
I will give it a go tomorrow, today too tired. Thank you koopajah!