jonasbark / flutter_stripe_payment

[DISCONTINUED] A flutter plugin with stripe payment plugin integration
MIT License
309 stars 244 forks source link

Use existing cards #187

Closed ollyde closed 4 years ago

ollyde commented 4 years ago

How would we use existing cards with this library? Instead of asking for a new card each time.

(We know how to process the APIs with customer id & card tokens)

deepakrana0011 commented 4 years ago

@ollydixon i have same query , i have tried alot but not get any solution , if you get any solution please let me know

eyoeldefare commented 4 years ago

@ollydixon i have same query , i have tried alot but not get any solution , if you get any solution please let me know

How would we use existing cards with this library? Instead of asking for a new card each time.

I am guessing by existing cards, you mean saved customers' cards you can charge. I don't think this is going to be possible to implement. This is not a direct API communication with the stripe service anymore, there will be intermediate steps that make it complicated. I believe you have to get customer-id from the stripe API to charge that customer instead of the card. And if you want to save the customer, that customer id needs to be in some sort of database, and have that customer id to charge as your existing card. As you can imagine this will require steps that could need a dedicated server.

ollyde commented 4 years ago

@eyoeldefare we managed to save customer cards using the server and retrieve them (Using StripeAPIs it returns the card id), but I can't see anything in this package that allows us to use existing card ids; there is only pay with card form. On the web, you can use a card id.

eyoeldefare commented 4 years ago

@eyoeldefare we managed to save customer cards using the server and retrieve them (Using StripeAPIs it returns the card id), but I can't see anything in this package that allows us to use existing card ids; there is only pay with card form. On the web, you can use a card id.

Are you saying you've manage to save the customer id (card id alone can't be used for recharging customers, you need to create customer object that will have the card object in it and charge the customer) into your database for later usage? And your issue now is not having a UI to display the saved cards?

ollyde commented 4 years ago

@eyoeldefare the process is that you create a customer, then the customer can add cards to though the Stripe API. You can also retrieve cards but not the full details (long number). Then you use the customer id with the card id to process the payment BUT it requires an additional authorization UI step that is missing in this package. Without saved cards this package is fairly useless to 99% of apps; no one is going to enter a card each time to pay for something; that is absurd.

eyoeldefare commented 4 years ago

@eyoeldefare the process is that you create a customer, then the customer can add cards to though the Stripe API. You can also retrieve cards but not the full details (long number). Then you use the customer id with the card id to process the payment BUT it requires an additional authorization UI step that is missing in this package. Without saved cards this package is fairly useless to 99% of apps; no one is going to enter a card each time to pay for something; that is absurd.

Haven't really tried it, but if you indeed saved the customer id in your database and have everything, you can try using the createPaymentMethod(PaymentMethodRequest request) method and see if it works.

ollyde commented 4 years ago

Unfortunately, it only takes the full card and not the card id. You're not actually allowed to store full card details by law unless you have a special license (hard to obtain) hence the reason for using Stripe Card Ids. Stripe holds the cards.

Screenshot 2020-08-10 at 17 43 45
eyoeldefare commented 4 years ago

Unfortunately, it only takes the full card and not the card id. You're not actually allowed to store full card details by law unless you have a special license (hard to obtain) hence the reason for using Stripe Card Ids. Stripe holds the cards.

Screenshot 2020-08-10 at 17 43 45

Yeah, you can ask the owner of this repository about it, but my guess is he will tell you its impossible. I just don't see a way to get the sensitive stuff from your serverside with all secret stuff and display them, and then allow the API to make a request using that sensitive info too. Well, good luck.

ollyde commented 4 years ago

@eyoeldefare we already have the card id and customer id that is enough to process a payment on the client 🤪 yes, who is the owner, I can tag them.

eyoeldefare commented 4 years ago

@eyoeldefare we already have the card id and customer id that is enough to process a payment on the client 🤪 yes, who is the owner, I can tag them.

jonasbark is the owner of this repository.

ollyde commented 4 years ago

@jonasbark currently it throws the error PlatformException(api, Missing required param: card[number]., null) when trying to use CardId

eyoeldefare commented 4 years ago

https://github.com/tipsi/tipsi-stripe/issues/610

tantzygames commented 4 years ago

My app saves cards for future use. If you want to re-use a payment method, you need to create a Setup Intent: https://stripe.com/docs/payments/setup-intents

Then you can use the payment method id for multiple future payments

ollyde commented 4 years ago

@Kretin1 I tried this, said that the long number was missing on the card. Can you give me your code example? (on the client) I know how to do it server side.

Because it's not just about making payment intents, it's about the authorization process as well, etc. Many factors here.

Both would be nice for future readers though.

tantzygames commented 4 years ago

Beyond getting a payment method id or native token, I don't really do anything on the client. I just send the customer id and payment method id to Firebase functions to create a payment intent.

There are quite a few tutorials for setting up this plugin. If you want help with authorization or specific questions maybe try StackOverflow

ollyde commented 4 years ago

@Kretin1 right but how do you consume that payment intent on the client? Your public payments will fail because you're not stepping though the many authorization gates stripe takes care of.

tantzygames commented 4 years ago

This explains how to confirm a payment intent: https://medium.com/flutterdevs/stripe-payment-in-flutter-d7f87f9a193c

ollyde commented 4 years ago

@Kretin1 I know how to setup payment intents for the last time, I have other web applications that use Stripe. That isn't the original question.

I asked how we process existing customer cards using the Stripe client since it requires authorization steps such as 3d secure, or bank id for example.

paymentRequestWithCardForm is the incorrect option. We are talking about saved cards on file on the Stripe API. You're not allowed to legally save cards in your own database if you didn't know.

eyoeldefare commented 4 years ago

@Kretin1 I know how to setup payment intents for the last time, I have other web applications that use Stripe. That isn't the original question.

I asked how we process existing customer cards using the Stripe client since it requires authorization steps such as 3d secure, or bank id for example.

paymentRequestWithCardForm is the incorrect option. We are talking about saved cards on file on the Stripe API. You're not allowed to legally save cards in your own database if you didn't know.

Why don't you close this? Like I told you, there is no implementation for it as of right now. This is a plug in using tipsi for reactjs and if they don't have it yet, that means we don't have it. We are just using their plugin. If you want more detail, here https://github.com/tipsi/tipsi-stripe/issues/610

ollyde commented 4 years ago

@eyoeldefare I'm looking into paying people to create a module on this library so it will stay open until we get that pull request in.

ollyde commented 4 years ago

@deepakrana0011 For anyone else who is stuck, I finally cracked it.

The steps.

  1. Backend: Create customer via Stripe API (you need endpoints for this.)

  2. Backend/Frontend: Add a card via Stripe API (you need endpoints for this.)

  3. Backend/Frontend: Fetch the existing cards, let the customer choose one (the card id is important here)

  4. Using the same card, create a payment intent.

const intent = await stripe.paymentIntents.create({
            amount: getStripeAmount(service),
            currency: 'NOK',
            customer: user.stripCustomerId,
            // Card id from the fetch list of cards.
            payment_method: card.id,
            // Just any meta data, important for link things.
            metadata: {
                'productId': productId,
                'userUid': userUid,
            },
            receipt_email: user.email,
            off_session: true,
            confirm: true,
        })

Then on the client you need to do the following

  1. Fetch the customer billing information (address), save this in the Stripe API, makes it easy.
  2. Create the billing address

    
    final customerJson = await request('fetch-user-stripe-customer');
    
    final billingAddress = BillingAddress(
      city: customerJson['address']['city'],
      country: customerJson['address']['country'],
      line1: customerJson['address']['line1'],
      line2: customerJson['address']['line2'],
      postalCode: customerJson['address']['postalCode'],
      state: customerJson['address']['state'],
    );

Finalise the card payments.

print('Paying with existing card'); final intentJson = await request('create-card-payment-method', data: { 'cardId': card.cardId, });

  final paymentIntent = PaymentIntent(
    clientSecret: intentJson['client_secret'],
    paymentMethodId: intentJson['payment_method'],
    paymentMethod: PaymentMethodRequest(
      token: Token(
        tokenId: intentJson['payment_method'],
        livemode: intentJson['livemode'],
        created: (intentJson['created'] as int).toDouble(),
      ),
      billingAddress: billingAddress,
    ),
  );

  paymentIntentResult = await StripePayment.authenticatePaymentIntent(
    clientSecret: paymentIntent.clientSecret,
  );


Then you should have ```(paymentIntentResult.status == 'succeeded')``` it's done!!
AdnanKazi commented 4 years ago

@deepakrana0011 For anyone else who is stuck, I finally cracked it.

The steps.

  1. Backend: Create customer via Stripe API (you need endpoints for this.)
  2. Backend/Frontend: Add a card via Stripe API (you need endpoints for this.)
  3. Backend/Frontend: Fetch the existing cards, let the customer choose one (the card id is important here)
  4. Using the same card, create a payment intent.
const intent = await stripe.paymentIntents.create({
            amount: getStripeAmount(service),
            currency: 'NOK',
            customer: user.stripCustomerId,
            // Card id from the fetch list of cards.
            payment_method: card.id,
            // Just any meta data, important for link things.
            metadata: {
                'productId': productId,
                'userUid': userUid,
            },
            receipt_email: user.email,
            off_session: true,
            confirm: true,
        })

Then on the client you need to do the following

  1. Fetch the customer billing information (address), save this in the Stripe API, makes it easy.
  2. Create the billing address
final customerJson = await request('fetch-user-stripe-customer');

    final billingAddress = BillingAddress(
      city: customerJson['address']['city'],
      country: customerJson['address']['country'],
      line1: customerJson['address']['line1'],
      line2: customerJson['address']['line2'],
      postalCode: customerJson['address']['postalCode'],
      state: customerJson['address']['state'],
    );

Finalise the card payments.

print('Paying with existing card');
      final intentJson = await request('create-card-payment-method', data: {
        'cardId': card.cardId,
      });

      final paymentIntent = PaymentIntent(
        clientSecret: intentJson['client_secret'],
        paymentMethodId: intentJson['payment_method'],
        paymentMethod: PaymentMethodRequest(
          token: Token(
            tokenId: intentJson['payment_method'],
            livemode: intentJson['livemode'],
            created: (intentJson['created'] as int).toDouble(),
          ),
          billingAddress: billingAddress,
        ),
      );

      paymentIntentResult = await StripePayment.authenticatePaymentIntent(
        clientSecret: paymentIntent.clientSecret,
      );

Then you should have (paymentIntentResult.status == 'succeeded') it's done!!

@ollydixon Good example but Does your method support SCA ?

ollyde commented 4 years ago

@AdnanKazi hey, it supports SCA since all the endpoints and information are processed by strip APIs. We don't store any personal information such as cards, etc. Retrieving the list of cards hides personal information like long numbers by default on the Stripe APIs.

AdnanKazi commented 4 years ago

@AdnanKazi hey, it supports SCA since all the endpoints and information are processed by strip APIs. We don't store any personal information such as cards, etc. Retrieving the list of cards hides personal information like long numbers by default on the Stripe APIs.

I want to use for subscription even i cant get the proper guidance how should proceed if i am using subscription api if payment succeeds it deducts amount but if it fail due to card authentication then i need to redirect to browser

I short i dont know weither i should use payment intent or subscription api for subcription flow

Thanks

ollyde commented 4 years ago

@AdnanKazi thats easy; it’s future card payments option :-)

AdnanKazi commented 4 years ago

Thank you very much glad you gave reply quickly just last thing can you give some links so that i can start @ollydixon

maxb94 commented 3 years ago

@deepakrana0011 For anyone else who is stuck, I finally cracked it.

The steps.

  1. Backend: Create customer via Stripe API (you need endpoints for this.)
  2. Backend/Frontend: Add a card via Stripe API (you need endpoints for this.)
  3. Backend/Frontend: Fetch the existing cards, let the customer choose one (the card id is important here)
  4. Using the same card, create a payment intent.
const intent = await stripe.paymentIntents.create({
            amount: getStripeAmount(service),
            currency: 'NOK',
            customer: user.stripCustomerId,
            // Card id from the fetch list of cards.
            payment_method: card.id,
            // Just any meta data, important for link things.
            metadata: {
                'productId': productId,
                'userUid': userUid,
            },
            receipt_email: user.email,
            off_session: true,
            confirm: true,
        })

Then on the client you need to do the following

  1. Fetch the customer billing information (address), save this in the Stripe API, makes it easy.
  2. Create the billing address
final customerJson = await request('fetch-user-stripe-customer');

    final billingAddress = BillingAddress(
      city: customerJson['address']['city'],
      country: customerJson['address']['country'],
      line1: customerJson['address']['line1'],
      line2: customerJson['address']['line2'],
      postalCode: customerJson['address']['postalCode'],
      state: customerJson['address']['state'],
    );

Finalise the card payments.

print('Paying with existing card');
      final intentJson = await request('create-card-payment-method', data: {
        'cardId': card.cardId,
      });

      final paymentIntent = PaymentIntent(
        clientSecret: intentJson['client_secret'],
        paymentMethodId: intentJson['payment_method'],
        paymentMethod: PaymentMethodRequest(
          token: Token(
            tokenId: intentJson['payment_method'],
            livemode: intentJson['livemode'],
            created: (intentJson['created'] as int).toDouble(),
          ),
          billingAddress: billingAddress,
        ),
      );

      paymentIntentResult = await StripePayment.authenticatePaymentIntent(
        clientSecret: paymentIntent.clientSecret,
      );

Then you should have (paymentIntentResult.status == 'succeeded') it's done!!

@ollydixon Thanks for this! For step 2, which Stripe API endpoint are you using to add a card and associate it with the customer?

jpcarreira commented 3 years ago

Reviving this one as I'm running to a similar issue: I can't re-use existing cards.

Exception has occurred.
PlatformException (PlatformException(authenticationFailed, There was an unexpected error -- try again in a few seconds, There was an unexpected error -- try again in a few seconds, null))

I've done all the steps: creating Stripe customer, adding a card, fetching all cards, picking a given card, etc. All of this is working. My problem is when I try to use that card, I can't seem to go through a (paymentIntentResult.status == 'succeeded')