Custom Payment UI Implementation
info
- View Custom example for the full example
Unified config for Moyasar API
final paymentConfig = PaymentConfig(
publishableApiKey: 'YOUR_API_KEY',
amount: 25758, // SAR 257.58
description: 'order #1324',
metadata: {'size': '250g'},
creditCard: CreditCardConfig(saveCard: true, manual: false),
applePay: ApplePayConfig(
merchantId: 'YOUR_MERCHANT_ID',
label: 'YOUR_STORE_NAME',
manual: false,
saveCard: false),
samsungPay: SamsungPayConfig(
serviceId: 'YOUR_SAMSUNG_SERVICE_ID',
merchantName: 'YOUR_STORE_NAME'),
);
1. Custom applePay UI
- Callback once the user clicks on the custom Apple Pay widget
void onSubmitApplePay(applePay) async {
final source = ApplePayPaymentRequestSource(
applePay['token'],
paymentConfig.applePay!.manual,
paymentConfig.applePay!.saveCard);
final paymentRequest = PaymentRequest(paymentConfig, source);
final result = await Moyasar.pay(
apiKey: paymentConfig.publishableApiKey,
paymentRequest: paymentRequest);
onPaymentResult(result);
}
2. Custom Credit Card UI
- Callback once the user fills & submit their CC information using the custom form widget
void onSubmitCcForm() async {
final source = CardPaymentRequestSource(
creditCardData: CardFormModel(
name: 'John Doe',
number: '4111111111111111',
cvc: '123',
month: '05',
year: '2027'),
tokenizeCard: paymentConfig.creditCard!.saveCard,
manualPayment: paymentConfig.creditCard!.manual);
final paymentRequest = PaymentRequest(paymentConfig, source);
final result = await Moyasar.pay(
apiKey: paymentConfig.publishableApiKey,
paymentRequest: paymentRequest);
onPaymentResult(result);
}
note
With a custom Credit Card UI, handling the 3DS step is your responsibility. When status is initiated, open (result.source as CardPaymentResponseSource).transactionUrl in a web view and watch for the redirect to PaymentConfig.callbackUrl.
3. Custom Samsung Pay UI
- Callback once the Samsung Pay SDK returns a payment token
void onSubmitSamsungPay(String token, String orderNumber) async {
final source = SamsungPayPaymentRequestSource(
samsungPayToken: token,
manualPayment: paymentConfig.samsungPay!.manual,
);
final paymentRequest = PaymentRequest(
paymentConfig,
source,
additionalMetadata: {'samsungpay_order_id': orderNumber},
);
final result = await Moyasar.pay(
apiKey: paymentConfig.publishableApiKey,
paymentRequest: paymentRequest);
onPaymentResult(result);
}
4. Custom STC UI
// STC Pay Implementation
String? transactionUrl; // Store this as a class variable
final phoneController = TextEditingController();
final otpController = TextEditingController();
// Callback when user submits their mobile number for STC Pay
void onSubmitStcPay() async {
final source = StcRequestSource(
mobile: phoneController.text,
);
final paymentRequest = PaymentRequest(paymentConfig, source);
final result = await Moyasar.pay(
apiKey: paymentConfig.publishableApiKey,
paymentRequest: paymentRequest,
);
if (result is PaymentResponse && result.status == PaymentStatus.initiated) {
final stcResponse = result.source as StcResponseSource;
setState(() {
transactionUrl = stcResponse.transactionUrl;
});
} else {
// Handle error
}
}
// Callback when user submits OTP for STC Pay
void onSubmitStcOtp() async {
if (transactionUrl == null) return;
final otpRequest = OtpRequestSource(
otpValue: otpController.text,
);
final result = await Moyasar.verifyOTP(
transactionURL: transactionUrl!,
otpRequest: otpRequest,
);
onPaymentResult(result);
}
Handling onPaymentResult
- Unified payment result processor
void onPaymentResult(result) {
if (result is PaymentResponse) {
switch (result.status) {
case PaymentStatus.initiated:
// handle 3DS redirection / awaiting OTP.
break;
case PaymentStatus.paid:
// handle success.
break;
case PaymentStatus.authorized:
case PaymentStatus.captured:
// manual capture flow.
break;
case PaymentStatus.failed:
// handle failure.
break;
}
return;
}
// Otherwise the result is an error.
if (result is PaymentCanceledError) {
// The user dismissed the payment sheet.
} else if (result is ValidationError) {
// Invalid request data — inspect result.errors.
} else if (result is NetworkError || result is TimeoutError) {
// Connectivity problem; the user can retry.
}
}
Error types
| Type | Meaning |
|---|---|
PaymentCanceledError | The user dismissed the payment sheet. |
UnprocessableTokenError | The wallet returned an empty or unusable token. |
ValidationError | Invalid request data. Has message and errors. |
AuthError | The publishable API key was rejected. |
ApiError | Moyasar returned a server-side error. |
NetworkError | The request never reached the API. |
TimeoutError | The request timed out. |
UnspecifiedError | Anything else. |