Transfers

Transfer money instantly between WasaaPay wallets. Transfers are processed in real-time with immediate balance updates.

Overview

The Transfers API allows you to move funds between wallets. You can:

  • Preview transfers before executing (see fees and recipient details)
  • Send money to any WasaaPay wallet using account number
  • Track transfers with your own reference IDs
  • Receive webhooks for transfer status changes

Transfer Flow

  1. Preview - Get transfer details including fees and verify recipient
  2. Create - Execute the transfer with idempotency protection
  3. Webhook - Receive notification when transfer completes

API Reference

Preview Transfer

Preview a transfer to see fees and verify the recipient before executing. This does not debit any funds.

Create Transfer

Execute a transfer between wallets. Requires idempotency key.

Get Transfer

Retrieve details of a specific transfer.

Code Examples

Complete Transfer Flow (JavaScript)

transfer.js
1async function sendMoney(fromWallet, toAccount, amount, description) {
2 const API_KEY = process.env.WASAAPAY_API_KEY;
3 const BASE_URL = 'https://api.wasaapay.com/api/v1/partner';
4
5 // Step 1: Preview the transfer
6 const previewResponse = await fetch(`${BASE_URL}/transfers/preview`, {
7 method: 'POST',
8 headers: {
9 'Content-Type': 'application/json',
10 'X-API-Key': API_KEY,
11 },
12 body: JSON.stringify({
13 sourceWalletId: fromWallet,
14 destinationAccountNumber: toAccount,
15 amount: amount,
16 }),
17 });
18
19 const preview = await previewResponse.json();
20
21 if (!preview.success || !preview.data.canProceed) {
22 throw new Error(preview.data.insufficientFunds
23 ? 'Insufficient funds'
24 : 'Transfer cannot proceed');
25 }
26
27 console.log('Transfer Preview:');
28 console.log(` Recipient: ${preview.data.destinationWallet.ownerName}`);
29 console.log(` Amount: ${preview.data.amount} KES`);
30 console.log(` Fee: ${preview.data.fee} KES`);
31 console.log(` Total: ${preview.data.totalDebit} KES`);
32
33 // Step 2: Execute the transfer
34 const idempotencyKey = `transfer_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
35
36 const transferResponse = await fetch(`${BASE_URL}/transfers`, {
37 method: 'POST',
38 headers: {
39 'Content-Type': 'application/json',
40 'X-API-Key': API_KEY,
41 'X-Idempotency-Key': idempotencyKey,
42 },
43 body: JSON.stringify({
44 sourceWalletId: fromWallet,
45 destinationAccountNumber: toAccount,
46 amount: amount,
47 narration: description,
48 }),
49 });
50
51 const transfer = await transferResponse.json();
52
53 if (!transfer.success) {
54 throw new Error(transfer.message);
55 }
56
57 console.log(`Transfer ${transfer.data.status}: ${transfer.data.reference}`);
58 return transfer.data;
59}
60
61// Usage
62sendMoney('wallet_abc123', '0712345678', 1000, 'Payment for services')
63 .then(result => console.log('Transfer ID:', result.id))
64 .catch(error => console.error('Transfer failed:', error.message));

Webhooks

Transfer events are delivered to your webhook URL. See the Webhooks documentation for setup instructions.

Transfer Events

EventDescription
transfer.completedTransfer was successful
transfer.failedTransfer failed

Webhook Payload

Webhook Payload
{
"event": "transfer.completed",
"timestamp": "2024-01-15T10:30:01Z",
"partnerId": "partner_abc123",
"environment": "PRODUCTION",
"signature": "sha256=abc123...",
"data": {
"transferId": "txn_xyz789",
"reference": "TRF-20240115-ABC123",
"externalReference": "INV-2024-001",
"amount": "1000.00",
"fee": "10.00",
"status": "COMPLETED"
}
}

Error Codes

CodeDescriptionResolution
INSUFFICIENT_FUNDSSource wallet doesn't have enough balanceAdd funds to the source wallet
WALLET_NOT_FOUNDSource or destination wallet doesn't existVerify wallet IDs/account numbers
WALLET_INACTIVEOne of the wallets is suspended or closedContact support
SAME_WALLETSource and destination are the sameUse different wallets
AMOUNT_TOO_LOWAmount below minimum (1 KES)Increase amount
AMOUNT_TOO_HIGHAmount exceeds maximum limitReduce amount or split transfer
DAILY_LIMIT_EXCEEDEDDaily transfer limit reachedWait until tomorrow or request limit increase

Best Practices