Issue in displaying card in stripe payment intigration - flutter

I want to intigrate stripe payment but i got this error Instance of 'StripeConfigException Also my when i click on pay button it is not showing any type of card. I want to print jsonresponse["emphermalKey"] and jsonresponse["customer"] but these show null value.I also put api key correctly . Please solve my issue i am stuck in stripe payment for couple of days Here is my stripe log which shoes null value.
{
"customer": null,
"description": null,
"invoice": null,
"last_payment_error": null,
"latest_charge": null,
"next_action": null,
"on_behalf_of": null,
"payment_method": null,
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
"processing": null,
"review": null,
"setup_future_usage": null,
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "requires_payment_method",
"transfer_data": null,
"transfer_group": null
}
my code
Center(
child: ElevatedButton(
onPressed: () {
intpayment(email: "email,amount: 50.0);
},
child: Text("Pay20\$"),
),
),
Function
Future<void> intpayment(
{required String email, required double amount})async{
try{
final response= await http.post(Uri.parse("https://api.stripe.com/v1/payment_intents")
,body:{
"receipt_email": email,
"amount": amount.toInt().toString(),
"currency": "usd"
},
headers: {
'Authorization': 'Bearer ' + 'key',
'Content-Type': 'application/x-www-form-urlencoded'
}
);
final jsonresponse=jsonDecode(response.body); Stripe.instance.initPaymentSheet(paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: jsonresponse['paymentIntent'],
merchantDisplayName: 'Zohaib',
customerId: jsonresponse['customer'],
customerEphemeralKeySecret: jsonresponse['ephemeralKey'],
));
await Stripe.instance.presentPaymentSheet();
Fluttertoast.showToast(
msg: "payment successfully",
);
}
catch(e){
if (e is StripeException) {
Fluttertoast.showToast(
msg: "Stripe error $e",
);
}
Fluttertoast.showToast(
msg: "$e",
toastLength: Toast.LENGTH_SHORT, );
}
}
I think issue in this line when I comment out this the error remove but card is not displying
await Stripe.instance.presentPaymentSheet();

If you don't have any value in jsonresponse it means you backend hasn't been able to return them, and mostly because it didn't have the correct Secret Key or having some issue sending Stripe API itself.
The fastest way to isolate the issue is looking at your backend log, or your Stripe Request Logs https://dashboard.stripe.com/test/logs and find the specific call from your backend -> Stripe.

Related

Issue is in displaying card in stripe payment

I want to intigrate stripe payment but i got this error
Instance of 'StripeConfigException
Also my when i click on pay button it is not showing any type of card.
I want to print jsonresponse["emphermalKey"] and jsonresponse["customer"] but these show null value .
Please solve my issue i am stuck in stripe payment for couple of days
Here is my stripe log which shoes null value
{
"customer": null,
"description": null,
"invoice": null,
"last_payment_error": null,
"latest_charge": null,
"next_action": null,
"on_behalf_of": null,
"payment_method": null,
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
"processing": null,
"review": null,
"setup_future_usage": null,
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "requires_payment_method",
"transfer_data": null,
"transfer_group": null
}
my code
Center(
child: ElevatedButton(
onPressed: () {
intpayment(email: "email,amount: 50.0);
},
child: Text("Pay20\$"),
),
),
Function
Future<void> intpayment(
{required String email, required double amount})async{
try{
final response= await http.post(Uri.parse("https://api.stripe.com/v1/payment_intents")
,body:{
"receipt_email": email,
"amount": amount.toInt().toString(),
"currency": "usd"
},
headers: {
'Authorization': 'Bearer ' + 'key',
'Content-Type': 'application/x-www-form-urlencoded'
}
);
final jsonresponse=jsonDecode(response.body); Stripe.instance.initPaymentSheet(paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: jsonresponse['paymentIntent'],
merchantDisplayName: 'Zohaib',
customerId: jsonresponse['customer'],
customerEphemeralKeySecret: jsonresponse['ephemeralKey'],
));
await Stripe.instance.presentPaymentSheet();
Fluttertoast.showToast(
msg: "payment successfully",
);
}
catch(e){
if (e is StripeException) {
Fluttertoast.showToast(
msg: "Stripe error $e",
);
}
Fluttertoast.showToast(
msg: "$e",
toastLength: Toast.LENGTH_SHORT, );
}
}

Why not displaying card

I want to intigrate stripe payment but i got this error
** FlowController must be successfully initialized using configureWithPaymentIntent() or configureWithSetupIntent() before calling presentPaymentOptions()**
How solve this error also it is not displaying any card
Center(
child: ElevatedButton(
onPressed: () {
intpayment(email: "email,amount: 50.0);
},
child: Text("Pay20\$"),
),
),
Future<void> intpayment(
{required String email, required double amount})async{
try{
final response= await http.post(Uri.parse("https://api.stripe.com/v1/payment_intents")
,body:{
"receipt_email": email,
"amount": amount.toInt().toString(),
"currency": "usd"
},
headers: {
'Authorization': 'Bearer ' + 'key',
'Content-Type': 'application/x-www-form-urlencoded'
}
);
final jsonresponse=jsonDecode(response.body); Stripe.instance.initPaymentSheet(paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: jsonresponse['paymentIntent'],
merchantDisplayName: 'Zohaib',
));
await Stripe.instance.presentPaymentSheet();
Fluttertoast.showToast(
msg: "payment successfully",
);
}
catch(e){
if (e is StripeException) {
Fluttertoast.showToast(
msg: "Stripe error $e",
);
}
Fluttertoast.showToast(
msg: "$e",
toastLength: Toast.LENGTH_SHORT, );
}
}
You need to create the PaymentIntent on the server-side and not within your flutter app.
final response= await http.post(Uri.parse("https://api.stripe.com/v1/payment_intents")
,body:{
"receipt_email": email,
"amount": amount.toInt().toString(),
"currency": "usd"
},
headers: {
'Authorization': 'Bearer ' + 'key',
'Content-Type': 'application/x-www-form-urlencoded'
}
);
Instead of calling the Stripe API directly as you did in the code above, you should call your own API and generate a Payment Intent and just send the client_secret to your flutter App, otherwise you would be exposing your secret key and thus giving access to your data. This is described here.
Once you do this server-side part the rest is explained here.

In Flutter Is that possible to call API request in firebase Messaging BackgroundHandler?

I have implemented chat message app in which user can
reply to chat from push
notification when app is killed/background/foreground.
But when app is in Terminated state API call not work in
firebaseMessagingBackgroundHandler.
Its stuck on sendNotification function.
Code to handle background events:
Future<void>
firebaseMessagingBackgroundHandler(RemoteMessage message)
async {
await GetStorage.init();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform);
//Call HTTP request <Stuck here
sendNotification(
personUid,
title,
body,
notificationTypeId,
chatRoomId,
userTokenDummy,
userToken,
serverKey,
currentUserId,
currentUserToken,
);
}
Here is a code for API request:
sendNotification({
required String personUid,
required String title,
required String body,
required int notificationTypeId,
String? chatRoomId,
String? userTokenDummy,
String? userToken,
String? serverKey,
String? currentUserId,
String? currentUserToken,
}) async {
try {
final response = await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
HttpHeaders.contentTypeHeader:
'application/json',
HttpHeaders.authorizationHeader: 'key=$serverKey'
},
body: jsonEncode(
<String, dynamic>{
"data": <String, dynamic>{
"title": title,
"body": body,
"click_action": "FLUTTER_NOTIFICATION_CLICK",
"id": "1",
"status": "done",
"senderId": currentUserId,
"senderToken": currentUserToken,
"notificationTypeId": notificationTypeId,
"chatRoomId": chatRoomId,
},
"android": {
"priority": "high",
},
"apns": {
"headers": {"apns-priority": "10"}
},
"to": userToken,
"content_available": true,
"mutable-content": 1,
"priority": "high",
},
),
);
return response;
} catch (e) {
console(e.toString());
}
}
Yes,you can call Http request inside firebaseMessagingBackgroundHandler. But make sure that this api is not taking too much time. Because long and intensive tasks impacts on device performance. Also make sure that there is not exception or error in the api which causes the device to freeze.
To make sure that api is not running forever place a timeout in http class.
for more refer to firebase documentation : https://firebase.google.com/docs/cloud-messaging/flutter/receive

Stripe error the customer has not entered their payment method in flutter

I have integrated flutter_stripe 2.0.1 plugins in my flutter application using Firebase CLI. getting a successful response of paymentIntent from firebase provided URL. But in the Stripe dashboard payment status is Incomplete.
Below is my node.js code
index.js file
const functions = require('firebase-functions');
const stripe = require('stripe')(functions.config().stripe.testkey);
exports.stripePayment = functions.https.onRequest(async (req, res) => {
const paymentIntent = await stripe.paymentIntents.create({
amount: 1,
currency: 'usd'
},
function(err, paymentIntent) {
if(err != null){
console.log(err);
} else {
res.json({
paymentIntent: paymentIntent.client_secret,
})
}
}
)
});
Below is my flutter code
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Stripe.publishableKey = stripePublishableKey;
Stripe.merchantIdentifier = 'merchant.flutter.stripe.test'; //any string works
await Stripe.instance.applySettings();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DashboradPage(),
);
}
}
class DashboradPage extends StatefulWidget {
const DashboradPage({Key? key}) : super(key: key);
#override
_DashboradPageState createState() => _DashboradPageState();
}
class _DashboradPageState extends State<DashboradPage> {
Map<String, dynamic>? paymentIntentData;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Stripe Examples'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
makePayment();
},
child: Text('Pay Amount'),
),
),
);
}
Future<void> makePayment() async {
final url = Uri.parse(
'https://us-central1-stripeflutterdemo.cloudfunctions.net/stripePayment');
final header = {'Content-Type': 'application/json'};
try {
final response = await http.get(url, headers: header);
paymentIntentData = json.decode(response.body);
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData?['paymentIntent'] ?? '',
applePay: true,
googlePay: true,
style: ThemeMode.light,
merchantCountryCode: 'US',
merchantDisplayName: 'Flutter Stripe Store Demo',
));
setState(() {});
displayPaymentSheet();
} catch (e) {
print(e);
displaySnackbar(e.toString());
}
}
Future<void> displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet();
// await Stripe.instance.presentPaymentSheet(
// parameters: PresentPaymentSheetParameters(
// clientSecret: paymentIntentData?['paymentIntent'] ?? '',
// confirmPayment: true,
// ),
// );
setState(() {
paymentIntentData = null;
});
displaySnackbar('Payment succesfully completed');
} catch (e) {
print(e);
displaySnackbar(e.toString());
}
}
void displaySnackbar(String msg) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(msg),
),
);
}
}
Below is the postman response of URL mentioned in makePayment()
I have used payment sheet, when I clicked on the Pay button it is redirecting to webview (Authentication completed) but in the Stripe dashboard payment status is Incomplete.
Stripe Dashboard Payment Event data
PaymentIntent status:requires_payment_method,
PaymentIntent status:requires_action
From Stripe
payment_intent.payment_failed
View event detail
Event data
{
"id": "pi_3JpZh7SIKwX0CSUQ0sUoM9wK",
"object": "payment_intent",
"last_payment_error": {
"message": "As per Indian regulations, export transactions require a description. More info here: https://stripe.com/docs/india-exports",
"param": "description",
"payment_method": {
"id": "pm_1JpZijSIKwX0CSUQ7u91wths",
"object": "payment_method",
"billing_details": {
"address": {
"city": null,
"country": "US",
"line1": null,
"line2": null,
"postal_code": "45612",
"state": null
},
"email": null,
"name": null,
"phone": null
},
"card": {
"brand": "visa",
"checks": {
"address_line1_check": null,
"address_postal_code_check": "unchecked",
"cvc_check": "unchecked"
},
"country": "US",
"exp_month": 4,
"exp_year": 2044,
"fingerprint": "EK9VAoccqqCLBqQk",
"funding": "credit",
"generated_from": null,
"last4": "4242",
"networks": {
"available": [
"visa"
],
"preferred": null
},
"three_d_secure_usage": {
"supported": true
},
"wallet": null
},
"created": 1635431806,
"customer": null,
"livemode": false,
"metadata": {
},
"type": "card"
},
"type": "invalid_request_error"
},
"livemode": false,
"next_action": null,
"status": "requires_payment_method",
"amount": 1,
"amount_capturable": 0,
"amount_received": 0,
"application": null,
"application_fee_amount": null,
"canceled_at": null,
"cancellation_reason": null,
"capture_method": "automatic",
"charges": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/charges?payment_intent=pi_3JpZh7SIKwX0CSUQ0sUoM9wK"
},
"client_secret": "pi_3JpZh7SIKwX0CSUQ0sUoM9wK_secret_oVhK5CmrcHjImvFMyoo51GCXy",
"confirmation_method": "automatic",
"created": 1635431705,
"currency": "usd",
"customer": null,
"description": null,
"invoice": null,
"metadata": {
},
"on_behalf_of": null,
"payment_method": null,
"payment_method_options": {
"card": {
"installments": null,
"network": null,
"request_three_d_secure": "automatic"
}
},
"payment_method_types": [
"card"
],
"receipt_email": null,
"review": null,
"setup_future_usage": "off_session",
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"transfer_data": null,
"transfer_group": null
}
Below is the iPhone screenshot
According to the Stripe documentation, the required_payment_method message as a status means you have not attached a payment method to your payment intent:
When the PaymentIntent is created, it has a status of requires_payment_method until a payment method is attached.
There is an official document explaining how to integrate Stripe payments with your Firebase backend. It provides all the required code and steps to properly set up payments with Stripe. In the sample code inside the index.js file, they include additional objects when creating the payment intent with stripe.paymentIntents.create()
const payment = await stripe.paymentIntents.create(
{
amount,
currency,
customer,
Payment_method, //payment method when creating the payment intent
off_session: false,
confirm: true,
confirmation_method: 'manual',
},
{ idempotencyKey }
);
Since your sample is missing the payment method, it could explain the error you are receiving, as the PaymentIntent is being created without a payment method. I recommend following the guide to cover all the required steps to avoid further errors that might be present. You can also see the full sample code, which is documented and can be customized for your use case and the flutter_stripe library.

Flutter how to add billing address with Stripe?

I am trying to learn how to (and best practices) to integrate Stripe into my mobile app.
I know from another post (Why there is no billing address in stripe Checkout) that Stripe has deprecated Billing Address Support however, I'd still want to be able to add that functionality into my app.
Currently the code I have is:
Future<void> createPaymentMethod(BuildContext context,
Map<String, String> billingAddress, String name, String phoneNumber) async {
StripePayment.setStripeAccount(null);
// Here to add the credit Card
PaymentMethod paymentMethod = PaymentMethod();
paymentMethod = await StripePayment.paymentRequestWithCardForm(
CardFormPaymentRequest(),
).then((PaymentMethod paymentMethod) {
paymentMethod.billingDetails = BillingDetails.fromJson({
'address': billingAddress,
'name': name,
'phone': phoneNumber,
});
return paymentMethod;
}).catchError((e) {
print('Error Card: ${e.toString()}');
});
paymentMethod != null
? processPaymentAsDirectCharge(paymentMethod,
context)
: AwesomeDialog(
context: context,
title: 'Uh oh! A wild error has appeared!',
desc:
'Seems like we cant process this card. Please double check your input or try a different card',
animType: AnimType.SCALE,
dialogType: DialogType.WARNING,
btnOkOnPress: () {})
.show();
}
Where I have a button that does:
onPressed: () {
createPaymentMethod(
context,
{
'city': cityController.text,
'line1': streetAddressController.text,
'postal_code': zipcodeController.text, // **postal_code does not show up for some reason**
'state': stateController.text
},
fullNameController.text,
'8007897890');
}
And What I got back from the paymentMethod in my console is:
paymentMethod: {
created: 1599242290.0,
id: pm_someIdHereThatGotReplacedByThis,
livemode: false,
type: card,
billingDetails: {name: John Doe,
phone: phoneNumber,
address: {city: Doggo Town, line1: 555 Puppy Street, state: CA}},
card: {addressLine1: null, addressLine2: null, brand: visa, country: US, expMonth: 4,
expYear: 2024, funding: credit, last4: 4242}}
However, in my Logs in Stripe it shows:
{
"id": "pm_someIdHereThatGotReplacedByThis",
"object": "payment_method",
"billing_details": {
"address": {
"city": null,
"country": "US",
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"email": null,
"name": null,
"phone": null
},
"card": {
"brand": "visa",
"checks": {
"address_line1_check": null,
"address_postal_code_check": null,
"cvc_check": null
},
"country": "US",
"exp_month": 4,
"exp_year": 2024,
"funding": "credit",
"generated_from": null,
"last4": "4242",
"networks": {
"available": [
"visa"
],
"preferred": null
},
"three_d_secure_usage": {
"supported": true
},
"wallet": null
},
"created": 1599240880,
"customer": null,
"livemode": false,
"metadata": {
},
"type": "card"
}
my question is:
How do I setup my function so that the "checks" and "billing_details" fields will be filled with the information provided by the customer? Should I be adding something to the function
paymentMethod = await StripePayment.paymentRequestWithCardForm(
CardFormPaymentRequest()).then(...)
This is the field I am talking about:
"checks": {
"address_line1_check": null,
"address_postal_code_check": null,
"cvc_check": null
},
"billing_details": {
"address": {
"city": null,
"country": "US",
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"email": null,
"name": null,
"phone": null
},
Thanks