Overview
HoneyCoin is a leading mobile money aggregator across East Africa, providing unified access to multiple mobile network operators. With FundKit’s HoneyCoin integration, you can process payments across Uganda, Kenya, and Tanzania through a single provider.
HoneyCoin specializes in cross-border payments and multi-operator support, making it ideal for
businesses operating across multiple East African countries.
Coverage & Capabilities
Supported Countries
Uganda Networks: MTN, Airtel Currency: UGX Features: Collections, Payouts, Status Check
Kenya Networks: Safaricom, Airtel Currency: KES Features: Collections, Payouts, Status Check
Tanzania Networks: Vodacom, Airtel, Tigo Currency: TZS Features: Collections, Status Check
Capabilities
Collections - Charge customers via mobile money
Payouts - Send money to recipients
Status Checking - Real-time transaction status
Webhooks - Instant status notifications
Multi-currency - UGX, KES, TZS support
Cross-border - Process payments across countries
Bulk operations - Process multiple transactions
Refunds - Available on request
Installation
npm install @fundkit/honeycoin
Configuration
Basic Setup
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'
});
Configuration Options
Your HoneyCoin API key. Get this from your HoneyCoin dashboard.
Your HoneyCoin public key for webhook signature verification.
environment
'sandbox' | 'production'
default: "sandbox"
Environment mode. Use sandbox for testing, production for live payments.
Request timeout in milliseconds.
Number of retry attempts for failed requests.
URL to receive webhook notifications for transaction updates.
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 ,
// Webhook configuration
webhookUrl: 'https://api.myapp.com/webhooks/honeycoin' ,
webhookSecret: process . env . HONEYCOIN_WEBHOOK_SECRET ,
// Rate limiting
rateLimit: {
requests: 100 ,
window: 60000 , // Per minute
},
// Custom headers
headers: {
'User-Agent' : 'MyApp/1.0' ,
'X-Source' : 'mobile-app' ,
},
// Logging
logger: customLogger ,
logLevel: 'info' , // 'debug', 'info', 'warn', 'error'
});
Getting API Credentials
Sandbox Credentials
For testing, you can get sandbox credentials instantly:
Visit HoneyCoin Developer Portal
Create Sandbox Application
Click “Create App” and select “Sandbox Environment”
Get Your Keys
Copy your API Key and Public Key from the dashboard
Set Environment Variables
HONEYCOIN_API_KEY = hc_test_your_api_key_here
HONEYCOIN_PUBLIC_KEY = pk_test_your_public_key_here
Production Credentials
For live payments, you need to complete HoneyCoin’s onboarding:
Production Onboarding Process
Business Registration - Submit business documents 2. Compliance Review - KYC/AML
verification (2-5 business days) 3. Integration Testing - Complete test scenarios 4. Go-Live
Approval - Final review and approval 5. Production Keys - Receive live API credentials
Production approval typically takes 3-7 business days. Plan accordingly for your launch
timeline.
Usage Examples
Basic Collection
import { PaymentClient } from '@fundkit/core' ;
import { HoneyCoin } from '@fundkit/honeycoin' ;
const honeycoin = new HoneyCoin ({
apiKey: process . env . HONEYCOIN_API_KEY ! ,
publicKey: process . env . HONEYCOIN_PUBLIC_KEY ! ,
environment: 'sandbox' ,
});
const client = new PaymentClient ({
apiKey: process . env . FUNDKIT_API_KEY ! ,
providers: [ honeycoin ],
environment: 'sandbox' ,
});
// Process payment
const transaction = {
amount: 10000 , // 100.00 UGX
currency: 'UGX' ,
operator: 'mtn' ,
accountNumber: '256779280949' ,
externalId: 'order_12345' ,
reason: 'Product purchase' ,
};
try {
const result = await client . collection ( transaction );
console . log ( 'Payment initiated:' , result );
} catch ( error ) {
console . error ( 'Payment failed:' , error . message );
}
Multi-Country Payment
// Kenya payment
const kenyaPayment = {
amount: 5000 , // 50.00 KES
currency: 'KES' ,
operator: 'safaricom' ,
accountNumber: '254701234567' ,
externalId: 'kenya_order_123' ,
reason: 'Service payment' ,
};
// Tanzania payment
const tanzaniaPayment = {
amount: 20000 , // 200.00 TZS
currency: 'TZS' ,
operator: 'vodacom' ,
accountNumber: '255754123456' ,
externalId: 'tz_order_456' ,
reason: 'Product delivery' ,
};
// Process payments
const [ kenyaResult , tanzaniaResult ] = await Promise . allSettled ([
client . collection ( kenyaPayment ),
client . collection ( tanzaniaPayment ),
]);
Payout Example
// Send money to a recipient
const payout = {
amount: 25000 , // 250.00 UGX
currency: 'UGX' ,
operator: 'airtel' ,
accountNumber: '256701234567' ,
externalId: 'payout_789' ,
reason: 'Commission payment' ,
// Additional payout fields
recipientName: 'John Doe' ,
reference: 'COMM_2024_001' ,
};
try {
const result = await honeycoin . payout ( payout );
console . log ( 'Payout sent:' , result );
} catch ( error ) {
console . error ( 'Payout failed:' , error . message );
}
Transaction Limits
Amount Limits by Currency
Uganda (UGX)
Kenya (KES)
Tanzania (TZS)
Minimum: 500 UGX - Maximum: 10,000,000 UGX (per transaction) - Daily limit:
20,000,000 UGX (per account) - Monthly limit: 100,000,000 UGX (per account)
Rate Limits
API Requests: 100 requests per minute
Concurrent Transactions: 50 simultaneous transactions
Bulk Operations: 1,000 transactions per batch
Error Handling
Common HoneyCoin Errors
try {
const result = await client . collection ( transaction );
} catch ( error ) {
switch ( error . code ) {
case 'HC_INSUFFICIENT_FUNDS' :
showMessage ( 'Customer has insufficient balance' );
break ;
case 'HC_INVALID_PHONE' :
showMessage ( 'Invalid phone number format' );
break ;
case 'HC_NETWORK_UNAVAILABLE' :
showMessage ( 'Mobile network is currently unavailable' );
break ;
case 'HC_CUSTOMER_CANCELLED' :
showMessage ( 'Customer cancelled the payment' );
break ;
case 'HC_DUPLICATE_TRANSACTION' :
showMessage ( 'Duplicate transaction detected' );
break ;
case 'HC_ACCOUNT_BLOCKED' :
showMessage ( 'Customer account is temporarily blocked' );
break ;
default :
showMessage ( 'Payment failed. Please try again.' );
logError ( error );
}
}
Error Details
HC_INSUFFICIENT_FUNDS - Customer doesn’t have enough money HC_CUSTOMER_CANCELLED -
Customer declined payment prompt HC_TIMEOUT - Customer didn’t respond to payment prompt
HC_INVALID_PIN - Customer entered wrong PIN
HC_INVALID_PHONE - Phone number format is incorrect HC_ACCOUNT_BLOCKED - Customer account
is suspended HC_ACCOUNT_NOT_FOUND - Phone number not registered HC_ACCOUNT_LIMIT_EXCEEDED
Transaction exceeds account limits
HC_NETWORK_UNAVAILABLE - Mobile network is down HC_PROVIDER_MAINTENANCE - HoneyCoin
system maintenance HC_RATE_LIMITED - Too many requests HC_AUTHENTICATION_FAILED -
Invalid API credentials
Webhooks
Webhook Configuration
const honeycoin = new HoneyCoin ({
apiKey: process . env . HONEYCOIN_API_KEY ! ,
publicKey: process . env . HONEYCOIN_PUBLIC_KEY ! ,
webhookUrl: 'https://api.myapp.com/webhooks/honeycoin' ,
webhookSecret: process . env . HONEYCOIN_WEBHOOK_SECRET ,
});
Webhook Handler
import crypto from 'crypto' ;
import express from 'express' ;
const app = express ();
app . use ( express . raw ({ type: 'application/json' }));
app . post ( '/webhooks/honeycoin' , ( req , res ) => {
const signature = req . headers [ 'x-honeycoin-signature' ];
const payload = req . body ;
// Verify webhook signature
const expectedSignature = crypto
. createHmac ( 'sha256' , process . env . HONEYCOIN_WEBHOOK_SECRET ! )
. update ( payload )
. digest ( 'hex' );
if ( signature !== `sha256= ${ expectedSignature } ` ) {
return res . status ( 400 ). json ({ error: 'Invalid signature' });
}
const event = JSON . parse ( payload . toString ());
// Handle different event types
switch ( event . type ) {
case 'transaction.completed' :
handleTransactionCompleted ( event . data );
break ;
case 'transaction.failed' :
handleTransactionFailed ( event . data );
break ;
case 'transaction.pending' :
handleTransactionPending ( event . data );
break ;
case 'payout.completed' :
handlePayoutCompleted ( event . data );
break ;
default :
console . log ( 'Unknown event type:' , event . type );
}
res . status ( 200 ). json ({ received: true });
});
function handleTransactionCompleted ( transaction ) {
console . log ( 'Transaction completed:' , transaction . externalId );
// Update your database
updateTransactionStatus ( transaction . externalId , 'completed' );
// Send confirmation to customer
sendConfirmationEmail ( transaction . customerEmail , transaction );
// Fulfill the order
fulfillOrder ( transaction . externalId );
}
Webhook Events
transaction.completed Payment was successful and money has been transferred
transaction.failed Payment failed due to various reasons (insufficient funds, etc.)
transaction.pending Payment is waiting for customer confirmation
transaction.timeout Payment timed out waiting for customer response
payout.completed Payout was successfully sent to recipient
payout.failed Payout failed to process
Testing in Sandbox
Test Phone Numbers
HoneyCoin provides special test phone numbers for different scenarios:
// Test numbers for different outcomes
const testNumbers = {
// Uganda
success: '256779000001' , // Always succeeds
insufficientFunds: '256779000002' , // Always fails with insufficient funds
timeout: '256779000003' , // Always times out
cancelled: '256779000004' , // Customer cancels
// Kenya
successKenya: '254701000001' , // Always succeeds
failKenya: '254701000002' , // Always fails
// Tanzania
successTanzania: '255754000001' , // Always succeeds
failTanzania: '255754000002' , // Always fails
};
// Test transaction
const testTransaction = {
amount: 5000 ,
currency: 'UGX' ,
operator: 'mtn' ,
accountNumber: testNumbers . success ,
externalId: 'test_' + Date . now (),
reason: 'Test payment' ,
};
Sandbox Environment Features
Sandbox transactions complete immediately without actual SMS prompts
Use specific test numbers to simulate different scenarios
Webhooks work the same as production for testing your integration
Test as much as you want without hitting rate limits
Production Checklist
Before going live with HoneyCoin:
Best Practices
Security // Good: Store credentials securely
const honeycoin = new HoneyCoin ({
apiKey: process . env . HONEYCOIN_API_KEY ! ,
publicKey: process . env . HONEYCOIN_PUBLIC_KEY !
});
// Bad: Hardcode credentials
// const honeycoin = new HoneyCoin({
// apiKey: 'hc_live_123456789',
// publicKey: 'pk_live_abcdefghi'
// });
Idempotency // Good: Use unique external IDs
const externalId = `order_ ${ orderId } _ ${ timestamp } ` ;
// Bad: Non-unique IDs
// const externalId = 'payment';
Webhooks // Good: Always verify webhook signatures
const isValid = verifyWebhookSignature (
payload ,
signature ,
webhookSecret
);
if ( ! isValid ) {
return res . status ( 400 ). end ();
}
Timeouts // Good: Handle timeouts gracefully
try {
const result = await client . collection ( transaction );
} catch ( error ) {
if ( error . code === 'HC_TIMEOUT' ) {
// Check status instead of immediate retry
const status = await client . getTransaction ({
provider: 'honeycoin' ,
txId: error . transactionId
});
}
}
Support & Resources
Next Steps