Closed gabriellend closed 2 years ago
createToken actually takes a couple different input options. But for cards, it relies on the CardField or CardForm components and pulls card data directly from there. This way, you aren't handling card data yourself and thus saves you a lot of time and effort around PCI compliance :) so I highly recommend going that route
Basically- render CardField and when the user fills that out, then you can create the token with createToken
. See - https://github.com/stripe/stripe-react-native/blob/master/example/src/screens/CreateTokenScreen.tsx
@charliecruzan-stripe Thanks so much for the help! Does that mean I have to change my UI? I already have a component that takes in the card info, do I need to replace it with a CardField/CardForm component? And how does createToken know about CardField/CardForm? Is that just baked in?
Totally baked in, you don't need to worry about it :)
And yes- you have to change your UI to incorporate CardField. Sorry for that, but it's definitely going to end up saving you lots of time in the long run since it makes your PCI approval process much easier: https://stripe.com/guides/pci-compliance. (Basically your requirements are far fewer)
@charliecruzan-stripe I truly thank you for your time!
@charliecruzan-stripe I'm not getting the token. I don't know what i'm doing wrong here. below is my code. I'm trying to integrate stripe in my react-native app.
let userDetails;
function CardSection() {
return (
<>
<CardField
postalCodeEnabled={true}
placeholders={{
number: '4242 4242 4242 4242',
}}
cardStyle={{
backgroundColor: '#FFFFFF',
textColor: '#000000',
}}
style={{
width: '100%',
height: 50,
marginVertical: 30,
}}
onCardChange={cardDetails => {
userDetails = cardDetails;
// console.log('mycardDetails=', cardDetails);
}}
onFocus={focusedField => {
// console.log('focusField', focusedField);
}}
/>
<Button
title={'Checkout'}
onPress={() => {
stripePaymentFunction();
}}
/>
</>
);
}
below function will run on press button
function stripePaymentFunction() {
createToken({
type: 'Card',
})
.then(token => {
console.log('token= ', token);
})
.catch(error => {
console.log('error= ', error);
});
}
return (
<StripeProvider
publishableKey={'publishable_key'}>
<CardSection />
</StripeProvider>
);
I'm getting below error when i press checkout button:
{"error": {"code": "Failed", "declineCode": null, "localizedMessage": "Card details not complete", "message": "Card details not complete", "stripeErrorCode": null, "type": null}}
Card details not complete
This means CardField isn't completely filled out. You should disable your Checkout
button until the onCardChange
callback fires with cardDetails.complete === true
Hello!
I'm migrating over from tipsi-stripe so I think I'm mostly integrated with Stripe already but I cannot for the life of me figure out how to create a token in the way I was doing it before. I would appreciate anyone pointing me in the right direction. I scoured the docs, examples, and issues for the last two days but got very lost/confused and think I might've ended up on the wrong site? I tried running the example project to investigate further too but couldn't get it to work.
In the app I'm working on, we allow users to add cards to use later (it's a food delivery app so they shouldn't have to add their card every time, only once). Before, I gathered the card info like this:
const params = { number: cardNumber, expMonth: Number(month), expYear: Number(year), cvc: security, };
and created a token (type object) like this:
const token = await stripe.createTokenWithCard(params);
I then sent the token to the backend where it talked to stripe which stored the card. The stripe-react-native function that seems to be analogous is
createToken
, which takes in an object wheretype
is the only required field, and returns a token object and an error. Then what happens? How doescreateToken
create a token that refers to a specific card with only the type (hypothetically) and not the number, cvc, etc? Is there another function that would let me take in my params and return an object with an id, or is this a much more complex problem?I'm not using expo if that is important. I truly appreciate anyone's help. I'm still learning so some things aren't intuitive to me yet.
currently i am facing same issue you faced. can you please help , how you solved this.
@shashigit107 I added the CardForm
component like this:
<CardForm
autofocus
onFormComplete={(cardDetails) => {
if (cardDetails.complete) {
this.setState({ formValid: true });
}
}}
placeholders={{ postalCode: 'Zip'/* Android only */ }}
cardStyle={styles.cardStyle}
style={styles.newCard}
/>
And then a button below that:
<Button
onPress={this.getStripeToken}
text="ADD CARD"
success={success}
loading={loading}
disabled={!formValid}
style={styles.addCardButton}
/>
I call createToken
in getStripeToken
like this:
getStripeToken = async () => {
const {
loading,
} = this.state;
const { STRIPE_KEY } = CONFIG || {};
if (loading) return;
this.setState({ loading: true });
try {
initStripe({
publishableKey: STRIPE_KEY,
});
const token = await createToken({ type: 'Card' });
if (typeof (token) === 'object' && typeof (token.token.id) === 'string' && token.token.id.length) {
await this.postCard(token.token.id);
return;
}
this.setState({ loading: false });
Alert.alert('Error', 'Unable to add card.', [{ text: 'OK', onPress: () => { } }]);
return;
} catch (e) {
Alert.alert(
'Error',
'Card is invalid.',
[{ text: 'OK', onPress: () => { this.setState({ loading: false }); } }],
);
}
}
CardForm
and createToken
are aware of each other and talk to each other under the hood so that's all you have to do! Hope that helps!
@gabriellend @charliecruzan-stripe
not working for me, tried both approached
I tried multiple options as mentioned
No issue found in my code
I tried by using StripeProvider
also tried by using initStripe method
I am consistently facing the following error:
{"error": {"code": "Failed", "declineCode": null, "localizedMessage": "Card details not complete", "message": "Card details not complete", "stripeErrorCode": null, "type": null}}
blocked
@charliecruzan-stripe @gabriellend
here is my code
import {Box, KeyboardAvoidingView, Stack, Text, useTheme, View} from 'native-base';
import {CardField, initStripe, StripeProvider, useStripe} from '@stripe/stripe-react-native';
import {Config} from 'react-native-config';
import React, {useContext, useEffect, useState} from 'react';
import LoadingScreen from 'components/LoadingScreen';
import {AuthContext} from 'context/authContext';
import GoToNext from 'screens/GoalCreating/components/GoToNext';
import {TOAST_TYPE, ToastContext} from 'context/toastContext';
import {CREATED_ROUTES} from 'screens/GoalCreating/constants';
import {useNavigation} from '@react-navigation/native';
import {
AmericanExpressIcon,
DinnerClubIcon,
DiscoverCardIcon,
MastercardIcon,
UnionPayIcon,
VisaCardIcon
} from 'assets/icons/cards';
import {Platform} from 'react-native';
const {STRIPE_PUBLISHABLE_KEY} = Config;
console.log('STRIPE_PUBLISHABLE_KEY', STRIPE_PUBLISHABLE_KEY);
const PaymentToken = () => {
const {createToken} = useStripe();
const {me} = useContext(AuthContext);
const {colors} = useTheme();
const {addToast} = useContext(ToastContext);
const {navigate} = useNavigation();
const [loading, setLoading] = useState(false);
const [loadingPay, setLoadingPay] = useState(false);
const [paymentMethodData, setPaymentMethodData] = useState();
const [cardData, setCardData] = useState();
const initializeStripe = async () => {
setLoading(true);
try {
await initStripe({
publishableKey: 'pk_test_U9omQHnm44eocSCqocC4JUOp00tnnig3IV'
});
console.log('stripe initialized');
} catch (e) {
console.log('error in init stripe', e);
} finally {
setLoading(false);
}
};
useEffect(() => {
initializeStripe();
}, []);
const handlePayPress = async () => {
setLoadingPay(true);
try {
if (!cardData.complete) {
console.log('card details not complete in creating stripe token', cardData);
addToast({type: TOAST_TYPE.ERROR, text: 'Please fill the card details'});
return;
}
await initializeStripe();
console.log('cardData', cardData);
const resToken = await createToken({
type: 'Card'
});
if (resToken.error) {
console.log('error in creating stripe token', resToken);
addToast({type: TOAST_TYPE.ERROR, text: resToken.error.message});
return;
}
addToast({type: TOAST_TYPE.SUCCESS, text: 'Card was added successfully'});
} catch (e) {
console.log('error in creating stripe token', e);
} finally {
setLoadingPay(false);
}
};
const fetchCardDetails = cardDetail => {
if (cardDetail?.complete) {
return setCardData(cardDetail);
}
// setCardData(null);
};
const behavior = Platform.OS === 'ios' ? 'padding' : 'height';
if (loading) return <LoadingScreen />;
return (
<View flex={1} px={4}>
<KeyboardAvoidingView
keyboardVerticalOffset={120}
behavior={behavior}
style={{
flex: 1
}}
>
<View flex={1}>
<Text fontWeight={'600'}>Add payment method</Text>
<Stack direction={'row'} justifyContent={'space-between'} mt={5}>
<MastercardIcon />
<VisaCardIcon />
<UnionPayIcon />
<AmericanExpressIcon />
<DinnerClubIcon />
<DiscoverCardIcon />
</Stack>
<StripeProvider publishableKey={STRIPE_PUBLISHABLE_KEY}>
<CardField
postalCodeEnabled={false}
placeholders={{
number: '4242 4242 4242 4242'
}}
cardStyle={{
backgroundColor: '#FFFFFF',
textColor: '#000000',
placeholderColor: colors.secondary[200]
}}
style={{
width: '100%',
height: 50,
marginVertical: 30
}}
onCardChange={cardDetails => {
fetchCardDetails(cardDetails);
}}
/>
</StripeProvider>
<View style={{flexGrow: 1}} />
<Box mb={6}>
<GoToNext handleSubmit={handlePayPress} isLoading={loadingPay} title={'save'} disabled={!cardData} />
</Box>
</View>
</KeyboardAvoidingView>
</View>
);
};
export default PaymentToken;
https://github.com/stripe/stripe-react-native/issues/1594 https://github.com/stripe/stripe-react-native/issues/1594
Is there an example of this for Swift/SwiftUI? I'm trying to create a token but I can only get the last four from STPPaymentMethod and it seems I need the full card number to create a token. cc @charliecruzan-stripe
Hello!
I'm migrating over from tipsi-stripe so I think I'm mostly integrated with Stripe already but I cannot for the life of me figure out how to create a token in the way I was doing it before. I would appreciate anyone pointing me in the right direction. I scoured the docs, examples, and issues for the last two days but got very lost/confused and think I might've ended up on the wrong site? I tried running the example project to investigate further too but couldn't get it to work.
In the app I'm working on, we allow users to add cards to use later (it's a food delivery app so they shouldn't have to add their card every time, only once). Before, I gathered the card info like this:
and created a token (type object) like this:
I then sent the token to the backend where it talked to stripe which stored the card. The stripe-react-native function that seems to be analogous is
createToken
, which takes in an object wheretype
is the only required field, and returns a token object and an error. Then what happens? How doescreateToken
create a token that refers to a specific card with only the type (hypothetically) and not the number, cvc, etc? Is there another function that would let me take in my params and return an object with an id, or is this a much more complex problem?I'm not using expo if that is important. I truly appreciate anyone's help. I'm still learning so some things aren't intuitive to me yet.