GithubHelp home page GithubHelp logo

stripe-expo's People

Contributors

altwohill avatar anp avatar brentvatne avatar dependabot[bot] avatar ide avatar jeff-da avatar romainhill avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

stripe-expo's Issues

createToken() returns SyntaxError: Unexpected token o in JSON at position 1

Hi,

I've been using this library for quite a while and never had an issue to create a credit card token with the method createToken(card). The card variable being an object following the documentation:

card: {
    cvc: "123",
    exp_month: "03",
    exp_year: "2021",
    number: "4000 0034 4000 0004"
}

Suddenly, I get the following error:
SyntaxError: Unexpected token o in JSON at position 1

Is this a bug?

Thank you.

`createToken()` fails on Android with error `Unexpected token o in JSON`

My creditcard form works fine on iOS, however on Android it fails to fetch the token

Here's a snippet of the code

class ConfirmOrderScreen extends Component {
  constructor(props, context) {
    super(props, context);
    this.receiveToken = this.receiveToken.bind(this);
    this.processCreditCard = this.processCreditCard.bind(this);
    this.stripe = stripe(STRIPE_CLIENT_KEY);
  }

  receiveToken(token) {
    const order = Object.assign({}, this.props.order);
    order.paymentToken = token;
    this.props.confirm(order);
  }

  async processCreditCard(card) {
    if (card.valid) {
      const payment = {
        card: {
          number: card.values.number.replace(/\s/g, ''),
          exp_month: card.values.expiry.slice(0, card.values.expiry.indexOf('/')),
          exp_year: card.values.expiry.slice(card.values.expiry.indexOf('/') + 1),
          cvc: card.values.cvc,
        },
      };
      const token = await this.stripe.createToken(payment); //<--- Error on Android only: SyntaxError: Unexpected token o in JSON at position 1
      this.receiveToken(token);
    }
  }
}

It appears to stem from the _parseJSON(token) function, judging from the "Pause on caught exception" snapshot

image

I'm using the following versions

    "expo": "^20.1.3",
    "react": "^16.0.0-rc.3",
    "react-native": "0.47",
    "stripe-client": "^1.1.3",
    "urijs": "^1.18.12"

The premise under "Features" seems false

Hello,

It seems to me that the premises under "Features" are false:

"Collect credit card information and convert it to a Stripe token in a single line of Javascript"

As far as I understand the library, it does not offer any tools to collect card information (checkout flow, UI elements or the like), but should instead read

"Convert credit card information to a Stripe token in a single line of Javascript"

  • at least for now? Maybe the library and readme was started with this in mind, but hasn't gotten that far yet?

Does this library generate tokens client side?

Hi,

Thank you for all of the work on this. I've looked through some of the source code and the README, and am uncertain whether the token is generated on the client side.

It appears you are posting the payment details to the https://api.stripe.com/v1/tokens endpoint (documented here, which might be advised against in the docs. They recommend using Checkout, Elements, or the native ios/android libraries, since the tokenization is done in the client.

Am I correct in my understanding, or is there only a risk if I were to send the payment information to my server before sending it to stripe? I tried digging into https://js.stripe.com/v3/, but am uncertain wether they create the token the same way.

Do I need to detach my expo project to make this API work?

Hi,

Thinking to switch my react-native apps to expo and the only blocking point I have today is about payment. According to the payment documentation from your website, I need to detach a project to implement it.

Is this library working without detaching the related expo project?

Also, if I need to detach a project, can I still use expo functionalities to publish my app to store and/or use push notifications for instance?

How can I be aware once expo support full implementation of Stripe payments?

Thanks and regards,

Current release (1.1.3) does not include important fix

Pull request #20 fixes an important bug, but it is not being included when package.json reads:

"stripe-client": "^1.1.3"

Instead to get it one has to install the client using:

"stripe-client": "github:expo/stripe-expo#master"

I'm no expert in how to resolve this... perhaps tag a new release?

Stripe UI element option

stripe-expo have any option for embed strip elements (card details,account info) view and validations ?
like rectjs we can use react-stripe-elements to embed stripe elements in our application directly.

Stripe Terminal SDK

Could this be extended to work for the Stripe Terminal SDK? Or is this strictly for the non-reader Stripe API?

Thanks,
Kevin

Unexpected return object from 'stripe.createToken()'

It seems that the .createToken() method is returning a different object than expected. Instead, it returns the entire response from the fetch to Stripe. The examples from the README.md access the 'id' attribute of the returned object, of which there is none.

I think that the solution is for the '_createTokenHelper()' function not to return the entire response from Stripe.

I'm going to make a quick pull-request to change it, but if this is actually the intended functionality of the 'createToken()' & '_createTokenHelper()' functions, don't mind me! 😊

Full payment Example

Is this API just for creating credit card token?

It will be my first attempt to implement payments in the app, and I would like use stripe with expo.
Could you add a example of how to handle payment with this API?

  1. registering credit card
  2. paying for product
  3. removing registered credit card

Basically, the flow in the app will looks like.
user must register credit card to make a payment -> with the token saved in the client, user can make a payment -> user can remove credit card(remove the token).

I don't have a clear picture how it should be implemented.

Stripe: Setting up future payments not working as expected.

Hi all! I’m in desperate need for help.

So I have a side project for an iOS app using Expo / React Native. And I'm having issues with setting up future payment methods using Stripe & Expo’s stripe library.

Our back-ender set up a graphql back-end, and provides me with all the variables I need. I’m trying to se up payment methods to charge clients later, but I’m having trouble having with the paymentIntentSheet not showing up after creating an intent and fetching the clientSecret, ephemeralKey and customerId from our back-end. Now i don’t know where the issue is.. Is it because of me using the wrong versions? Maybe incorrect installation? Are the variables I’m using right..?

I used the following documentation page(s) as a guide:
https://stripe.com/docs/payments/save-and-reuse?platform=react-native
https://github.com/stripe/stripe-react-native#expo

These are the version numbers of the libraries I’m using, relevant to this topic/issue:

"expo": "~41.0.1",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
"@stripe/stripe-react-native": "0.1.1"

These are the steps I took:

  1. Install stripe-react-native, and add it to my app.json as a plugin:
"plugins": [
			[
				"@stripe/stripe-react-native",
				{
					"merchantIdentifier": "",
					"enableGooglePay": false
				}
			]
		],
  1. On global level, I import the StripeProvider component and pass down the given publishable key:
    pk_live_51[.....]

On global level it’ll look like this:

<StripeProvider
publishableKey="pk_live_51[...]"
		>
			<AuthProvider>
				<ApolloProvider client={client}>
					<InnerApp />
				</ApolloProvider>
			</AuthProvider>
		</StripeProvider>
  1. Then according to the stripe docs, at the location where I’ll be using the bulk of the logic, I am supposed to fetch the setupIntent, ephemeralKey, and the customer from the back-end, in this case, in the useEffect of my component. I was provided with a graphql mutation to obtain these values:
mutation (
		$createUserPaymentMethodSetupIntentInput: CreateUserPaymentMethodSetupIntentInput!
	) {
		createUserPaymentMethodSetupIntent(
			input: $createUserPaymentMethodSetupIntentInput
		) {
			setupIntentId
			clientSecret
			customerId
			ephemeralKeySecret
		}
	}

Then, I call the function that will eventually provide me with all the necessary variables:


createIntent({
			variables: {
				createUserPaymentMethodSetupIntentInput: {
					userUid: userUid,
				},
			},
		})
			.then((res) => {
				const clientSecret =
					res.data.createUserPaymentMethodSetupIntent.clientSecret
				const setupIntentId =
					res.data.createUserPaymentMethodSetupIntent.setupIntentId
				const ephemeralKeySecret =
				res.data.createUserPaymentMethodSetupIntent.ephemeralKeySecret
				const customerId =
					res.data.createUserPaymentMethodSetupIntent.customerId
                
                // IGNORE THIS FOR NOW
				initializePaymentSheet(
					clientSecret,
					setupIntentId,
					ephemeralKeySecret,
					customerId
				)
			})
			.catch((err) => console.log({ graphqlError: err }))

The function gives me the following response:

Object {
  "data": Object {
    "createUserPaymentMethodSetupIntent": Object {
      "__typename": "CreatedUserPaymentMethodSetupIntent",
      "clientSecret": "seti_1K[....]",
      "customerId": "cus_[...]",
      "ephemeralKeySecret": "ek_live_[...]",
      "setupIntentId": "seti_[...]",
    },
  },
  1. According to the docs, I should use the setupIntent, ephemeralKey, and customer values as variables in ONE of their given functions/hooks called “initPaymentSheet” that should initialize the paymentsheet on their end.

These functions are imported like this:

const { initPaymentSheet, presentPaymentSheet } = useStripe();

In step 3, you see that I call a function that then calls the initPaymentSheet after successfully fetching the values from the server.

initializePaymentSheet(
					clientSecret,
					setupIntentId,
					ephemeralKeySecret,
					customerId
				)

The initializePaymentSheet looks like this:

const initializePaymentSheet = (
		clientSecret,
		setupIntentId,
		ephemeralKeySecret,
		customerId
	) => {
		initPaymentSheet({
			customerId: customerId,
			customerEphemeralKeySecret: ephemeralKeySecret,
			setupIntentClientSecret: setupIntentId,
		})
			.then((res) => {
				console.log(res)
				setDisabledButton(false)
			})
			.catch((err) => console.log("error.."))
	}

As you can see, I call the initPaymentSheet hook there, exactly like shown on the docs, and pass in the values i received from the back-end. However, after doing this i get the following error in the console:

Object {
  "error": Object {
    "code": "Failed",
    "message": "You must provide the paymentIntentClientSecret",
  },
}

This didn’t seem like a huge error, so I went ahead and changed the initPaymentSheet parameters by adding the paymentIntentClientSecret field and passed in the clientSecret value which wasn’t previously used:

initPaymentSheet({
			customerId: customerId,
			customerEphemeralKeySecret: ephemeralKeySecret,
			setupIntentClientSecret: setupIntentId,
			paymentIntentClientSecret: clientSecret
		})
			.then((res) => {
				console.log(res)
				setDisabledButton(false)
			})
			.catch((err) => console.log("little error.."))

After calling the function and seeing the error disappear, and the console.log shown above logs the following in the console:

Object {
  "paymentOption": null,
}

I didn’t think too much of this, and thought it says null just because I have no previously set paymentOptions. I was just happy there were no more errors.
In the .then chain, you see that i enable a button that basically allows a user to call a function that would present a payment sheet where users can submit their paymentMethod. This button is disabled, because I think you should initialize the paymentSheet first before presenting it?

<WideButton
				disabled={disabledButton}
				text="Add New Payment Method"
				clicked={openPaymentSheet}
			/>
  1. Anyways, now that the button is finally enabled, the user can click on it and it'll call the following function:
const openPaymentSheet = async () => {
		setDisabledButton(true)
		const { error, paymentOption } = await presentPaymentSheet()

		if (error) {
			console.log(error)
			setDisabledButton(false)
			Alert.alert(`Error code: ${error.code}`, error.message)
		}

		if (paymentOption) {
			setDisabledButton(false)
			Alert.alert(
				"Success",
				"Your payment method is successfully set up for future payments!"
			)
			console.log(paymentOption)
		}

	
	}

Now to quote the stripe docs:
When your customer taps the Set up button, call presentPaymentSheet() to open the sheet. After the customer completes setting up their payment method for future use, the sheet is dismissed and the promise resolves with an optional StripeError.

So, that's exactly what I did: Call the presentPaymentSheet, but then i get the following error:

Object {
  "code": "Failed",
  "message": "There was an unexpected error -- try again in a few seconds",
}

Now this is where I’m stuck, because it doesn’t provide me with any more information than given above. I’ve tried looking everywhere, and some resources tell me that I should update my stripe, some say i should add stripe to my plugins in app.json. I’ve done all of that and I can’t still figure it out.

Here is a video showing you the behavior in action:
https://user-images.githubusercontent.com/29804130/146274443-82c581ba-8913-4c87-ad2e-5b8719680fed.mov

Here is the code of the entire component:


// steps
// 1. call graphql query to set up intent, retrieve the clientsecret and setupintentid
// 2. call stripes initPaymentSheet's function and pass in useruid, clientsecret and setupintentid
// 3. when  initpaymentsheet is ready, enable button for user to add payment information
// 4. Retrieve the payment information and call the createpaymentmethod mutation
// 5. disable button again, and refresh page

export default function PaymentMethods({ userUid }) {
	const { initPaymentSheet, presentPaymentSheet } = useStripe()

	const [disabledButton, setDisabledButton] = useState(false)

	const [createIntent, { data, loading, error }] = useMutation(
		ADD_PAYMENT_METHOD_INTENT
	)

	useEffect(() => {
		createUserPaymentMethodIntent()
	}, [])

	const createUserPaymentMethodIntent = () => {
		setDisabledButton(true)

		createIntent({
			variables: {
				createUserPaymentMethodSetupIntentInput: {
					userUid: userUid,
				},
			},
		})
			.then((res) => {
				console.log(res)

				const clientSecret =
					res.data.createUserPaymentMethodSetupIntent.clientSecret
				const setupIntentId =
					res.data.createUserPaymentMethodSetupIntent.setupIntentId
				const ephemeralKeySecret =
					res.data.createUserPaymentMethodSetupIntent.ephemeralKeySecret
				const customerId =
					res.data.createUserPaymentMethodSetupIntent.customerId

				initializePaymentSheet(
					clientSecret,
					setupIntentId,
					ephemeralKeySecret,
					customerId
				)
			})
			.catch((err) => console.log({ graphqlError: err }))
	}

	const initializePaymentSheet = (
		clientSecret,
		setupIntentId,
		ephemeralKeySecret,
		customerId
	) => {
		initPaymentSheet({
			customerId: customerId,
			customerEphemeralKeySecret: ephemeralKeySecret,
			setupIntentClientSecret: setupIntentId,
			paymentIntentClientSecret: clientSecret,
		})
			.then((res) => {
				console.log(res)
				setDisabledButton(false)
			})
			.catch((err) => console.log("little error.."))
	}

	const openPaymentSheet = async () => {
		setDisabledButton(true)

		const { error } = await presentPaymentSheet()

		if (error) {
			Alert.alert(`Error code: ${error.code}`, error.message)
		} else {
			Alert.alert(
				"Success",
				"Your payment method is successfully set up for future payments!"
			)
		}
	}

	return (
		<ScrollView>
			<PaymentMethodList userUid={userUid} />
			<WideButton
				disabled={disabledButton}
				text="Add New Payment Method"
				clicked={openPaymentSheet}
			/>
		</ScrollView>
	)
}

someone plz help :(

Invalid token ID error

Hi, I'm not sure if this is a "stipe-expo" issue but I suspect it might be because it relates to a token I'm trying to generate using this library. So forgive me if not ;)

I'm getting the error: Invalid token ID when creating a paymentIntent through the official "stripe" node.js library on my back end.

I can process a simple payment where my platform charges a customer card token. This works fine:

stripe.paymentIntents
    .create({
      amount: 100,
      confirm: true,
      currency: "gbp",
      description: "payment",
      payment_method_types: ["card"],
      payment_method_data: {
        type: "card",
        card: {
          token: customerCard.id, // token generated on the client side (see below for code)
        },
      },
    })

But now I want to move away from a 'simple' charge to a 'direct' charge flow using Stripe Connect, as per this guide: https://stripe.com/docs/connect/direct-charges

If I amend my code as per the guide so that I'm trying to generate the card token on the connect account (rather than my platform stripe account), and then create the paymentIntent to create the charge on the connect account:

stripe.paymentIntents
    .create({
      amount: 1000,
      application_fee_amount: 100, // trying to take a fee now
      confirm: true,
      currency: "gbp",
      description: "payment",
      payment_method_types: ["card"],
      payment_method_data: {
        type: "card",
        card: {
          token: customerCard.id, // token generated using the connect account id (see below for code)
        },
      },
    }, { stripeAccount: "{{ ACTUAL_CONNECT_ACCOUNT_ID_IS_HERE }}"}) // so that we're creating the charge on the connect account

The call fails (in my try catch) with "Error: Invalid token Id: tok_abc..."

Here's how I'm generating the token:

import createStripe from "stripe-client"; // https://github.com/expo/stripe-expo

...

// init a new instance of stripe client passing the ID of the connected account to create the token on that account
  const stripeClient = createStripe(
    "pk_test_5...gKi",
    { stripeAccount: "{ ACTUAL_CONNECT_ACCOUNT_ID_IS_HERE }" }
  );
  return stripeClient.createToken({ card });

I am getting what looks to be a valid token before passing it to the back end so I'm really stuck as to the reason the token is invalid.

Can someone please help?

Thanks!

Test environment

Invalid API Key provided: pk_test_

This error seems to imply no test enviorment?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.