TR Payment Hub
Unified Turkish payment gateway integration for Flutter/Dart applications.
Supported Providers
| Provider | Status | Non-3DS | 3DS | Installments | Refunds |
|---|---|---|---|---|---|
| iyzico | ✅ Stable | Yes | Yes | Yes | Yes |
| PayTR | ✅ Stable | Yes | Yes | Yes | Yes |
| Param | 🔜 Planned | - | - | - | - |
| Sipay | 🔜 Planned | - | - | - | - |
Features
- Unified API - Single interface for all payment providers
- Type Safe - Full Dart null safety support
- Secure - Automatic sensitive data masking with LogSanitizer
- Testable - Built-in MockPaymentProvider for unit testing
- Cross Platform - Works on iOS, Android, Web, and Desktop
Installation
Add to your pubspec.yaml:
dependencies:
tr_payment_hub: ^1.0.2
Then run:
dart pub get
Quick Start
1. Create Provider
import 'package:tr_payment_hub/tr_payment_hub.dart';
// iyzico
final provider = TrPaymentHub.create(ProviderType.iyzico);
// PayTR
final provider = TrPaymentHub.create(ProviderType.paytr);
// Mock (for testing)
final provider = TrPaymentHub.createMock(shouldSucceed: true);
2. Initialize with Config
// iyzico Configuration
final config = IyzicoConfig(
merchantId: 'YOUR_MERCHANT_ID',
apiKey: 'YOUR_API_KEY',
secretKey: 'YOUR_SECRET_KEY',
isSandbox: true, // false for production
);
// PayTR Configuration
final config = PayTRConfig(
merchantId: 'YOUR_MERCHANT_ID',
apiKey: 'YOUR_MERCHANT_KEY',
secretKey: 'YOUR_MERCHANT_SALT',
successUrl: 'https://yoursite.com/success',
failUrl: 'https://yoursite.com/fail',
callbackUrl: 'https://yoursite.com/callback',
isSandbox: true,
);
await provider.initialize(config);
3. Create Payment
final request = PaymentRequest(
orderId: 'ORDER_123',
amount: 100.0,
currency: Currency.tryLira,
installment: 1,
card: CardInfo(
cardHolderName: 'John Doe',
cardNumber: '5528790000000008',
expireMonth: '12',
expireYear: '2030',
cvc: '123',
),
buyer: BuyerInfo(
id: 'BUYER_1',
name: 'John',
surname: 'Doe',
email: 'john@example.com',
phone: '+905551234567',
ip: '127.0.0.1',
city: 'Istanbul',
country: 'Turkey',
address: 'Test Address',
),
basketItems: [
BasketItem(
id: 'ITEM_1',
name: 'Product',
category: 'Category',
price: 100.0,
itemType: ItemType.physical,
),
],
);
try {
final result = await provider.createPayment(request);
if (result.isSuccess) {
print('Payment successful! ID: ${result.transactionId}');
}
} on PaymentException catch (e) {
print('Payment failed: ${e.message}');
}
4. 3D Secure Payment
// Step 1: Initialize 3DS
final threeDSResult = await provider.init3DSPayment(
request.copyWith(callbackUrl: 'https://yoursite.com/3ds-callback'),
);
if (threeDSResult.needsWebView) {
// Step 2: Display in WebView
// iyzico: Use threeDSResult.htmlContent
// PayTR: Redirect to threeDSResult.redirectUrl
}
// Step 3: Complete after callback
final result = await provider.complete3DSPayment(
threeDSResult.transactionId!,
callbackData: receivedCallbackData,
);
5. Query Installments
final installments = await provider.getInstallments(
binNumber: '552879', // First 6 digits of card
amount: 1000.0,
);
print('Bank: ${installments.bankName}');
for (final option in installments.options) {
print('${option.installmentNumber}x: ${option.totalPrice} TL');
}
6. Process Refund
final refundResult = await provider.refund(RefundRequest(
transactionId: 'ORIGINAL_TRANSACTION_ID',
amount: 50.0, // Partial refund
));
if (refundResult.isSuccess) {
print('Refund successful!');
}
Error Handling
try {
await provider.createPayment(request);
} on PaymentException catch (e) {
switch (e.code) {
case 'insufficient_funds':
// Handle insufficient balance
break;
case 'invalid_card':
// Handle invalid card
break;
case 'expired_card':
// Handle expired card
break;
case 'threeds_failed':
// Handle 3DS failure
break;
default:
print('Error: ${e.message}');
}
}
Testing
// Create mock provider
final mockProvider = TrPaymentHub.createMock(
shouldSucceed: true,
delay: Duration(milliseconds: 100),
);
// Test failure scenarios
final failingProvider = TrPaymentHub.createMock(
shouldSucceed: false,
customError: PaymentException.insufficientFunds(),
);
Security Best Practices
- Card numbers are never logged
- Use
LogSanitizer.sanitize()before logging any payment data - Always use HTTPS callback URLs
- Store API keys securely (environment variables, secure storage)
// Safe logging
final safeLog = LogSanitizer.sanitize(sensitiveData);
final safeMap = LogSanitizer.sanitizeMap(requestData);
Flutter Web Notice
Turkish payment APIs have CORS restrictions. For Flutter Web:
- Use a backend proxy (recommended)
- Route through Cloud Functions
- Or use mobile platforms only
API Reference
| Method | Description |
|---|---|
initialize(config) |
Initialize the provider |
createPayment(request) |
Process non-3DS payment |
init3DSPayment(request) |
Start 3DS payment flow |
complete3DSPayment(id) |
Complete 3DS payment |
getInstallments(bin, amount) |
Get installment options |
refund(request) |
Process refund |
getPaymentStatus(id) |
Check payment status |
dispose() |
Clean up resources |
Contributing
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing) - Open a Pull Request
License
MIT License - see LICENSE for details.
Contact
- GitHub Issues: Report Issue
- Email: dev.abdullahtas@gmail.com
Note: This is a community package, not an official iyzico or PayTR product.
Libraries
- tr_payment_hub
- Turkish Payment Gateway Integration Library