Pool Account Integration
Digital wallets require a sponsor bank with deposit-taking licences in the country in which the wallet is issued. EFT Corporation partners with banks to provide this backing. The sponsor bank holds a pool account which 100% backs the value sitting in the individual digital wallets. Net credits into digital wallets have an associated transfer into the pool account, while net debits have a transfer out of the pool account.
In order for a pool account to back the digital wallets, certain interfaces are required with the bank in order to keep the sum of all digital wallets in sync with the pool account balance.
Interface Summary
| Interface | Direction | Protocol | Purpose |
|---|---|---|---|
| Real-time deposit notification | Bank → Eclipse | HTTP webhook | Notify Eclipse of incoming EFT/ATM credits to the pool account so customer wallets can be credited immediately |
| EFT outbound instruction | Eclipse → Bank | HTTP or SFTP batch | Instruct the bank to EFT funds out of the pool account to a customer's external bank account |
| Merchant settlement notification | Bank → Eclipse | HTTP, SFTP, or email | Notify Eclipse when inter-bank card acquiring settlement has occurred so merchant funds can be released |
These interfaces are as follows:
Real-Time Deposit Notifications
Whenever a credit is received in the pool account due to an incoming EFT or ATM deposit, Eclipse needs to be notified so that an associated wallet can be credited. This should happen in near real-time so that the end customer does not need to wait for their wallet balance to reflect the credit once the amount hits the pool account.
Setup prerequisites:
- EFTCorp generates a 36-character UUID as the global unique identity for each EFT integration.
- An
INSTITUTION_ADMINuser is created in Eclipse specifically for the bank integration. - EFTCorp generates a random API key and registers it in the global property
apikey.to.user.mappingsmapped to that user's identity. - The API key is shared with the bank. The bank must include it in the
Authorizationheader of every deposit notification request.
Wallet resolution — the bank must provide at least one of:
| Field | Resolution |
|---|---|
destinationWalletId | Directly identifies the wallet by Eclipse wallet ID |
destinationAccountNumber | Matches the account number stored on the wallet |
reference | Matches the wallet-friendly ID or registered mobile number on the wallet |
An example of the payload for this API call is as follows:
Headers
Authorization: <EFT Provided API Key>
POST /eclipse-conductor/rest/v1/webhooks/deposits
{
"destinationAccountNumber": "80000200000001", // If present, must match the account number in the wallet (optional)
"destinationWalletId": 12345, // If present, must match the wallet to be credited (optional)
"bankName": "ZA_Nedbank",
"currency": "ZAR",
"amount": "100.00",
"transactionId": "514FTIN100000029982B006",
"reference": "100143234PR", // If present, must match the wallet-friendly ID or mobile number in the wallet
"transactionDate": "2024/11/11 12:20:23 GMT +02:00",
"additionalFields": [ // Optional
{
"id": "xxx",
"defaultValue": "xxx"
}
]
}
NoteIn the request, either destinationWalletId, destinationAccountNumber or reference is mandatory to identify the wallet for the deposit.
Additionally, there is an attribute called type in the request, which can be used in special cases, such as notifying the bank using the bank's webhook URL or other bank-specific actions.
Another example of the payload using type and additional fields is as follows:
{
"destinationAccountNumber": "80000200000001",
"bankName": "ABCD",
"currency": "SZL",
"amount": "100.00",
"transactionId": "514FTIN100000029982B006",
"reference": "100143234PR",
"type": "ERS_DEPOSIT",
"transactionDate": "2024/11/11 12:20:23 GMT +02:00",
"additionalFields": [
{
"id": "tenantId",
"defaultValue": "688"
},
{
"id": "taxType",
"defaultValue": "ORMB"
}
]
}A description of these fields and their validation criteria are as follows:
@Schema(description = "The destination account number. If provided, must match an account number in the wallet. Required if reference and walleId is missing.")
protected String destinationAccountNumber;
@Schema(description = "The destination wallet id. If provided, must match a wallet. Required if reference and account number is missing.")
protected String destinationWalletId;
@Schema(description = "Bank name. Optional. Possible values: ZA_Nedbank, ZA_FNB, ZA_Standardbank, KE_DTB, ZA_Africanbank, ZA_PnP_Deposit")
protected String bankName;
@Schema(description = "Currency of the transaction, e.g., ZAR. Optional.")
protected String currency;
@Schema(description = "Transaction amount in major currency units. Optional.")
@Pattern(regexp = "^\\d+(\\.\\d{1,2})?$", message = "Value '${validatedValue}' for amount is invalid: Must be a decimal number with up to two decimal places")
protected BigDecimal amount;
@Schema(description = "Transaction ID. Optional unique identifier for the transaction.")
protected String transactionId;
@Schema(description = "Reference. If provided, must match wallet-friendly ID or mobile number. Required if destinationAccountNumber is missing.")
protected String reference;
@Schema(description = "Transaction date in the format yyyy/MM/dd HH:mm:ss z Z. Optional.")
protected String transactionDate;
@Schema(description = "Transaction type. Used for special-case deposits such as ERS_DEPOSIT. Optional.")
protected String type;
// Nested class for additionalFields
@Schema(description = "Structure representing an additional field for the transaction.")
public static class AdditionalField {
@Schema(description = "Field identifier.")
protected String id;
@Schema(description = "Default value for the field.")
protected String defaultValue;
}EFT Interface
In order for customers to withdraw money from digital wallets to an external bank account, Eclipse must be able to instruct the sponsor bank to EFT from the pool account to the customer’s account. EFT rails are asynchronous — Eclipse submits the instruction and receives the result at a later time (typically the next business day).
Preferred interface: HTTP with an Eclipse callback for results. SFTP batch is also supported.
Minimum fields the bank’s EFT interface must accept:
| Field | Description |
|---|---|
| Source pool bank account number | The pool account to debit |
| Destination bank name | Target bank (e.g. ZA_FNB, ZA_Nedbank) |
| Destination branch code | Bank branch code |
| Destination account number | Beneficiary account number |
| Destination account name | Beneficiary account holder name |
| Amount | EFT amount in major currency units |
| Beneficiary reference | Reference shown on beneficiary’s bank statement |
| Unique EFT identifier | UUID for idempotency — Eclipse will use this to match results |
Result notification: When the EFT succeeds or fails, the bank must notify Eclipse with the unique EFT identifier and the outcome (SUCCESS or FAILED). Eclipse then updates the withdrawal status and credits/reverses the wallet accordingly.
Merchant Settlement Notification
When inter-bank settlement occurs for card acquiring transactions into an Eclipse tenant's merchant account, Eclipse needs to process the settlement and make the funds available to the sub-merchant. Until settlement is confirmed, acquired funds are held in a reserved state in the merchant's wallet.
Notifications can be delivered via email, SFTP, or HTTP. For each settled transaction, the following fields are required:
| Field | Description |
|---|---|
| Transaction date/time | The date and time of the original card transaction (not the settlement date) |
| Transaction amount | The settled amount |
| Auth code | 6-character authorisation code from the original card transaction |
| UTI | Unique Transaction Identifier from the original card transaction |
Eclipse matches each settlement notification to the original card transaction using the auth code and UTI, then releases the reserved funds into the merchant's available wallet balance.
Note: Settlement notifications must reference the original transaction date and auth code, not the settlement date. Using the settlement date will cause a matching failure.
