Ad

Flutter Stripe_payment Native Pay Not Charged(Apple Pay And Google Pay)

- 1 answer

The stripe payment API call return status 200 but the amount isn't charged.

I have a Flutter application uses Stripe payment.

I have done:

  1. certification has been created.
  2. merchant id has been created.

Followed the example of stripe_payment, I have my native payment method below:

void _handleNativePayment(String amount) async {
    Token token = await StripePayment.paymentRequestWithNativePay(
      androidPayOptions: AndroidPayPaymentRequest(
        totalPrice: amount,
        currencyCode: _currencyCode,
      ),
      applePayOptions: ApplePayPaymentOptions(
        countryCode: _countryCode,
        currencyCode: _currencyCode,
        items: [
          ApplePayItem(
            type: 'final',
            label: _paymentLabel,
            amount: amount,
          )
        ],
      ),
    );

    await StripePayment.completeNativePayRequest();
}

When I run it on simulator, I can see the payment is done and can view the request on Stripe dashboard unfortunately the Payment is still 0.: enter image description hereenter image description hereenter image description here

Ad

Answer

Before look into the code, please make sure you have finished the following steps: 0. stripe_payment is added.

  1. Merchant Id has been created.
  2. Apple Pay has been enabled in Xcode.
  3. Stripe "Standard Key" and "Restricted Key" have been generated.
    • standard key contains publishable key and secret key
    • publishable key uses in Flutter project.
    • restricted key uses in Server side.

What i have been done for the native payment:

  1. calls paymentRequestWithNativePay() to get token.
  2. charges with own implemented charge method(on Server side, makes sure you use the restricted key and it has charge write permission).
  3. calls paymentRequestWithNativePay()
    void handleNativePayment(BuildContext context, String amountInStr) async {
        // I used environment configurations for ANDROID_PAY_MODE, use "test" in test mode
        // and uses "production" in production mode
        StripePayment.setOptions(StripeOptions(
            publishableKey: _publishableKey,
            merchantId: _merchantId,
            androidPayMode: EnvironmentConfig.ANDROID_PAY_MODE,
        ));
    
        // this is my service class talks to server side API 
        PaymentService paymentService = Provider.of<PaymentService>(
          context,
          listen: false,
        );
    
        Token token = await StripePayment.paymentRequestWithNativePay(
          androidPayOptions: AndroidPayPaymentRequest(
            totalPrice: amountInStr,
            currencyCode: _currencyCode,
          ),
          applePayOptions: ApplePayPaymentOptions(
            countryCode: _countryCode,
            currencyCode: _currencyCode,
            items: [
              ApplePayItem(
                type: 'final',
                label: paymentLabel,
                amount: amountInStr,
              )
            ],
          ),
        );
    
        // converts amount from string to int, and it is in cents
        dynamic chargeResult = await paymentService.charge({
          "token": token.tokenId,
          "amount": double.parse(amountInStr) * 100,
          "currency": _currencyCode,
        });
    
        if (chargeResult is ChargeResult) {
          _buildSnackBar(context, "Payment success", Colors.green);
        } else {
          _buildSnackBar(context, "Payment fail", Colors.red);
        }
    
        await StripePayment.completeNativePayRequest();
      }

  _buildSnackBar(BuildContext context, String content, Color color) {
    final snackBar = SnackBar(
      content: Text(content),
      backgroundColor: color,
    );
    Scaffold.of(context).showSnackBar(snackBar);
  }

Here's the PaymentService in Flutter. You need implement the server side charge API call with the Stripe restricted key.

class PaymentService {
  var logger = Logger(printer: PrettyPrinter());

  Future<dynamic> charge(Map<String, dynamic> data) async {
    Map<String, dynamic> charge = {
      "source": data["token"],
      "amount": data["amount"],
      "currency": data["currency"],
    };
    final response = await DioHttp.post('/stripe/payment/charge', charge);
    if (response.containsKey("results")) {
      return ChargeResult.fromMap(response["results"]);
    } else {
      String errorMessage = response["errors"][0]["description"];
      return errorMessage;
    }
  }
}

There's one more thing needs your attention:

When test with Android phone, don't use Stripe test cards numbers, it always gives you request failure(error codeOR-CCSEH-21). What you need to do is:

  1. sets android pay mode to 'test'.
  2. pays with your own/real card and it will pass(In below attached payment records, you can see the last payment contains my name, that's because i used my own card for the android google pay testing)

Hope it helps developers who needs it.

enter image description hereenter image description here

Ad
source: stackoverflow.com
Ad