stripe / stripe-react-native

React Native library for Stripe.
https://stripe.dev/stripe-react-native
MIT License
1.27k stars 265 forks source link

Error in createPaymentMethod: You must provide card details #239

Closed peraltafederico closed 3 years ago

peraltafederico commented 3 years ago

Describe the bug After setup StripeProvider and render correctly CardField I keep receiving error: "You must provide card details" when calling await createPaymentMethod({type: 'Card'}).

Expected behavior createPaymentMethod should read the card details from CardField. If that's not the supposed behavior please let me know. I'm following this guide https://stripe.com/docs/payments/accept-a-payment-synchronously

Smartphone (please complete the following information):

Additional context I could make createPaymentMethod work by tokenizing the card with another library and passing it as a parameter like in the below example. I could get the token by hardcoding the card details because CardField doesn't provide the full card properties (I know this is excepted):

const pm = await createPaymentMethod({ type: "Card", token: token.id });
thorsten-stripe commented 3 years ago

Please provide a console.log of the cardDetails from the CardField component at the time of calling createPaymentMethod. The cardDetails have a complete param which indicates whether the CardField is considered complete. Do note that on iOS the CardField is only considered complete when a postal code has been provided. If you do not wish to collect the postal code you need to set the postalCodeEnabled={false} param on the CardField component.

peraltafederico commented 3 years ago

Thanks @thorsten-stripe for the quick reply. This is the console log of the cardDetails when calling createPaymentMethod

{
    "last4": "4242",
    "expiryMonth": "11",
    "expiryYear": "26",
    "complete": true,
    "brand": "Visa"
}

I leave you below a code snippet, I think that may help:

const StripeForm = () => {
  const [card, setCard] = useState(null);
  const { createPaymentMethod } = useStripe();

  const handlePress = async () => {
    console.log(card);

    const pm = await createPaymentMethod({ type: "Card" });

    console.log(pm);
  };

  return (
    <View>
      <CardField
        postalCodeEnabled={false}
        placeholder={{
          number: "4242 4242 4242 4242",
        }}
        cardStyle={{
          backgroundColor: "#FFFFFF",
          textColor: "#000000",
        }}
        style={{
          width: "100%",
          height: 50,
          marginVertical: 30,
        }}
        onCardChange={cardDetails => {
          setCard(cardDetails);
        }}
      />
      <Button onPressHandler={handlePress}>Pay</Button>
    </View>
  );
};
totodot commented 3 years ago

I have the same problem, in documentation, you save card details in state but you never use that. I guess, that it should be provided to confirmPayment or createPaymentMethod functions.

arekkubaczkowski commented 3 years ago

@totodot you are wrong, we passing card details to the payment under the hood, so processing the payment should be on the same screen as CardField component is mounted.

Is it occurs on android as well?

totodot commented 3 years ago

Ok, thanks. Did you include that in the documentation? For me it's a little tricky, and I don't know what happens in code.

For android i need to update gradle to 6.5 and com.android.tools.build:gradle to 4.1.2. It's strange for android it works, after that i run app on IOS second time and now it works. I don't know why.

that my code:

const PayScreen: React.FC = () => {
  const { createPaymentMethod } = useStripe();
  const [card, setCard] = useState(null);

  const submit = async () => {
    const billingDetails = {
      email: "jenny.rosen@example.com",
    };

    const paymentMethod = await createPaymentMethod({
      type: "Card",
      billingDetails,
    });
    console.log({ paymentMethod, card });
  };
  return (
    <View style={styles.wrapper}>
      <CardField
        postalCodeEnabled
        placeholder={{
          number: "4242 4242 4242 4242",
        }}
        cardStyle={{
          backgroundColor: "#FFFFFF",
          textColor: "#000000",
        }}
        style={{
          width: "100%",
          height: 50,
          marginVertical: 30,
        }}
        onCardChange={setCard}
      />
      <Button onPress={submit} text="pay" />
    </View>
  );
};

export default PayScreen;
totodot commented 3 years ago

@arekkubaczkowski Do you consider adding createPaymentMethodToken function? It is necessary if you want to implement your own card input UI.

arekkubaczkowski commented 3 years ago

Do you consider adding createPaymentMethodToken function? It is necessary if you want to implement your own card input UI.

actually it's available already, you can use it by passing token to the createPaymentMethod

const { paymentMethod, error } = await createPaymentMethod({
      type: 'Card',
      token: token
    });
arekkubaczkowski commented 3 years ago

It's strange for android it works, after that i run app on IOS second time and now it works. I don't know why.

please let me know when it occurs again, I will try to help with some debugging

thorsten-stripe commented 3 years ago

It is necessary if you want to implement your own card input UI.

Note that in most cases you should not use your own card input UI due to PCI compliance considerations. See https://github.com/stripe/stripe-react-native/issues/178#issuecomment-831651413

trex-quo commented 3 years ago

Do you consider adding createPaymentMethodToken function? It is necessary if you want to implement your own card input UI.

actually it's available already, you can use it by passing token to the createPaymentMethod

const { paymentMethod, error } = await createPaymentMethod({
      type: 'Card',
      token: token
    });

Yes but there is no easy way to create the token with the current API. In tipsi-stripe they allow you to create a token with the card

arekkubaczkowski commented 3 years ago

It will be available in the next release https://github.com/stripe/stripe-react-native/pull/221

thorsten-stripe commented 3 years ago

@peraltafederico you should not use any third party library to handle card detail collection nor should you send them directly to the Stripe API! To create tokens you will be able to use the createToken method with the <CardField> component once version 0.1.2 is released.

peraltafederico commented 3 years ago

@peraltafederico you should not use any third party library to handle card detail collection nor should you send them directly to the Stripe API! To create tokens you will be able to use the createToken method with the <CardField> component once version 0.1.2 is released.

@thorsten-stripe Ok I see what you mean and I absolutely agree with you. But.. how can I integrate a React Native App with Stripe if I need that feature now and it is currently under development? 🤔

thorsten-stripe commented 3 years ago

@peraltafederico ideally you should migrate to use createPaymentMethod instead. Any reason why you need a legacy token?

peraltafederico commented 3 years ago

@thorsten-stripe My bad, forget about tokens.

Coming back to createPaymentMethod issue I want to make it work but as I said at the very beginning unfortunately I couldn't yet. Here is the console.log you asked for plus a code snippet of the implementation: https://github.com/stripe/stripe-react-native/issues/239#issuecomment-844222912. I'll try to implement it in Android and see what happens there but in the meantime any ideas of why I'm getting the You must provide card details error?

thorsten-stripe commented 3 years ago

Your code snippet above works fine for me. Can you try replacing setCard(cardDetails); with console.log(cardDetails); and post the last log before hitting submit? For me it is:

 LOG  {"brand": "Visa", "complete": true, "expiryMonth": "12", "expiryYear": "22", "last4": "4242"}
 LOG  {"error": undefined, "paymentMethod": {"AuBecsDebit": {"bsbNumber": null, "fingerprint": null, "last4": null}, "BacsDebit": {"fingerprint": null, "last4": null, "sortCode": null}, "Card": {"brand": "Visa", "country": "US", "expMonth": 12, "expYear": 2022, "fingerprint": null, "funding": "credit", "last4": "4242"}, "Fpx": {"bank": ""}, "Ideal": {"bankIdentifierCode": "", "bankName": ""}, "SepaDebit": {"bankCode": null, "country": null, "fingerprint": null, "last4": null}, "Sofort": {"country": null}, "billingDetails": {"address": [Object], "email": null, "name": null, "phone": null}, "customerId": null, "id": "pm_1ItPjVG7gfqYEkPOwqLXhEVE", "livemode": false, "type": "Card"}}
peraltafederico commented 3 years ago

@thorsten-stripe Thanks for your time! I'll share you the log ASAP.

anija commented 3 years ago

I'm experiencing this problem also. I'm migrating from tipsi-stripe, but i can't obtain the paymentMethodId from createPaymentMethod method. I'm trying createPaymentMethod from the same screen where the CardField component is rendered, and if i log cardDetails i see: Object { last4: "4242", expiryMonth: 4, expiryYear: 24, complete: true, brand: "Visa" } But the method gives the error: { code: "Failed", message: "Card details not complete" }

This is the code snippet: const handleAdd = async () => { console.log(card); const billingDetails = { email: 'jenny.rosen@example.com', }; const pm = await createPaymentMethod({ type: 'Card', ...card, billingDetails }); console.log(pm); };

thorsten-stripe commented 3 years ago

@anija what are the values of ...card,? When using the CardField no card params need to be provided, we extract the card information securely under the hood: https://github.com/stripe/stripe-react-native/blob/master/example/src/screens/NoWebhookPaymentScreen.tsx#L67-L71

// 2. Create payment method    
const { paymentMethod, error } = await createPaymentMethod({ type: 'Card', billingDetails });
anija commented 3 years ago

Card parameters are the ones logged before: { last4: "4242", expiryMonth: 4, expiryYear: 24, complete: true, brand: "Visa" } But the result is the same, with or without card, with or without billingDetails.

thorsten-stripe commented 3 years ago

@anija can you please provide your full components code where CardField is used?

m-salamon commented 3 years ago

Describe the bug After setup StripeProvider and render correctly CardField I keep receiving error: "You must provide card details" when calling await createPaymentMethod({type: 'Card'}).

Expected behavior createPaymentMethod should read the card details from CardField. If that's not the supposed behavior please let me know. I'm following this guide https://stripe.com/docs/payments/accept-a-payment-synchronously

Smartphone (please complete the following information):

  • Device: Xcode - iPhone11

Additional context I could make createPaymentMethod work by tokenizing the card with another library and passing it as a parameter like in the below example. I could get the token by hardcoding the card details because CardField doesn't provide the full card properties (I know this is excepted):

const pm = await createPaymentMethod({ type: "Card", token: token.id });

I had the same issue using Expo SDK 41, I needed to upgrade to Expo SDK 42 (latest SDK) it all works now.

babyrusa commented 3 years ago

I'm experiencing this same issue on Android. Gradle 4.0.0, react-native 0.64.2

  <CardField
              postalCodeEnabled={true}
              placeholder={{
                number: '4242 4242 4242 4242',
              }}
              cardStyle={{
                backgroundColor: '#FFFFFF',
                textColor: '#000000',
              }}
              style={{
                width: '100%',
                height: 50,
                marginVertical: 30,
              }}
              onCardChange={(cardDetails) => {
                console.log('cardDetails', cardDetails);
                if (cardDetails.complete && cardDetails.postalCode) {
                  console.log('complete');
                  setCardValid(true);
                } else {
                  setCardValid(false);
                }
              }}
              onFocus={(focusedField) => {
                console.log('focusField', focusedField);
              }}
            />
"brand": "Visa", "complete": true, "expiryMonth": 4, 
"expiryYear": 24, "last4": "4242", "postalCode": "mypostal"}
m-salamon commented 3 years ago

Gradle 4.0.0,

You are using an old Gradle Version I would recommend updating to a newer version preferably released after May 2021 and see what happens.

babyrusa commented 3 years ago

@m-salamon I have been trying since yesterday to upgrade Gradle and Android studio but there was a few issues with compilations which have not been resolved However I want t come back and comment that I WAS able to send a few one-time transaction just fine followed by the stripe-react-native tutorial. However when I started adding like receipt-email/custom email this issue started to happen. I commented out the new changes but I could no longer made any payments :(

maxgenest commented 3 years ago

I have the same issue here only on android. The issue happens only with 3D secure cards (such as 4000 0000 000 3220 card).

here is my CardField :

          <CardField
            postalCodeEnabled={false}
            placeholder={{
              number: '4242 4242 4242 4242',
            }}
            style={styles.cardFieldStyle}
            onCardChange={(details) => console.log('card details', details)}
         />

my handleSubmitCard :

    const billingDetails = {
      email: 'email@test.com'
    };

    const {paymentMethod, error} = await createPaymentMethod({
      type: 'Card',
      billingDetails,
    });

and the cardDetails juste before the createPayementMethod :

cardDetails1 {last4: "3220", expiryMonth: 11, expiryYear: 22, complete: true, brand: "Visa"}

Again, I have no issue on iOs or with the 4242 4242 4242 4242 card.

Android Gradle Plugin version : 4.2.0 Gradle Version : 6.7.1

markl-vesper commented 3 years ago

I've also just started process from tipsi to react-native-stripe. Huge amount of work to get all the RN packages updated long with Android build issues as result.

Gradle 6.9 Gradle Plugin 4.1.2

"@stripe/stripe-js": "1.17.0", "@stripe/stripe-react-native": "0.2.0"

When calling

                    const {paymentMethodId, error} = await createPaymentMethod({
                        type: 'Card'
                    });

console log reports

createPaymentMethod response: {"stripeErrorCode":null,"message":"Card details not complete","declineCode":null,"type":null,"localizedMessage":"Card details not complete","code":"Failed"}

stripe imported via

import { CardField, useStripe, confirmPayment, createPaymentMethod } from "@stripe/stripe-react-native";

Card defined as

                    <View style={Styles.inputContainerStyle}>
                        <CardField
                            postalCodeEnabled={false}
                            cardStyle={{
                                backgroundColor: '#FFFFFF',
                                textColor: '#000000',
                            }}
                            style={{
                                width: '100%',
                                height: 50,
                                marginVertical: 30,
                            }}
                            onCardChange={(cardDetails) => {
                                this.handleStripeParamsChange(cardDetails.complete, cardDetails)
                            }}
                        />
                    </View>
LiyaYe commented 3 years ago

Card parameters are the ones logged before: { last4: "4242", expiryMonth: 4, expiryYear: 24, complete: true, brand: "Visa" } But the result is the same, with or without card, with or without billingDetails.

Hi @anija I am having the same issue where the cardField is not providing enough details to createPaymentMethod, the gateway is returning a missing param error for card[number]. Any chance you could share how you solved the issue, if at all?

Thanks!

anija commented 3 years ago

Card parameters are the ones logged before: { last4: "4242", expiryMonth: 4, expiryYear: 24, complete: true, brand: "Visa" } But the result is the same, with or without card, with or without billingDetails.

Hi @anija I am having the same issue where the cardField is not providing enough details to createPaymentMethod, the gateway is returning a missing param error for card[number]. Any chance you could share how you solved the issue, if at all?

Thanks!

Upgrading the library to the latest version (0.2.2) solved my problem: the console.log is still incomplete, but if i send the details to createPaymentMethod, it works now.

arekkubaczkowski commented 3 years ago

@anija what you mean that console.log is incomplete?

anija commented 3 years ago

That is the same logged before, it doesn't contain the full card number, but this is ok since i use createPaymentMethod

Il giorno lun 4 ott 2021 alle ore 12:34 arekkubaczkowski < @.***> ha scritto:

@anija https://github.com/anija what you mean that console.log is incomplete?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/stripe/stripe-react-native/issues/239#issuecomment-933355535, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPYFKRL2H2ZBXM3QIN3GITUFF7KFANCNFSM45E4VUDQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

--

Angelica. http://www.anija.it www.anija.it http://www.anija.it

arekkubaczkowski commented 3 years ago

@anija there shouldn't be full card number visible as it's a sensitive data, that's why we handover card details under the hood and you don't need to do it on your own. It's better explained here: https://github.com/stripe/stripe-react-native/blob/master/docs/tipsi-stripe-migration-guide.md#paymentintent-api

anija commented 3 years ago

I think there's a misunderstanding... i don't need nothing :) i was just answering to LiyaYe on how i solved the problem i had (that's why i quoted her post).

arekkubaczkowski commented 3 years ago

@anija yeah I got it but I just wanted to make you aware that this what you mentioned works correctly to avoid any confusions in the future :)

anija commented 3 years ago

While on iOS the CardField component returns enough information to create the payment method using createPaymentMethod, on Android createPaymentMethod returns an error:

  error: {
    code: "Failed",
    declineCode: null,
    localizedMessage: "Card details not complete",
    message: "Card details not complete",
    stripeErrorCode: null,
    type: null
  }
}

I'm using the same test card i'm using on iOS (that works). I've postal code disabled. This is the log of the values return by the CardField component:

​complete: true
​expiryMonth: 4
​expiryYear: 24
​last4: "4242"
arekkubaczkowski commented 3 years ago

@anija can you make sure that after upgrading library version there are not any caches?

anija commented 3 years ago

@anija can you make sure that after upgrading library version there are not any caches?

Yes, i'm sure. Never built the app for android with this library, we were using tipsi-stripe before.

arekkubaczkowski commented 3 years ago

@anija have you removed tipsi-stripe from your project yet? There might appears mismatches of stripe-android versions

anija commented 3 years ago

@anija have you removed tipsi-stripe from your project yet? There might appears mismatches of stripe-android versions

yes, I confirm is removed. From build reports the stripe-android version seems to be 17.1.10.

arekkubaczkowski commented 3 years ago

@anija can you please create an issue with all needed details, like environment, all the related library versions, content of build.gradle and app/build.gradle, also code snippet of your payment screen would be useful.

anija commented 3 years ago

@anija can you please create an issue with all needed details, like environment, all the related library versions, content of build.gradle and app/build.gradle, also code snippet of your payment screen would be useful.

https://github.com/stripe/stripe-react-native/issues/624

aliMurtaja commented 2 years ago

I have used payment-sheet in react native, and sheet is opening, my issue is that how does i will get the token from sheet so that i can use that token to save card.

my code:

const { error, paymentOption } = await presentPaymentSheet();

joix97b commented 2 years ago

I needed to use paymentMethodType instead of type

const pm = await createPaymentMethod({paymentMethodType: 'Card'})

mostafijur-rahman299 commented 2 years ago

This worked for me :)

pck555 commented 1 year ago

It's working fine on iOS, but on android it returns error: Card details not complete although I input the all fields as same as iOS fields.