#boundaryboys-cardelement-cvcpostalcheck
1 messages · Page 1 of 1 (latest)
we are able to create and add payment with correct number but wrong cvv and zip code
we dont perform payment now but details are taken for future purpose
Quoting for context
hi
CVC and zipcode are only validated when a card is authenticated by the issuing bank
You can save the card using a Setup Intent and we will perform the authentication
yes i did that too
here is what we did
create customer > add payment > CreateSetupIntent
can i share our code here?
You should be able to explain in clear, discreet steps what you are doing and where the problem is
Here is what we are doing
- Customer enters card details on frontend stripe widget and returns a paymentinfotoken
- fronend send the token to backend
- backend creates a paymentmethodcreateoptions
adds the payment token to it - we call customerService,CreateAsync(customerOPtions)
- we then create strypepaymentservice.createSetupIntent(customerID)
we see no error message when we make these api calls if cvv or zip entered is wrong
are we missing anything?
- What stripe widet are you using?
- Are you using Setup Intents or creating Payment Methods directly?
'const CreditCardForm = (props: CreditCardFormProps) => (
<Elements stripe={stripePromise}>
<UnwrappedCreditCardForm {...props} />
</Elements>
);'
is there a specific widget we need to sue
use?
~What is this <UnwrappedCreditCardForm {...props} />?~
NVM, it's the Card Element
And you are just using this form to collect the card details, correct?
yes
return (
<div>
<p className=" pb-2">Credit card validation - There is no charge for the tour.</p>
<form onSubmit={handleSubmit} className="credit-card-input">
<FormInput
inputProps={{
id: 'card-holder-name',
name: 'cardHolderName',
type: 'text',
placeholder: 'Jane Doe',
value: cardHolderName,
required: true
}}
labelProps={{
labelText: 'Credit Card Holder Name',
invalidText: 'Please enter the card holder name'
}}
onChange={(_name, value) => setCardHolderName(value.toString())}
/>
<div className="form-group">
<label className="font-weight-bold">Credit Card Details</label>
<CardElement />
</div>
<div className="navigation-buttons">
<Button type="submit" disabled={!stripe} text="Next" />
</div>
</form>
</div>
);.
Okay so that's part of the problem. We (Stripe) cannot check the CVC and Zip code. Only the bank that issued the card knows if that is correct
we use CardElement
Yes I know. What I mentioned above is still the case though
ok
how can i fix this?
we dont collect any payment at the time of taking these details, we just keep it for future transactions
We recommend using Setup Intents: https://stripe.com/docs/payments/save-and-reuse
This approach will save the Payment Method to the Customer and authorize it with the issuing bank
so our front end need to use a diff widget?
You can still use the Card Element
The Payment Element is the recommended approach so that is what our docs show but both support saving payment methods for future use: https://stripe.com/docs/payments/payment-card-element-comparison
so what is that we are doing wrong here?
we use this version of stripe
"@stripe/react-stripe-js": "^1.1.2",
"@stripe/stripe-js": "^1.11.0",
it says PaymentElement is not available
You are not using setup intents. This means the details the card details are not authorized with the bank until you attempt a payment
ok
i updated my strips to latest version to use PaymentElement and now i am getting this error
/@stripe/stripe-js/types/index"' has no exported member 'StripePayButtonElementOptions'.
Okay so that looks to be a breaking change between the versions. It looks like that isn't something we export in our current version of Stripe.js
how do i fix this?
Well you cannot export that as an option for starters. Can I ask you what you are trying to do here?
i am not exporting any thing with that name
u said, we need to use PaymentElement instead of card element so updated my react code to get latest stripe module
and did this
/>
<div className="form-group">
<label className="font-weight-bold">Credit Card Details</label>
<PaymentElement />
</div>
No I never said you need to use Payment Element. I explicitly said Card Element will work
But you need to create Setup Intents on your server and use them with your Card Element
i think that is what we did already
That is not the flow you described. Can you share a payment method ID or setup intent ID where the cvc problem occurred?
This is our CreateCustomer method on server side
public async Task<(string CustomerId, string errorMessage)> CreateCustomer(string paymentInfoToken, string email, string name)
{
try
{
// Create PaymentMethod from the token
var paymentMethodOptions = new PaymentMethodCreateOptions
{
Type = "card",
Card = new PaymentMethodCardOptions
{
Token = paymentInfoToken
}
};
var paymentMethodService = new PaymentMethodService();
var paymentMethod = await paymentMethodService.CreateAsync(paymentMethodOptions);
// Create Customer with the PaymentMethod
var customerOptions = new CustomerCreateOptions
{
PaymentMethod = paymentMethod.Id, // Use the PaymentMethod ID here
Email = email,
Description = name,
InvoiceSettings = new CustomerInvoiceSettingsOptions
{
DefaultPaymentMethod = paymentMethod.Id
}
};
var customerService = new CustomerService();
var customer = await customerService.CreateAsync(customerOptions);
return (customer.Id, null);
}
catch (StripeException ex)
{
return (null, ex.Message);
}
catch (Exception ex)
{
return (null, ex.Message);
}
}
I don't see anything pertaining to a Setup Intent in there.
This is our payment intent method on our server side
// https://stripe.com/docs/payments/save-and-reuse is the code to follow
public async Task<(string ClientSecret, string errorMessage)> CreateSetupIntent(string customerId)
{
// Create Setup Intent
var options = new SetupIntentCreateOptions
{
Customer = customerId,
PaymentMethodTypes = new List<string> { "card" }, // specify the supported payment method type
Usage = "off_session", // indicate that this Setup Intent will be used for off-session payments
};
var setupIntentService = new SetupIntentService();
try
{
var setupIntent = await setupIntentService.CreateAsync(options);
return (setupIntent.ClientSecret, null);
}
catch (Exception ex)
{
return (null, ex.Message);
}
}
we call createcustomer and then call createsetupintent
Okay and when you return the client_secret, you use that with your Card Element to create the Payment Method?
yes
we use cardElement on the front end and it returns a token
that we send to CreateCustomer on
Do you have an example PaymentMethod ID where you had a zipcode or cvc error that I could review?
our controller calls createcustomer and then calls CreateCustomer intent service methods
Yeah, at this point I think it'll help if I can see an example Payment Method.
pm_1OhzUSEVZvhMCAQUYoIQmy17
Thanks! Taking a look
I don't know what that is a screenshot of. However, this PM was created by a direct call to the Payment Methods API https://dashboard.stripe.com/logs/req_nFsckuPIz643qJ and then attached to the Customer using the Customers API https://dashboard.stripe.com/logs/req_t52KZVHPF7KFLa
I'm looking for a related setup intent but I can't see it anywhere
But this flow is kind of the opposite of our recommended approach to saving cards for future payments: https://stripe.com/docs/payments/save-and-reuse
From what I can see this card is saved and attached to the customer all without any authorization from the issuing bank
That is why we see the following properties for this Payment Method
checks: {
address_line1_check: null,
address_postal_code_check: "unchecked",
cvc_check: "unchecked"
},
boundaryboys-cardelement-cvcpostalcheck
public async Task<(string CustomerId, string ClientSecret, string errorMessage)> CreateCustomerAndSetupIntent(string paymentInfoToken, string email, string name)
{
try
{
var paymentMethodOptions = new PaymentMethodCreateOptions
{
Type = "card",
Card = new PaymentMethodCardOptions
{
Token = paymentInfoToken
}
};
var paymentMethodService = new PaymentMethodService();
var paymentMethod = await paymentMethodService.CreateAsync(paymentMethodOptions);
var customerOptions = new CustomerCreateOptions
{
PaymentMethod = paymentMethod.Id, // Use the PaymentMethod ID here
Email = email,
Description = name,
InvoiceSettings = new CustomerInvoiceSettingsOptions
{
DefaultPaymentMethod = paymentMethod.Id
}
};
var customerService = new CustomerService();
var customer = await customerService.CreateAsync(customerOptions);
var setupIntentOptions = new SetupIntentCreateOptions
{
Customer = customer.Id,
PaymentMethodTypes = new List<string> { "card" },
Usage = "off_session",
};
var setupIntentService = new SetupIntentService();
var setupIntent = await setupIntentService.CreateAsync(setupIntentOptions);
return (customer.Id, setupIntent.ClientSecret, null);
}
catch (StripeException ex)
{
return (null, null, ex.Message);
}
catch (Exception ex)
{
return (null, null, ex.Message);
}
}
is that flow wrong
create var paymentMethod = await paymentMethodService.CreateAsync(paymentMethodOptions);
create var customer = await customerService.CreateAsync(customerOptions);
create var setupIntent = await setupIntentService.CreateAsync(setupIntentOptions);
Yes,
At least, it will not perform the authorization and check the postal code or CVC, which is I think what you are asking about
The steps in this doc: https://stripe.com/docs/payments/save-and-reuse are
- create Customer <- server
- create Setup Intent <- server
- confirm Setup Intent w/ Element (CardElement or PaymentElement) <- client (creates and attaches Payment Method)
That last step performs an auth request with the issuing bank and triggers the postal code and CVC checks.
ok
confirm Setup Intent w/ Element (CardElement or PaymentElement) <- client (creates and attaches Payment Method)
how do we confirm this
i meant i got the part to create customer and setupintent
but how do we force client to do
confirm Setup Intent w/ Element (CardElement or PaymentElement) <- client (creates and attaches Payment Method)
You would use this method: https://stripe.com/docs/js/setup_intents/payment_method
Which uses a Card Element and confirms the Setup Intent using the card details the customer provides
ok, looks like we are missing that step "confirmSetup" on the client side to perform validations