Skip to main content

STC Pay Integration Guide

This guide will walk you through integrating STC Pay payments into your Flutter application using the Moyasar Flutter SDK.

Prerequisites

Before you begin, ensure you have:

  1. A Moyasar account with STC Pay enabled
  2. Your Moyasar publishable API key
  3. Flutter SDK installed (v2.0.17 or later)

Installation

Add the latest version of the moyasar package to your pubspec.yaml:

dependencies:
moyasar: ^3.0.5 # or the latest version

Then run:

flutter pub get

Implementation

1. Add the STCPay Widget

// Initialize payment config
final paymentConfig = PaymentConfig(
publishableApiKey: 'YOUR_PUBLISHABLE_API_KEY',
amount: 10000, // 100.00 SAR
description: 'Order #12345',
metadata: {'order_id': '12345'},
);

// In your widget
STCPay(
config: paymentConfig,
onPaymentResult: onPaymentResult,
locale: const Localization.ar(), // optional, defaults to English
)

// Payment result handler
void onPaymentResult(result) {
if (result is PaymentResponse) {
switch (result.status) {
case PaymentStatus.paid:
print('Payment successful: ${result.id}');
break;
case PaymentStatus.failed:
print('Payment failed: ${result.id}');
break;
case PaymentStatus.initiated:
print('Awaiting OTP: ${result.id}');
break;
default:
break;
}
}
}
Deprecated widget

STCPaymentComponent is deprecated and will be removed in the next major version. It is a drop-in rename:

- STCPaymentComponent(config: paymentConfig, onPaymentResult: onPaymentResult)
+ STCPay(config: paymentConfig, onPaymentResult: onPaymentResult)

Testing

Test Environment

  1. Use the sandbox environment for testing
  2. Enter a valid Saudi mobile number starting with 05
  3. For testing OTP:
    • Use 123456 for successful payment
    • Use 000000 for failed payment

Error Handling

Handle different payment statuses in your onPaymentResult callback:

void onPaymentResult(result) {
if (result is PaymentResponse) {
switch (result.status) {
case PaymentStatus.paid:
// Handle successful payment
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Payment successful!')),
);
break;
case PaymentStatus.failed:
// Handle failed payment. Details are on the source:
// (result.source as StcResponseSource).message
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Payment failed')),
);
break;
case PaymentStatus.initiated:
// Handle initiated state (waiting for OTP)
break;
default:
break;
}
return;
}

// Otherwise the result is one of the SDK error types.
if (result is ValidationError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${result.message}')),
);
} else if (result is NetworkError || result is TimeoutError) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Connection problem. Please try again.')),
);
}
}
note

onPaymentResult receives a dynamic value — either a PaymentResponse or one of the error types (ValidationError, AuthError, ApiError, NetworkError, TimeoutError, PaymentCanceledError, UnprocessableTokenError, UnspecifiedError). Always check the type before reading fields. Note that PaymentResponse itself has no message field — per-method details live on result.source.

Production Deployment

Before going live:

  1. Replace the test API key with your live publishable API key
  2. Test the complete payment flow with real STC Pay accounts
  3. Ensure you have proper error handling in place

Support

For any issues or questions, please contact Moyasar Support.