Use the XPay Flutter SDK to render XPay-hosted payment fields in a Flutter application and confirm a PaymentIntent created by your backend.
Outcome
By the end of this guide, your application will:
- render a card payment form;
- enable payment submission only when all required fields are valid; and
- confirm a PaymentIntent with values returned by your backend.
Install the SDK
Use the package for the environment your application connects to.
For production:
dependencies:
xpay_element_flutter: 7.0.5For staging:
dependencies:
xpay_element_flutter_stage: 7.0.7Import the corresponding package:
// Production
import 'package:xpay_element_flutter/xpay_element_flutter.dart';
// Staging
import 'package:xpay_element_flutter_stage/xpay_element_flutter_stage.dart';ℹ️ Flutter SDK 7.x no longer accepts
hmacKey. Remove that argument when upgrading from an earlier Flutter SDK version.
Initialize the controller
Create one XPayElementController for the payment element. Use the public key and account ID for the same environment as the installed package.
final XPayElementController controller = XPayElementController(
publicKey: "{{publishable_key}}",
accountId: "{{account_id}}",
enableBackButtonOnIframe: false,
);Keep enableBackButtonOnIframe disabled unless the checkout requires the device back button to close the authentication screen.
Render the payment element
Render a card form with XPayElementWidget:
class CheckoutPage extends StatefulWidget {
const CheckoutPage({super.key});
@override
State<CheckoutPage> createState() => _CheckoutPageState();
}
class _CheckoutPageState extends State<CheckoutPage> {
bool isReady = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
XPayElementWidget(
controller: controller,
onReady: (bool ready) {
setState(() => isReady = ready);
},
),
ElevatedButton(
onPressed: isReady ? confirmPayment : null,
child: const Text('Pay now'),
),
],
),
);
}
}onReady reports the current form-validity state. A value of true means all required fields contain valid input and the payment button can be enabled.
To let the SDK display every payment method enabled for the merchant account, use XPayElementWidget with showAllPaymentMethods: true. To control placement separately, use the method-specific widgets and a separate controller for each one:
XPayJazzCashElementWidgetXPayEasyPaisaElementWidgetXPayGooglePayElementWidgetXPayRaastRTPElementWidgetXPayRaastDQRElementWidgetXPayBaadmayElementWidget
Confirm the payment
First, create a PaymentIntent on the merchant backend. Return its client secret and encryption keys to the application, then call confirmPayment with the controller for the selected payment method.
Future<void> confirmPayment() async {
final paymentResponse = await controller.confirmPayment(
customerName: "Customer Name",
clientSecret: "{{pi_client_secret}}",
encryptionKeys: "{{encryption_keys}}",
);
if (paymentResponse.error) {
// Display paymentResponse.message and allow the customer to recover.
return;
}
// Show the submitted result while the backend verifies the webhook outcome.
}The response includes error, message, and status. Treat it as the client submission result. Use payment webhook events to reconcile the final payment outcome on the merchant backend.
If showNameField: true is enabled on the card widget, the SDK uses the entered cardholder name and customerName doesn't need to be passed to confirmPayment. Otherwise, customerName is required for card payments.
Reset the form
Use clear when the customer needs to restart payment entry:
controller.clear();What to do next
Use the confirmed Flutter flow with XPay test payment details, then review the PaymentIntent lifecycle before handling production outcomes. Complete endpoint schemas remain in the XPay API reference.
To charge an existing token through customer authentication, follow Authenticate a saved card with 3DS.