TR Payment Hub

Pub Version License: MIT Dart CI

Türkçe Dokümantasyon

Unified Turkish payment gateway integration for Flutter/Dart applications.

Supported Providers

Provider Status Non-3DS 3DS Installments Refunds Saved Cards
iyzico ✅ Stable Yes Yes Yes Yes Yes
PayTR ✅ Stable Yes Yes Yes Yes No
Param ✅ Stable Yes Yes Yes Yes No
Sipay ✅ Stable Yes Yes Yes Yes Yes

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
  • Saved Cards - Card tokenization support (iyzico, Sipay)

Installation

Add to your pubspec.yaml:

dependencies:
  tr_payment_hub: ^1.0.3

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);

// Param
final provider = TrPaymentHub.create(ProviderType.param);

// Sipay
final provider = TrPaymentHub.create(ProviderType.sipay);

// 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,
);

// Param Configuration
final config = ParamConfig(
  merchantId: 'YOUR_CLIENT_CODE',
  apiKey: 'YOUR_CLIENT_USERNAME',
  secretKey: 'YOUR_CLIENT_PASSWORD',
  guid: 'YOUR_GUID',
  isSandbox: true,
);

// Sipay Configuration
final config = SipayConfig(
  merchantId: 'YOUR_MERCHANT_ID',
  apiKey: 'YOUR_APP_KEY',
  secretKey: 'YOUR_APP_SECRET',
  merchantKey: 'YOUR_MERCHANT_KEY',
  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/Sipay: 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!');
}

7. Saved Cards (iyzico & Sipay)

// Get saved cards
final cards = await provider.getSavedCards('user_card_key');

// Charge with saved card
final result = await provider.chargeWithSavedCard(
  cardToken: cards.first.cardToken,
  orderId: 'ORDER_456',
  amount: 50.0,
  buyer: buyerInfo,
);

// Delete saved card
await provider.deleteSavedCard(cardToken: 'card_token');

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

Unit Tests with Mock Provider

// 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(),
);

Running Tests

# Run all unit tests
dart test

# Run with coverage
dart test --coverage=coverage

# Run integration tests (requires credentials)
export IYZICO_MERCHANT_ID=xxx
export IYZICO_API_KEY=xxx
export IYZICO_SECRET_KEY=xxx
dart test --tags=integration

Test Cards

Use these test card numbers in sandbox environments:

Provider Card Number Scenario
iyzico 5528790000000008 Success (MasterCard)
iyzico 5400010000000004 Success (MasterCard)
iyzico 4543590000000006 Insufficient Funds
iyzico 4059030000000009 3DS Required
PayTR 4355084355084358 Success
PayTR 5571135571135575 Success (MasterCard)
Sipay 4508034508034509 Success
Param 4022774022774026 Success

Test CVV: 000 or 123 Test Expiry: Any future date (e.g., 12/2030)

Sandbox Environments

Provider Sandbox URL Documentation
iyzico sandbox-api.iyzipay.com dev.iyzipay.com
PayTR www.paytr.com dev.paytr.com
Sipay sandbox.sipay.com.tr apidocs.sipay.com.tr
Param test-dmz.param.com.tr dev.param.com.tr

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:

  1. Use a backend proxy (recommended)
  2. Route through Cloud Functions
  3. 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
chargeWithSavedCard(...) Pay with saved card
getSavedCards(userKey) List saved cards
deleteSavedCard(token) Remove saved card
dispose() Clean up resources

Contributing

  1. Fork the repository
  2. Create feature branch (git checkout -b feature/amazing)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing)
  5. Open a Pull Request

License

MIT License - see LICENSE for details.

Contact


Note: This is a community package, not an official iyzico, PayTR, Param, or Sipay product.

Libraries

tr_payment_hub
Turkish Payment Gateway Integration Library