Issue Description
When attempting to process a card payment through the PayTabs Flutter SDK, I'm receiving a content type error.
Environment
- Flutter SDK : sdk: ^3.5.2
- PayTabs SDK version: flutter_paytabs_bridge: 2.7.0
- Platform: [iOS/Android]
- Device: Tested multiple device (both android and ios)
Steps to Reproduce
- Initialized payment with method "card payment"
- Set amount to 400.0
- Set eventId to 25
- Set country to SAR (Saudi Arabia)
- Used dummy/test card with following details
Card Number: 4000 0000 0000 0002
Exp date: 03/27
CVV:123
- Error getting : Payment failed with message: Request must be in JSON format with content type application/json
Code Snippet
`class PaymentService {
static Future initiatePayment({
required BuildContext context,
required double amount,
required int eventId,
String? cartDescription = "Event Payment",
String? packageId,
required String paymentMethod,
}) async {
print("Initiating payment with method: $paymentMethod, amount: $amount, eventId: $eventId");
final payTabsProvider = Provider.of<PayTabsProvider>(context, listen: false);
final completer = Completer<PaymentResult>();
try {
switch (paymentMethod.toLowerCase()) {
case 'apple pay':
payTabsProvider.payWithApple(context, amount, eventId, (event) {
print("Handling Apple Pay event: $event");
_handlePaymentEvent(event, completer, eventId);
});
break;
case 'card payment':
payTabsProvider.payWithCards(context, amount, eventId, (event) {
print("Handling Card payment event: $event");
_handlePaymentEvent(event, completer, eventId);
});
break;
case 'samsung pay':
payTabsProvider.payWithSamsung(context, amount, eventId, (event) {
print("Handling Samsung Pay event: $event");
_handlePaymentEvent(event, completer, eventId);
});
break;
default:
print("Unsupported payment method: $paymentMethod");
completer.complete(PaymentResult.failure('Unsupported payment method: $paymentMethod//'));
break;
}
} catch (e) {
print("Error in initiatePayment: $e");
completer.complete(PaymentResult.failure('Payment initiation failed: $e'));
}
return completer.future;
}
static void _handlePaymentEvent(Map<String, dynamic> event, Completer completer, int eventId) {
print("Processing payment event: $event");
var data = event['data'] ?? {};
String status = event['status']?.toString() ?? 'error';
bool isSuccess = status == 'success' && (data['isSuccess'] == true);
String transactionReference = data['transactionReference']?.toString() ?? 'Unknown';
String message = event['message']?.toString() ?? 'Unknown error';
if (isSuccess) {
print("Payment successful with transaction reference: $transactionReference");
completer.complete(PaymentResult.success(eventId, transactionReference));
} else {
print("Payment failed with message: $message");
completer.complete(PaymentResult.failure(message));
}
}
}`
`import 'package:flutter/material.dart';
import 'package:flutter_paytabs_bridge/BaseBillingShippingInfo.dart';
import 'package:flutter_paytabs_bridge/IOSThemeConfiguration.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkApms.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkConfigurationDetails.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkLocale.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkTokeniseType.dart';
import 'package:flutter_paytabs_bridge/flutter_paytabs_bridge.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
class PayTabsProvider with ChangeNotifier {
PaymentSdkConfigurationDetails generateConfig(BuildContext context, double amount) {
var billingDetails = BillingDetails(
"Test User",
"test@example.com",
"+966123456789",
"123 Test Street",
"SA",
"Riyadh",
"Riyadh",
"12345",
);
var profileId = dotenv.env['PAYTABS_PROFILE_ID'] ?? '';
var serverKey = dotenv.env['PAYTABS_SERVER_KEY'] ?? '';
var clientKey = dotenv.env['PAYTABS_CLIENT_KEY'] ?? '';
if (profileId.isEmpty || serverKey.isEmpty || clientKey.isEmpty) {
debugPrint("Error: Missing PayTabs credentials in .env file");
}
var configuration = PaymentSdkConfigurationDetails(
profileId: profileId,
serverKey: serverKey,
clientKey: clientKey,
cartId: "cart_${DateTime.now().millisecondsSinceEpoch}",
currencyCode: "SAR",
amount: amount,
screentTitle: "Halawaghala Payment",
showBillingInfo: true,
forceShippingInfo: false,
cartDescription: "Halawaghala Payment",
merchantName: "Halawaghala",
merchantApplePayIndentifier: "merchant.com.halawaghala.services",
samsungPayToken: "your_samsung_pay_token",
billingDetails: billingDetails,
tokeniseType: PaymentSdkTokeniseType.USER_OPTIONAL,
merchantCountryCode: "SA",
simplifyApplePayValidation: true,
alternativePaymentMethods: [PaymentSdkAPms.APPLE_PAY, PaymentSdkAPms.SAMSUNG_PAY],
locale: Localizations.localeOf(context).languageCode == "ar" ? PaymentSdkLocale.AR : PaymentSdkLocale.EN,
);
final theme = IOSThemeConfigurations();
theme.secondaryColor = "02652A";
theme.buttonColor = "02652A";
// Remove logoImage if the asset is missing to avoid errors
configuration.iOSThemeConfigurations = theme;
return configuration;
}
void payWithCards(BuildContext context, double amount, int eventId, Function(Map<String, dynamic>) onPaymentCallback) async {
try {
FlutterPaytabsBridge.startCardPayment(generateConfig(context, amount), (event) {
// Cast event to Map<String, dynamic>
final eventMap = event.cast<String, dynamic>();
onPaymentCallback(eventMap);
});
} catch (e) {
onPaymentCallback({'status': 'error', 'message': 'Payment initiation failed: $e'});
}
}
void payWithSamsung(BuildContext context, double amount, int eventId, Function(Map<String, dynamic>) onPaymentCallback) async {
try {
FlutterPaytabsBridge.startSamsungPayPayment(generateConfig(context, amount), (event) {
final eventMap = event.cast<String, dynamic>();
onPaymentCallback(eventMap);
});
} catch (e) {
onPaymentCallback({'status': 'error', 'message': 'Payment initiation failed: $e'});
}
}
void payWithApple(BuildContext context, double amount, int eventId, Function(Map<String, dynamic>) onPaymentCallback) async {
try {
FlutterPaytabsBridge.startApplePayPayment(generateConfig(context, amount), (event) {
final eventMap = event.cast<String, dynamic>();
onPaymentCallback(eventMap);
});
} catch (e) {
onPaymentCallback({'status': 'error', 'message': 'Payment initiation failed: $e'});
}
}
void initializePayTabs() {
}
}`
`class PaymentResult {
final bool isSuccess;
final bool isCancelled;
final String message;
final int? eventId;
final String? details;
PaymentResult._({
required this.isSuccess,
required this.isCancelled,
required this.message,
this.eventId,
this.details,
});
factory PaymentResult.success(int eventId, String details) {
return PaymentResult._(
isSuccess: true,
isCancelled: false,
message: "Payment Successful!",
eventId: eventId,
details: details,
);
}
factory PaymentResult.failure(String message) {
return PaymentResult._(
isSuccess: false,
isCancelled: false,
message: message,
);
}
factory PaymentResult.cancelled(String message) {
return PaymentResult._(
isSuccess: false,
isCancelled: true,
message: message,
);
}
}`
`import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:hala_wa_ghala/screens/checkout/components/payment_result.dart';
import 'package:hala_wa_ghala/res/widgets/custom_snack_bar.dart';
import 'dart:io' show Platform;
import '../../../data/manager/payment_manager.dart';
class PaymentType {
final String title;
final String svgAsset;
final double iconSize;
final bool enabled;
final VoidCallback? onTap;
PaymentType({
required this.title,
required this.svgAsset,
this.iconSize = 24.0,
this.enabled = true,
this.onTap,
});
static List getPaymentTypes(BuildContext context, double amount, int eventId, Function(PaymentResult) onPaymentResult) {
bool isIOS = Platform.isIOS;
bool isAndroid = Platform.isAndroid;
return [
PaymentType(
title: AppLocalizations.of(context)!.payApple,
svgAsset: 'assets/images/applepay.svg',
iconSize: 30,
enabled: isIOS,
onTap: isIOS
? () {
Navigator.pop(context);
_handleApplePay(context, amount, eventId, onPaymentResult);
}
: null,
),
PaymentType(
title: AppLocalizations.of(context)!.cardPayment,
svgAsset: 'assets/images/card.svg',
onTap: () {
Navigator.pop(context);
_handleCardPayment(context, amount, eventId, onPaymentResult);
},
),
PaymentType(
title: AppLocalizations.of(context)!.samsungPay,
svgAsset: 'assets/images/samsung_pay.svg',
iconSize: 25,
enabled: isAndroid,
onTap: isAndroid
? () {
Navigator.pop(context);
_handleSamsungPay(context, amount, eventId, onPaymentResult);
}
: null,
),
];
}
static void _handleApplePay(BuildContext context, double amount, int eventId, Function(PaymentResult) onPaymentResult) async {
try {
final result = await PaymentService.initiatePayment(
context: context,
amount: amount,
eventId: eventId,
paymentMethod: 'apple pay',
);
_handlePaymentResult( result, amount);
onPaymentResult(result);
} catch (e) {
final failureResult = PaymentResult.failure("Apple Pay failed: $e");
_handlePaymentResult( failureResult, amount);
onPaymentResult(failureResult);
}
}
static void _handleCardPayment(BuildContext context, double amount, int eventId, Function(PaymentResult) onPaymentResult) async {
try {
final result = await PaymentService.initiatePayment(
context: context,
amount: amount,
eventId: eventId,
paymentMethod: 'card payment',
);
_handlePaymentResult( result, amount);
onPaymentResult(result);
} catch (e) {
final failureResult = PaymentResult.failure("Card Payment failed: $e");
_handlePaymentResult( failureResult, amount);
onPaymentResult(failureResult);
}
}
static void _handleSamsungPay(BuildContext context, double amount, int eventId, Function(PaymentResult) onPaymentResult) async {
try {
final result = await PaymentService.initiatePayment(
context: context,
amount: amount,
eventId: eventId,
paymentMethod: 'samsung pay',
);
_handlePaymentResult( result, amount);
onPaymentResult(result);
} catch (e) {
final failureResult = PaymentResult.failure("Samsung Pay failed: $e");
_handlePaymentResult( failureResult, amount);
onPaymentResult(failureResult);
}
}
static void _handlePaymentResult( PaymentResult result, double amount) {
if (result.isSuccess) {
SnackBarUtils.showSuccess(result.message);
} else {
SnackBarUtils.showError(result.message);
}
}
}`
Iam also tried your example code with same credentials getting same error with Saudi Arabia
Issue Description
When attempting to process a card payment through the PayTabs Flutter SDK, I'm receiving a content type error.
Environment
Steps to Reproduce
Card Number: 4000 0000 0000 0002
Exp date: 03/27
CVV:123
Code Snippet
`class PaymentService {
static Future initiatePayment({
required BuildContext context,
required double amount,
required int eventId,
String? cartDescription = "Event Payment",
String? packageId,
required String paymentMethod,
}) async {
}
static void _handlePaymentEvent(Map<String, dynamic> event, Completer completer, int eventId) {
print("Processing payment event: $event");
}
}`
`import 'package:flutter/material.dart';
import 'package:flutter_paytabs_bridge/BaseBillingShippingInfo.dart';
import 'package:flutter_paytabs_bridge/IOSThemeConfiguration.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkApms.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkConfigurationDetails.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkLocale.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkTokeniseType.dart';
import 'package:flutter_paytabs_bridge/flutter_paytabs_bridge.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
class PayTabsProvider with ChangeNotifier {
PaymentSdkConfigurationDetails generateConfig(BuildContext context, double amount) {
var billingDetails = BillingDetails(
"Test User",
"test@example.com",
"+966123456789",
"123 Test Street",
"SA",
"Riyadh",
"Riyadh",
"12345",
);
}
void payWithCards(BuildContext context, double amount, int eventId, Function(Map<String, dynamic>) onPaymentCallback) async {
try {
FlutterPaytabsBridge.startCardPayment(generateConfig(context, amount), (event) {
// Cast event to Map<String, dynamic>
final eventMap = event.cast<String, dynamic>();
onPaymentCallback(eventMap);
});
} catch (e) {
onPaymentCallback({'status': 'error', 'message': 'Payment initiation failed: $e'});
}
}
void payWithSamsung(BuildContext context, double amount, int eventId, Function(Map<String, dynamic>) onPaymentCallback) async {
try {
FlutterPaytabsBridge.startSamsungPayPayment(generateConfig(context, amount), (event) {
final eventMap = event.cast<String, dynamic>();
onPaymentCallback(eventMap);
});
} catch (e) {
onPaymentCallback({'status': 'error', 'message': 'Payment initiation failed: $e'});
}
}
void payWithApple(BuildContext context, double amount, int eventId, Function(Map<String, dynamic>) onPaymentCallback) async {
try {
FlutterPaytabsBridge.startApplePayPayment(generateConfig(context, amount), (event) {
final eventMap = event.cast<String, dynamic>();
onPaymentCallback(eventMap);
});
} catch (e) {
onPaymentCallback({'status': 'error', 'message': 'Payment initiation failed: $e'});
}
}
void initializePayTabs() {
}
}`
`class PaymentResult {
final bool isSuccess;
final bool isCancelled;
final String message;
final int? eventId;
final String? details;
PaymentResult._({
required this.isSuccess,
required this.isCancelled,
required this.message,
this.eventId,
this.details,
});
factory PaymentResult.success(int eventId, String details) {
return PaymentResult._(
isSuccess: true,
isCancelled: false,
message: "Payment Successful!",
eventId: eventId,
details: details,
);
}
factory PaymentResult.failure(String message) {
return PaymentResult._(
isSuccess: false,
isCancelled: false,
message: message,
);
}
factory PaymentResult.cancelled(String message) {
return PaymentResult._(
isSuccess: false,
isCancelled: true,
message: message,
);
}
}`
`import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:hala_wa_ghala/screens/checkout/components/payment_result.dart';
import 'package:hala_wa_ghala/res/widgets/custom_snack_bar.dart';
import 'dart:io' show Platform;
import '../../../data/manager/payment_manager.dart';
class PaymentType {
final String title;
final String svgAsset;
final double iconSize;
final bool enabled;
final VoidCallback? onTap;
PaymentType({
required this.title,
required this.svgAsset,
this.iconSize = 24.0,
this.enabled = true,
this.onTap,
});
static List getPaymentTypes(BuildContext context, double amount, int eventId, Function(PaymentResult) onPaymentResult) {
bool isIOS = Platform.isIOS;
bool isAndroid = Platform.isAndroid;
}
static void _handleApplePay(BuildContext context, double amount, int eventId, Function(PaymentResult) onPaymentResult) async {
try {
final result = await PaymentService.initiatePayment(
context: context,
amount: amount,
eventId: eventId,
paymentMethod: 'apple pay',
);
_handlePaymentResult( result, amount);
onPaymentResult(result);
} catch (e) {
final failureResult = PaymentResult.failure("Apple Pay failed: $e");
_handlePaymentResult( failureResult, amount);
onPaymentResult(failureResult);
}
}
static void _handleCardPayment(BuildContext context, double amount, int eventId, Function(PaymentResult) onPaymentResult) async {
try {
final result = await PaymentService.initiatePayment(
context: context,
amount: amount,
eventId: eventId,
paymentMethod: 'card payment',
);
_handlePaymentResult( result, amount);
onPaymentResult(result);
} catch (e) {
final failureResult = PaymentResult.failure("Card Payment failed: $e");
_handlePaymentResult( failureResult, amount);
onPaymentResult(failureResult);
}
}
static void _handleSamsungPay(BuildContext context, double amount, int eventId, Function(PaymentResult) onPaymentResult) async {
try {
final result = await PaymentService.initiatePayment(
context: context,
amount: amount,
eventId: eventId,
paymentMethod: 'samsung pay',
);
_handlePaymentResult( result, amount);
onPaymentResult(result);
} catch (e) {
final failureResult = PaymentResult.failure("Samsung Pay failed: $e");
_handlePaymentResult( failureResult, amount);
onPaymentResult(failureResult);
}
}
static void _handlePaymentResult( PaymentResult result, double amount) {
if (result.isSuccess) {
SnackBarUtils.showSuccess(result.message);
}
}`
Iam also tried your example code with same credentials getting same error with Saudi Arabia