Overview

Payment providers are the backbone of FundKit. Each provider represents a different payment service (like HoneyCoin, EasyPay, or Tola) with its own API, authentication, and capabilities. FundKit abstracts these differences behind a unified interface.
Think of providers as different payment “channels” - each with their own strengths, coverage areas, and supported features. FundKit lets you use them all through one consistent API.

Provider Architecture

BaseProvider Class

All payment providers extend the BaseProvider class, ensuring consistent behavior:
import { BaseProvider } from '@fundkit/core';

abstract class BaseProvider {
  abstract collection(transaction: Transaction): Promise<CollectionResponse>;
  abstract getTransaction(txId: string): Promise<TransactionStatus>;
  abstract validateTransaction(transaction: Transaction): Promise<boolean>;

  // Common functionality
  getName(): string;
  getCapabilities(): ProviderCapabilities;
  isHealthy(): Promise<boolean>;
}

Provider Lifecycle

1

Initialization

Provider is configured with API credentials and settings
const honeycoin = new HoneyCoin({
  apiKey: 'your_api_key',
  publicKey: 'your_public_key'
});
2

Registration

Provider is added to PaymentClient
const client = new PaymentClient({
  providers: [honeycoin, easypay, tola]
});
3

Health Check

FundKit periodically checks provider health and availability
4

Selection

PaymentClient selects the best provider for each transaction
5

Execution

Transaction is sent to the selected provider

Supported Providers

HoneyCoin

Coverage: Uganda, Kenya, Tanzania
Specialties: Mobile money, multi-country support
import { HoneyCoin } from '@fundkit/honeycoin';

const honeycoin = new HoneyCoin({
  apiKey: process.env.HONEYCOIN_API_KEY!,
  publicKey: process.env.HONEYCOIN_PUBLIC_KEY!,
  environment: 'sandbox', // or 'production'
});
Capabilities:
  • Collections (charge customers)
  • Payouts (send money)
  • Status checking
  • Webhook notifications
  • Multi-currency (UGX, KES, TZS)
  • Multiple operators (MTN, Airtel, Safaricom)
Limits:
  • Minimum: 500 UGX / 50 KES / 1000 TZS
  • Maximum: 10,000,000 UGX / 1,000,000 KES / 20,000,000 TZS

EasyPay

Coverage: Uganda
Specialties: Fast processing, webhook support
import { EasyPay } from '@fundkit/easypay';

const easypay = new EasyPay({
  apiKey: process.env.EASYPAY_SECRET!,
  clientId: process.env.EASYPAY_CLIENT_ID!,
  environment: 'sandbox',
});
Capabilities:
  • Collections
  • Real-time webhooks
  • Fast processing (< 30 seconds)
  • MTN and Airtel support
  • Payouts (coming soon)
Limits:
  • Minimum: 1,000 UGX
  • Maximum: 5,000,000 UGX

Tola

Coverage: Uganda
Specialties: Banking integration, reconciliation
import { Tola } from '@fundkit/tola';

const tola = new Tola({
  apiKey: process.env.TOLA_API_KEY!,
  merchantId: process.env.TOLA_MERCHANT_ID!,
  environment: 'sandbox',
});
Capabilities:
  • Collections
  • Payouts
  • Bank transfers
  • Transaction reconciliation
  • Detailed reporting
  • Multiple payment methods
Limits:
  • Minimum: 500 UGX
  • Maximum: 20,000,000 UGX

Provider Configuration

Basic Configuration

Each provider requires specific configuration:
const honeycoin = new HoneyCoin({
  apiKey: 'your_api_key',        // Required
  publicKey: 'your_public_key',  // Required
  environment: 'sandbox',       // 'sandbox' | 'production'
  timeout: 30000,               // Request timeout (ms)
  retries: 3                    // Retry attempts
});

Advanced Configuration

const honeycoin = new HoneyCoin({
  apiKey: process.env.HONEYCOIN_API_KEY!,
  publicKey: process.env.HONEYCOIN_PUBLIC_KEY!,
  environment: 'production',

  // Advanced options
  timeout: 45000,
  retries: 5,
  retryDelay: 2000,

  // Rate limiting
  rateLimit: {
    requests: 100,
    window: 60000, // Per minute
  },

  // Custom headers
  headers: {
    'User-Agent': 'MyApp/1.0',
    'X-Custom-Header': 'value',
  },

  // Webhook configuration
  webhook: {
    url: 'https://api.myapp.com/webhooks/honeycoin',
    secret: 'webhook_secret_key',
    events: ['transaction.completed', 'transaction.failed'],
  },

  // Logging
  logger: customLogger,
  logLevel: 'debug',
});

Provider Selection Strategies

Smart Selection (Default)

FundKit automatically selects the best provider based on multiple factors:
const client = new PaymentClient({
  providers: [honeycoin, easypay, tola],
  strategy: 'smart', // Default
});

// FundKit will automatically choose the best provider
const result = await client.collection(transaction);
Selection Criteria:
  1. Currency Support - Does the provider support this currency?
  2. Amount Limits - Can the provider handle this transaction amount?
  3. Operator Support - Does the provider support this mobile operator?
  4. Provider Health - Is the provider currently healthy?
  5. Success Rate - Historical success rate for similar transactions
  6. Response Time - Average response time
  7. Fees - Transaction fees (if optimization enabled)

Round Robin

Distribute transactions evenly across providers:
const client = new PaymentClient({
  providers: [honeycoin, easypay, tola],
  strategy: 'round-robin',
});

// First transaction -> HoneyCoin
// Second transaction -> EasyPay
// Third transaction -> Tola
// Fourth transaction -> HoneyCoin (cycles back)

Priority-Based

Use providers in order of preference:
const client = new PaymentClient({
  providers: [
    { provider: honeycoin, priority: 1 }, // Try first
    { provider: easypay, priority: 2 }, // Try second
    { provider: tola, priority: 3 }, // Try last
  ],
  strategy: 'priority',
});

Manual Selection

Override automatic selection for specific transactions:
// Force use of specific provider
const result = await client.collection(transaction, {
  preferredProvider: 'easypay',
});

// Exclude certain providers
const result = await client.collection(transaction, {
  excludeProviders: ['tola'],
});

Provider Health Monitoring

FundKit continuously monitors provider health:

Health Metrics

// Check provider health
const health = await honeycoin.getHealth();

console.log(health);
// {
//   status: 'healthy',
//   uptime: 99.9,
//   responseTime: 1200,
//   successRate: 98.5,
//   lastCheck: '2024-01-15T10:30:00Z',
//   errors: []
// }

Health States

Provider is functioning normally:
  • Response time < 5 seconds
  • Success rate > 95%
  • No recent errors
status: 'healthy'
Provider is working but with issues:
  • Response time 5-15 seconds
  • Success rate 85-95%
  • Some recent errors
status: 'degraded'
Provider has significant problems:
  • Response time > 15 seconds
  • Success rate < 85%
  • Multiple recent errors
status: 'unhealthy'
Provider is completely unavailable:
  • Connection timeouts
  • Authentication failures
  • Service unavailable responses
status: 'offline'

Health-Based Fallback

// Configure health-based fallback
const client = new PaymentClient({
  providers: [honeycoin, easypay, tola],
  fallbackStrategy: {
    enabled: true,
    healthThreshold: 'degraded', // Fall back if provider is degraded or worse
    maxFallbacks: 2, // Try up to 2 alternative providers
    fallbackDelay: 1000, // Wait 1 second between attempts
  },
});

Provider Capabilities

Querying Capabilities

// Check what a provider supports
const capabilities = honeycoin.getCapabilities();

console.log(capabilities);
// {
//   collections: true,
//   payouts: true,
//   currencies: ['UGX', 'KES', 'TZS'],
//   operators: ['mtn', 'airtel', 'safaricom'],
//   features: ['webhooks', 'status_check', 'refunds'],
//   limits: {
//     min: { UGX: 500, KES: 50, TZS: 1000 },
//     max: { UGX: 10000000, KES: 1000000, TZS: 20000000 }
//   }
// }

Capability-Based Selection

// Find providers that support specific features
const providers = client.getProvidersWithCapability('payouts');
const kenyaProviders = client.getProvidersForCurrency('KES');
const fastProviders = client.getProvidersByResponseTime('< 5s');

Provider Events

Monitor provider activities:
// Listen for provider events
honeycoin.on('request:started', request => {
  console.log('API request started:', request.url);
});

honeycoin.on('request:completed', (request, response) => {
  console.log('API request completed:', response.status);
});

honeycoin.on('request:failed', (request, error) => {
  console.error('API request failed:', error.message);
});

honeycoin.on('health:changed', (oldHealth, newHealth) => {
  console.log(`Health changed from ${oldHealth} to ${newHealth}`);
});

// PaymentClient also emits provider events
client.on('provider:selected', (provider, transaction) => {
  console.log(`Selected ${provider.getName()} for ${transaction.externalId}`);
});

client.on('provider:fallback', (fromProvider, toProvider, reason) => {
  console.log(`Falling back from ${fromProvider} to ${toProvider}: ${reason}`);
});

Best Practices

Use Multiple Providers

// Good: Multiple providers for redundancy
const client = new PaymentClient({
  providers: [honeycoin, easypay, tola]
});

Monitor Provider Health

// Good: Regular health checks
setInterval(async () => {
  for (const provider of providers) {
    const health = await provider.getHealth();
    if (health.status === 'unhealthy') {
      await notifyTeam(provider, health);
    }
  }
}, 300000); // Every 5 minutes

Secure Credential Storage

// Good: Use environment variables
const honeycoin = new HoneyCoin({
  apiKey: process.env.HONEYCOIN_API_KEY!,
  publicKey: process.env.HONEYCOIN_PUBLIC_KEY!
});

// Bad: Hardcoded credentials
// const honeycoin = new HoneyCoin({
//   apiKey: 'hc_123456789',
//   publicKey: 'pk_abcdefghi'
// });

Configure Webhooks

// Good: Use webhooks for real-time updates
const easypay = new EasyPay({
  apiKey: process.env.EASYPAY_SECRET!,
  clientId: process.env.EASYPAY_CLIENT_ID!,
  webhookUrl: 'https://api.myapp.com/webhooks/easypay'
});

Troubleshooting

// Check credentials are correct
try {
  const health = await provider.getHealth();
  console.log('Provider healthy:', health.status);
} catch (error) {
  if (error.code === 'AUTHENTICATION_FAILED') {
    console.error('Invalid API credentials');
    // Check environment variables
    // Verify credentials with provider
  }
}
// Increase timeout for slow providers
const honeycoin = new HoneyCoin({
  apiKey: process.env.HONEYCOIN_API_KEY!,
  publicKey: process.env.HONEYCOIN_PUBLIC_KEY!,
  timeout: 60000 // 60 seconds
});
// Handle rate limiting gracefully
try {
  const result = await provider.collection(transaction);
} catch (error) {
  if (error.code === 'RATE_LIMITED') {
    const retryAfter = error.details.retryAfter;
    await sleep(retryAfter * 1000);
    // Retry the request
  }
}

Next Steps