#batler-cardelement-confirmation
1 messages · Page 1 of 1 (latest)
@glacial scroll It feelsl like you are misunderstanding something fundamental with the product here.
Collecting card details is protected by PCI compliance which comes with strict rules. The way it works is that you use one of our UI libraries client-side to collect card details securely. Not server-side (which is blocked by default and can lead to all your transactions beind blocked)
You didn't read what I typed.
I did
I DO NOT WANT THE CARD DATA
Your API refused to work unless I sent the full card.
yes because you're not listening and using the wrong API
I am asking how to send the source / token / whatever instead.
I am asking how to send the source / token / whatever instead.
sending where? Where does that source/token/whatever comes from?
Let's simplify the process...
Step 1: the client's browser loads a script, one moment...
<script src="https://js.stripe.com/v3/"></script>
<script src="checkout.js" defer></script>
In Square's example code this happens:
setOutcome(result)
That result is a JavaScript object that contains the token/source based on...
stripe.createSource(cardNumberElement, {}
Tokens and Sources are legacy and were deprecated years ago. So why are you using that API?
Because that is the only thing that worked that I could find.
I don't treat code like an installer on a Windows machine.
I need to have individual iframes per card field (one for the 16 digit number, one for the expiration, etc).
The demo that was presented creates one monolithic form in a single iframe.
I can't style client websites if Stripe only presents a monolithic iframe.
That "monolithic iframe" is drastically more powerful though and you 100% should be using it and selling your clients on it.
No, I won't be using the monolithic ifame, I need the form fields broken up in to separate "fields"/iframes.
But ultimately if you have the split CardElement integration working then what you need to do is
1/ Create a PaymentIntent server-side
2/ Confirm the PaymentIntent client-side with confirmCardPayment()
Where is a tutorial for the latest version that doesn't dump a monolithic iframe?
So...
- I ask for help with server code and am told about client code.
- I get the server code working but it's old.
- I ask for a modern client code and you send me a link to server code!
...I'm asking this with only a respectful intention: do you know the difference between client and server?
yep I do
You asked for code, I explained exactly what to do, you asked for a doc, I gave you an exact doc, which has both client-side and server-side code.
Clearly you understand you need code client-side since you're already using our CardElement UI component and were calling createSource() in Javascript create a Source object (deprecated).
So you can yell at me all you want and demand server-side code, but ultimately you need both sides and you know that because you already wrote the client-side part. What you need to do now is modify that client-side code to properly finish this
1/ Create a PaymentIntent server-side for the amount/currency you're trying to charge
2/ Client-side, collect card detais with Elements (you're using the legacy CardElement components because you don't like the full iframe for PaymentElement)
3/ Confirm the PaymentIntent client-side using the card details collected securely in that UI element by calling confirmCardPayment() instead of createSource
batler-cardelement-confirmation
let me get a quick screenshot in here to help visualize this...
Earlier you shared this: stripe.createSource(cardNumberElement, {}
That's what you need to modify to switch to stripe.confirmCardPayment() which is covered in details in that doc I linked you to.
literally this step https://stripe.com/docs/payments/accept-card-payments?platform=web&ui=elements#web-submit-payment which is step 3 in my list above
So here is the card form with each field being it's own iframe...
I've got the result object using either the stripe.createSource or stripe.createToken
Just to be clear: I'm an experienced developer, I know our products inside and out. I know exactly what you're doing
do not call createSource() nor createToken() at all. Replace that entire part of the code with what's covered in the doc I shared
Okay, I'm clear on that, so work with me on this...
I'm not using anyone's PHP code other than (if I can even get it to work) see what cURL raw outpit it produces.
I was using Square for a few years and their format was also similar.
Sure but I'm not going to teach you how to do url form encoding or curl requests
- hash generated at client
- I AJAX it to my server
- I do my records at my server.
- I PHP / cURL to the API server.
it's your right to refuse to use our official PHP library but you're on your own here
and no, the steps you're doing are not how you use our product. So you can do it this way
sorry you can not do it this way
I'm sure you want to, and you'll try. But you need to flip how you think about things. For example 3D Secure is more and more common in the world, even in the US. If you collect card details this way, when you try to charge that card you'll get a decline saying "well you need to do 3D Secure"
Re-posting what I said earlier, this is the flow:
1/ Create a PaymentIntent server-side for the amount/currency you're trying to charge
2/ Client-side, collect card detais with Elements (you're using the legacy CardElement components because you don't like the full iframe for PaymentElement)
3/ Confirm the PaymentIntent client-side using the card details collected securely in that UI element by calling confirmCardPayment() instead of createSource
yep
and we handle 3DS at the same time if needed
I know it's mind bending at first. It does this to all developers because it's not how most competitors do it. But even for card payments when you start needing to handle 3D Secure, flipping things over where you start with "I want a payment for $100 please" and then client-side you go "Okay now use those card details and confirm it right now and show a decline if it fails or do 3DS if needed"
There are ways to do what you want, I can show you, but only after you grasp what I am trying to explain, otherwise in a few weeks you will be quite mad you didn't realize the downside
Ah...
The issue I have is that we're not supposed to trust the client.
So what you're inferring in the process...
you don't have to trust the client. Your server initiated the payment request by creating the PaymentIntent explicitly.
Well...
The form I have that generates the hash works without any interaction with my server, it's all JavaScript.
I understand all of that, that doesn't change what I am describing
Let's shift gears
you clearly want your answer and I won't convince you
1/ call createPaymentMethod() instead since it's newer https://stripe.com/docs/js/payment_methods/create_payment_method
you will get a PaymentMethod object https://stripe.com/docs/api/payment_methods/object that represents the card information. What matters there is the id of that object, it will look like this: pm_12345678
After that, send that id to your server. There use this Attach PaymentMethod API https://stripe.com/docs/api/payment_methods/attach to attach that PaymentMethod to an existing Customer object.
If you don't have one, create one first: https://stripe.com/docs/api/customers/create
After that you now have a Customer cus_123 and a PaymentMethod pm_123 that represnts that card information and you can do what you want with it
Okay, now this is starting to make sense!
I'm sure it does. You will regret this approach but I tried, and my team tried earlier. You can figure it out in the future once you start being stuck
I already figured out how to create a customer and list cards (ironically enough hah)
So right now the only thing that isn't clear (and thank you for the clarifications)...
I'm not sure how to word this, but using the latest JavaScript API how do I break out of the monolithic iframe? I can't do cookie-cutter styling for my clients.
you don't
We control this, you have limited styling possibilities for it and that's it. No other choice unless you want to do PCI compliance yourself (which you don't)
https://stripe.com/docs/js/appendix/style are the styling options
Thank you for the clarifications and I apologize about the frustration. I'm not interested in egotism or anything like that. I changed the JavaScipt code and got the pm_id like you mentioned while keeping the separate iframe form fields as desired. Here is the JavaScript code:
function window_onload(event)
{
cardNumberElement.mount('#card-number-element');
cardExpiryElement.mount('#card-expiry-element');
cardCvcElement.mount('#card-cvc-element');
cardNumberElement.on('change', function(event) {setOutcome(event);});
document.querySelector('form').addEventListener('submit', function(e)
{
e.preventDefault();
var options = {address_zip: document.getElementById('postal-code').value};
console.log('e', e);
console.log('cardNumberElement', cardNumberElement);
stripe
.createPaymentMethod({
type: 'card',
card: cardNumberElement,
billing_details: {
name: 'Jenny Rosen',
},
})
.then(function(result) {
// Handle result.error or result.paymentMethod
console.log('result',result);
});
});
}
document.addEventListener('DOMContentLoaded', function (event) {window_onload(event);},false);
👋 taking over here
I'm going to create the test PHP file for Attach a PaymentMethod to a Customer. I wish the documentation was a bit more clear from the start.
Okay, not a problem and I appreciate the patience, I've been on both sides of these kinds of conversations.
Good luck and LMK if you have more questions!
I'll note the (hopefully successful) result here in a few minutes. I would be very happy to provide the absolute minimal JavaScript/PHP code used to accomplish what I'm doing so you guys have a minimal working example for other 100% hands on programmers.
Question...
In regards to: "message": "No such PaymentMethod: 'pm_1Nap7s2eZvKYlo2CRphEgW3H';
That was in PHP after attempting to attach the customer to the card.
So I suppose my intuition leads me to this question:
After the paymentMethod object is created with the paymentMethod.id does it exist on Stripe's servers and I can send it to my server to attach or do I have to do a second action in JavaScript to "validate" that paymentMethod.id?
No you don't need to validate it. That is a different issue. Maybe you are using secret key on your server on a different Stripe account than whose the Publishable key belongs to
ie. you use secret key on account acct_A, but your Publishable key is on acct_B
I have the client/server (or public / secret) keys defined very well in my documentation.
I wish they would call them client/server keys.
There is just one account (for me using Stripe). The account has a test mode and live mode.
Okie, go to https://dashboard.stripe.com/test/logs and find the errored "No such PaymentMethod" request
LMK if you see it
Yes.
I basically have a 2KB PHP/cURL file that I copy/paste and then modify the $method, etc. All the variables are defined at the top. So that way I don't have to figure stuff out a second time.
Oh, I might have two list files confused...ha, checking...
Validated, I have the correct customer ID and the corret paymentMethod.id (from the client form):
$post_fields = 'customer='.urlencode('cus_ONCfFhBUjc2Jka');
$url = 'https://api.stripe.com/v1/payment_methods/pm_1Nap7s2eZvKYlo2CRphEgW3H/attach';
It's a bit odd, the way this setup works isn't attaching a card to a customer, it's attaching a customer to a card.
Oh, is there a CREATE method (on the server) that I need to do FIRST and THEN attach that method this way?
No
It should work, if you are using a secret key on the same Stripe Account
What is your account id? acct_xxx
Got it! Thank you, it's acct_1Aji0zCbr9UflH1h
Here is the full error, if that helps?
{
"error": {
"code": "resource_missing",
"doc_url": "https://stripe.com/docs/error-codes/resource-missing",
"message": "No such PaymentMethod: 'pm_1Nap7s2eZvKYlo2CRphEgW3H'; 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 https://stripe.com/docs/connect/authentication",
"param": "payment_method",
"request_log_url": "https://dashboard.stripe.com/test/logs/req_iBOduQQ73unccc?t=1691024305",
"type": "invalid_request_error"
}
}
Okie so it's a different account
This is acct_1032D82eZvKYlo2C Your javascript was using a Publishable Key from acct_1032D82eZvKYlo2C
Damn, thank you, looking to fix and I should be able to retest this quickly...
wait...
I think the problem is here (now fixed, I think, and will generate a new paymentMethod.id to test the server attach feature with):
var stripe = Stripe('pk_test_MkP3RBSXldJELDE9z6OngRHi');//pk_test_6pRNASCoBOKtIshFeQd4XMUh
SUCCESS! Thank you! Now the last thing I need to do is charge that saved payment method that I just attached.
Koop mentioned that the charge isn't done by my server via the API though via JavaScript?