stripe-react-native: Error in createPaymentMethod: You must provide card details

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

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 2
  • Comments: 45 (7 by maintainers)

Most upvoted comments

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;

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

I needed to use paymentMethodType instead of type

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

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

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"

@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

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.

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

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