XPay Element for Flutter is an embedded payment system that allows you to collect payments directly from users within your Flutter applications. This package is highly customizable, enabling you to tailor the appearance and functionalities of the payment form to align seamlessly with your app's style and theme.
Features
Seamless Payment Integration
Easily integrate payment functionalities into your Flutter app without redirecting users to external applications or pages.
Custom Styling
Style the payment SDK according to your app's theme with customizable labels, placeholders, and more.
Embedded Authentication
Conduct OTP authentication within your app, ensuring a smooth and secure user experience.
Event Handling
Utilize built-in events such as onBinDiscount and onReady to dynamically manage changes and validate inputs.
Getting started
To incorporate the XPay embedded payment system into your Flutter application, start by adding the following dependency to your pubspec.yaml file:
dependencies:
xpay_element_flutter_stage: ^3.6.0
Usage
To use the XPay SDK in your app, follow these steps:
Import the Package
import 'package:xpay_element_flutter_stage/xpay_element_flutter_stage.dart';
Initialize the Element Controller
Create an instance of XPayElementController with necessary credentials available on your XPay dashboard:
final XPayElementController controller = XPayElementController(
publicKey: "your_account_public_key",
hmacKey: "your_account_hmac_key",
accountId: "your_account_id"
);
Embed the Card Payment Widget
Integrate XPayElementWidget into your app's widget tree and configure it with the controller:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('XPay Payment Example')),
body: XPayElementWidget(controller: controller),
);
}
Embed the JazzCash Payment Widget
Integrate XPayJazzCashElementWidget into your app's widget tree and configure it with the controller:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('XPay Payment Example')),
body: XPayJazzCashElementWidget(controller: controller),
);
}
Embed the EasyPaisa Payment Widget
Integrate XPayEasyPaisaElementWidget into your app's widget tree and configure it with the controller:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('XPay Payment Example')),
body: XPayEasyPaisaElementWidget(controller: controller),
);
}
Embed the Google Pay Payment Widget
Integrate XPayGooglePayElementWidget into your app's widget tree and configure it with the controller:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('XPay Payment Example')),
body: XPayGooglePayElementWidget(controller: controller),
);
}
How to Integrate all or few payment elements
If you want to integrate all or few payment elements, you need to create separate instances of XPayElementController
with the necessary data and pass them to the relevant UI widget.
Custom Styling
Customize the SDK's appearance to seamlessly integrate with your app's style and theme. The XPay SDK allows you to modify elements' style and appearance, making it adaptable to various design requirements.
Initializing and Applying Custom Styles
Initialize XPayElementCustomStyle and pass custom style configurations to its constructor. Below is an example of how you can tailor the appearance of your payment elements:
For Credit/Debit Card (XPayElementWidget), pass the following inputConfiguration
:
"inputConfiguration": {
"cardNumber": {
"label": "Card Number",
"placeholder": "Enter card number"
},
"expiry": {"label": "Expiry Date", "placeholder": "MM/YY"},
"cvc": {"label": "CVC", "placeholder": "Enter cvc"}
}
For JazzCash Wallet (XPayJazzCashElementWidget), pass the following inputConfiguration
:
"inputConfiguration": {
"phoneNumber": {
"label": "Phone Number",
"placeholder": "0312-3456789"
},
"cnicNumber": {"label": "CNIC Number", "placeholder": "Enter cnic number"}
},
For EasyPaisa Wallet (XPayEasyPaisaElementWidget), pass the following inputConfiguration
:
"inputConfiguration": {
"phoneNumber": {
"label": "Phone Number",
"placeholder": "0312-3456789"
},
},
You can create a single constructor that includes inputConfiguration along with other styles to handle all element input configuration data and pass it to the widget. Alternatively, you can define separate constructors for each payment method. Below is a sample example of how you can configure and pass a custom style.
@override
XPayElementCustomStyle elementCustomStyle =
XPayElementCustomStyle.configureCustomStyle({
"inputConfiguration": {
"cardNumber": {
"label": "Card Number",
"placeholder": "Enter card number"
},
"expiry": {"label": "Expiry Date", "placeholder": "MM/YY"},
"cvc": {"label": "CVC", "placeholder": "Enter cvc"}
},
"inputStyle": {
"height": 40,
"textColor": 0xff000000,
"textSize": 16,
"fontWeight": 400,
"borderColor": 0xffe6e6e6,
"borderRadius": 5,
"borderWidth": 1
},
"inputLabelStyle": {
"textSize": 16,
"fontWeight": 400,
"textColor": 0xff000000
},
"onFocusInputStyle": {
"textColor": 0xff000000,
"textSize": 16,
"fontWeight": 400,
"borderColor": 0xffc8dbf9,
"borderWidth": 1
},
"invalidStyle": {
"borderColor": 0xffff0000,
"borderWidth": 1,
"textColor": 0xffff0000,
"textSize": 14,
"fontWeight": 400
},
"errorMessageStyle": {
"textColor": 0xffff0000,
"textSize": 14,
"fontWeight": 400
}
});
Applying the Custom Styles
After configuring your styles, apply them to the XPayElementWidget to enhance the user interface:
For Credit/Debit Card (XPayElementWidget)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Styled XPay Element')),
body: XPayElementWidget(style: elementCustomStyle, controller: controller)
);
}
For JazzCash Wallet (XPayJazzCashElementWidget)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Styled XPay Element')),
body: XPayJazzCashElementWidget(style: elementCustomStyle, controller: controller)
);
}
For EasyPaisa Wallet (XPayEasyPaisaElementWidget)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Styled XPay Element')),
body: XPayEasyPaisaElementWidget(style: elementCustomStyle, controller: controller)
);
}
The above styling properties are all optional; you can define only those you require, ensuring flexibility and customization according to your specific design needs.
Element Events
Handle element-specific events to enhance the user experience:
onReady Event
This event triggers when all form fields are valid and the form is ready for submission.
For Credit/Debit Card (XPayElementWidget)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Styled XPay Element')),
body: XPayElementWidget(
controller: controller,
onReady: (bool isReady) {
// Update your state to enable payment submission
},
)
);
}
For JazzCash Wallet (XPayJazzCashElementWidget)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Styled XPay Element')),
body: XPayJazzCashElementWidget(
controller: controller,
onReady: (bool isReady) {
// Update your state to enable payment submission
},
)
);
}
For EasyPaisa Wallet (XPayEasyPaisaElementWidget)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Styled XPay Element')),
body: XPayEasyPaisaElementWidget(
controller: controller,
onReady: (bool isReady) {
// Update your state to enable payment submission
},
)
);
}
For Google Pay (XPayGooglePayElementWidget)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Styled XPay Element')),
body: XPayGooglePayElementWidget(
controller: controller,
onReady: (bool isReady) {
// Update your state to enable payment submission
},
)
);
}
onBinDiscount
Receive data related to the card's BIN as the user inputs their card number, which can be used for implementing discounts or promotional offers.
Just for Credit/Debit Card (XPayElementWidget)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Styled XPay Element')),
body: XPayElementWidget(
controller: controller,
onBinDiscount: (dynamic binDiscountData) {
// Process and apply BIN-based discounts
},
)
);
}
Confirming Payment
To proceed with the payment confirmation when all form fields are valid and the onReady event has returned true, you should perform a few necessary steps. First, ensure you have initiated a server-side API call to create a payment intent. This create intent API is responsible for generating the clientSecret
and encryptionKey
, which are critical for securing the payment confirmation.
Server-Side Payment Intent Creation
Before invoking the payment confirmation on the client side, your backend should call the create intent API to obtain:
clientSecret
: A secret key used to initiate the payment process securely.
encryptionKey
: Used to encrypt sensitive information before it is transmitted.
Confirming the Payment
Once you have the necessary keys from your backend, use the XPayElementController initialized earlier to call the confirmPayment method. Here’s how you can implement this in your Flutter app:
void confirmPayment() async {
try {
// Assuming 'controller' is your instance of XPayElementController
var paymentResponse = await controller.confirmPayment(
customerName: "Customer Name",
clientSecret: "client_secret_from_intent_api",
encryptionKeys: "encryption_keys_from_intent_api"
);
if (paymentResponse.error) {
// Handle payment failure
print("Payment failed: ${paymentResponse.message}");
} else {
// Handle payment success
print("Payment successful: ${paymentResponse.message}");
}
} catch (e) {
// Handle exceptions
print("Payment Error: $e");
}
}
Note for Confirm Payment
If you have integrated more than one elements, call the confirmPayment
method with the relevant controller based on the customer's selected payment method.
Confirm Payment Response
The response from confirmPayment contains two keys:
error
: A boolean that indicates whether the payment was unsuccessful. If true, it means the payment failed.
message
: A string containing a message from the server. This message provides details about the payment outcome or error information.
Clean Method
The clear
method is used to reset the payment form. This is especially useful if you have a button designed to clear the form or reset the checkout process.
// Assuming 'controller' is your instance of XPayElementController
controller.clear();
Get Form Ready Status Using Controller
The isReady
method is used to check the form field status. If all fields are filled with valid data, it returns true
, allowing the payment button to be enabled. Otherwise, it returns false
.
// Assuming 'controller' is your instance of XPayElementController
controller.isReady();