Overview

The PaymentClient is the central orchestrator in FundKit. It manages multiple payment providers, handles smart provider selection, validates transactions, and provides a unified interface for all payment operations.
Think of PaymentClient as your payment conductor - it knows which providers are available, their capabilities, and automatically routes transactions to the best provider for each situation.

Basic Usage

import { PaymentClient } from '@fundkit/core';
import { HoneyCoin } from '@fundkit/honeycoin';
import { EasyPay } from '@fundkit/easypay';

const client = new PaymentClient({
  apiKey: process.env.FUNDKIT_API_KEY!,
  providers: [
    new HoneyCoin({
      apiKey: process.env.HONEYCOIN_API_KEY!,
      publicKey: process.env.HONEYCOIN_PUBLIC_KEY!,
    }),
    new EasyPay({
      apiKey: process.env.EASYPAY_SECRET!,
      clientId: process.env.EASYPAY_CLIENT_ID!,
    }),
  ],
  environment: 'sandbox',
});

Configuration

Required Configuration

apiKey
string
required
Your FundKit API key. Use fk_test_ prefixed keys for sandbox mode.
providers
BaseProvider[]
required
Array of configured payment provider instances. Must include at least one provider.

Optional Configuration

environment
'sandbox' | 'production'
default:"sandbox"
Environment mode. Use sandbox for testing, production for live payments.
timeout
number
default:"30000"
Request timeout in milliseconds for provider API calls.
retries
number
default:"3"
Number of retry attempts for failed provider requests.
logger
Logger
default:"console"
Custom logger instance for debugging and monitoring.

Advanced Configuration

const client = new PaymentClient({
  apiKey: process.env.FUNDKIT_API_KEY!,
  providers: [honeycoin, easypay],
  environment: 'production',

  // Advanced options
  timeout: 45000, // 45 second timeout
  retries: 5, // Retry failed requests 5 times
  retryDelay: 1000, // Wait 1 second between retries

  // Provider selection strategy
  strategy: 'round-robin', // 'smart', 'round-robin', 'priority'

  // Event handlers
  onSuccess: transaction => console.log('Payment succeeded:', transaction.id),
  onFailure: error => console.error('Payment failed:', error),

  // Custom logger
  logger: {
    info: msg => logger.info(msg),
    error: msg => logger.error(msg),
    debug: msg => logger.debug(msg),
  },
});

Core Methods

collection()

Process a payment collection (charge customer):
const transaction = {
  amount: 10000, // Amount in smallest unit (e.g., cents)
  currency: 'UGX',
  operator: 'mtn',
  accountNumber: '256779280949',
  externalId: 'order_12345',
  reason: 'Order payment',
};

try {
  const result = await client.collection(transaction);
  console.log('Payment initiated:', result);
} catch (error) {
  console.error('Payment failed:', error);
}
Response:
{
  provider: 'honeycoin',
  data: {
    transactionId: 'txn_abc123',
    status: 'pending',
    amount: 10000,
    currency: 'UGX',
    externalId: 'order_12345',
    reference: 'HC_REF_456'
  }
}

getTransaction()

Check the status of a transaction:
const status = await client.getTransaction({
  provider: 'honeycoin',
  txId: 'txn_abc123',
});

console.log('Transaction status:', status);
Response:
{
  id: 'txn_abc123',
  status: 'completed',
  amount: 10000,
  currency: 'UGX',
  externalId: 'order_12345',
  completedAt: '2024-01-15T10:30:00Z',
  fees: 100,
  provider: 'honeycoin'
}

payout() (Coming Soon)

Send money to a recipient:
const payout = await client.payout({
  amount: 50000,
  currency: 'UGX',
  operator: 'airtel',
  accountNumber: '256701234567',
  externalId: 'payout_789',
  reason: 'Seller payment',
});

Smart Provider Selection

PaymentClient automatically selects the best provider based on multiple factors:
Ensures the selected provider supports the transaction currency.
// Will automatically choose a provider that supports KES
const transaction = {
  amount: 1000,
  currency: 'KES', // Kenyan Shillings
  operator: 'safaricom',
  accountNumber: '254701234567'
};
Respects minimum and maximum transaction amounts for each provider.
// Large transaction - will choose provider with higher limits
const transaction = {
  amount: 5000000, // 50,000 UGX
  currency: 'UGX'
};
Monitors provider uptime and success rates, avoiding unhealthy providers.
// Will skip providers with recent failures
// and choose the most reliable option
Considers average response times and chooses faster providers when possible.

Manual Provider Selection

You can also manually specify which provider to use:
const result = await client.collection(transaction, {
  preferredProvider: 'easypay',
});

Event Handling

PaymentClient emits events for monitoring and debugging:
import { PaymentClient } from '@fundkit/core';

const client = new PaymentClient(config);

// Listen for events
client.on('transaction:started', transaction => {
  console.log('Transaction started:', transaction.externalId);
});

client.on('transaction:completed', transaction => {
  console.log('Transaction completed:', transaction.id);
});

client.on('transaction:failed', (error, transaction) => {
  console.error('Transaction failed:', error.message);
});

client.on('provider:selected', (provider, transaction) => {
  console.log(`Selected ${provider} for transaction ${transaction.externalId}`);
});

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

Environment Modes

Sandbox Mode

Perfect for development and testing:
const client = new PaymentClient({
  apiKey: 'fk_test_sandbox_key',
  providers: [honeycoin, easypay],
  environment: 'sandbox',
});

// All transactions will be simulated
// No real money is moved
// Instant responses for testing
Sandbox Benefits:
  • No provider approval needed
  • Instant testing
  • Predictable responses
  • No real money involved
  • All providers available immediately

Production Mode

For live transactions:
const client = new PaymentClient({
  apiKey: 'fk_live_production_key',
  providers: [honeycoin, easypay],
  environment: 'production',
});

// Real transactions with actual money
// Requires provider approval and live credentials
Production Requirements:
  • Provider compliance approval
  • Live API credentials
  • Webhook endpoints configured
  • Error handling implemented
  • Monitoring and alerting setup

Error Handling

PaymentClient provides structured error handling:
import { PaymentClient, FundKitError } from '@fundkit/core';

try {
  const result = await client.collection(transaction);
} catch (error) {
  if (error instanceof FundKitError) {
    console.error('FundKit Error:', {
      code: error.code,
      message: error.message,
      provider: error.context?.provider,
      details: error.details,
    });

    // Handle specific error types
    switch (error.code) {
      case 'INSUFFICIENT_FUNDS':
        // Show user-friendly message
        break;
      case 'INVALID_PHONE_NUMBER':
        // Ask user to verify phone number
        break;
      case 'PROVIDER_UNAVAILABLE':
        // Try again or use different provider
        break;
    }
  } else {
    // Unexpected error
    console.error('Unexpected error:', error);
  }
}

Best Practices

Always Validate Input

// Good: Validate before sending
if (!transaction.accountNumber) {
  throw new Error('Account number required');
}

const result = await client.collection(transaction);

Handle Failures Gracefully

// Good: Implement retry logic
let attempts = 0;
while (attempts < 3) {
  try {
    return await client.collection(transaction);
  } catch (error) {
    attempts++;
    if (attempts === 3) throw error;
    await sleep(1000 * attempts);
  }
}

Set Appropriate Timeouts

// Good: Configure timeouts
const client = new PaymentClient({
  ...config,
  timeout: 30000, // 30 seconds
});

Monitor Transaction Status

// Good: Poll for status updates
const checkStatus = async (txId) => {
  let status = 'pending';
  while (status === 'pending') {
    const result = await client.getTransaction({ txId });
    status = result.status;
    if (status === 'pending') {
      await sleep(5000); // Wait 5 seconds
    }
  }
  return status;
};

Next Steps