#boundaryboys-cardelement-cvcpostalcheck

1 messages · Page 1 of 1 (latest)

knotty meteorBOT
brittle shadow
#

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

tardy smelt
#

hi

brittle shadow
#

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

tardy smelt
#

yes i did that too

#

here is what we did
create customer > add payment > CreateSetupIntent

#

can i share our code here?

brittle shadow
#

You should be able to explain in clear, discreet steps what you are doing and where the problem is

tardy smelt
#

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?

brittle shadow
#
  1. What stripe widet are you using?
  2. Are you using Setup Intents or creating Payment Methods directly?
tardy smelt
#

'const CreditCardForm = (props: CreditCardFormProps) => (
<Elements stripe={stripePromise}>
<UnwrappedCreditCardForm {...props} />
</Elements>
);'

#

is there a specific widget we need to sue

#

use?

brittle shadow
#

~What is this <UnwrappedCreditCardForm {...props} />?~
NVM, it's the Card Element

#

And you are just using this form to collect the card details, correct?

tardy smelt
#

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>
);.
brittle shadow
#

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

tardy smelt
#

we use CardElement

brittle shadow
#

Yes I know. What I mentioned above is still the case though

tardy smelt
#

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

brittle shadow
#

This approach will save the Payment Method to the Customer and authorize it with the issuing bank

tardy smelt
#

so our front end need to use a diff widget?

brittle shadow
#

You can still use the Card Element

tardy smelt
#

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

brittle shadow
#

You are not using setup intents. This means the details the card details are not authorized with the bank until you attempt a payment

tardy smelt
#

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'.

brittle shadow
#

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

tardy smelt
#

how do i fix this?

brittle shadow
#

Well you cannot export that as an option for starters. Can I ask you what you are trying to do here?

tardy smelt
#

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>

brittle shadow
#

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

tardy smelt
#

i think that is what we did already

brittle shadow
#

That is not the flow you described. Can you share a payment method ID or setup intent ID where the cvc problem occurred?

tardy smelt
#

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);
        }
    }
brittle shadow
#

I don't see anything pertaining to a Setup Intent in there.

tardy smelt
#

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

brittle shadow
#

Okay and when you return the client_secret, you use that with your Card Element to create the Payment Method?

tardy smelt
#

yes

#

we use cardElement on the front end and it returns a token

#

that we send to CreateCustomer on

brittle shadow
#

Do you have an example PaymentMethod ID where you had a zipcode or cvc error that I could review?

tardy smelt
#

our controller calls createcustomer and then calls CreateCustomer intent service methods

brittle shadow
#

Yeah, at this point I think it'll help if I can see an example Payment Method.

tardy smelt
#

pm_1OhzUSEVZvhMCAQUYoIQmy17

brittle shadow
#

Thanks! Taking a look

tardy smelt
brittle shadow
#

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"
    },
knotty meteorBOT
#

boundaryboys-cardelement-cvcpostalcheck

tardy smelt
#

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);

brittle shadow
#

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.

tardy smelt
#

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)

brittle shadow
#

Which uses a Card Element and confirms the Setup Intent using the card details the customer provides

tardy smelt
#

ok, looks like we are missing that step "confirmSetup" on the client side to perform validations