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

InterfaceDirectionProtocolPurpose
Real-time deposit notificationBank → EclipseHTTP webhookNotify Eclipse of incoming EFT/ATM credits to the pool account so customer wallets can be credited immediately
EFT outbound instructionEclipse → BankHTTP or SFTP batchInstruct the bank to EFT funds out of the pool account to a customer's external bank account
Merchant settlement notificationBank → EclipseHTTP, SFTP, or emailNotify 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:

  1. EFTCorp generates a 36-character UUID as the global unique identity for each EFT integration.
  2. An INSTITUTION_ADMIN user is created in Eclipse specifically for the bank integration.
  3. EFTCorp generates a random API key and registers it in the global property apikey.to.user.mappings mapped to that user's identity.
  4. The API key is shared with the bank. The bank must include it in the Authorization header of every deposit notification request.

Wallet resolution — the bank must provide at least one of:

FieldResolution
destinationWalletIdDirectly identifies the wallet by Eclipse wallet ID
destinationAccountNumberMatches the account number stored on the wallet
referenceMatches 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"  
        }  
    ]  
}
📘

Note

In 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:

FieldDescription
Source pool bank account numberThe pool account to debit
Destination bank nameTarget bank (e.g. ZA_FNB, ZA_Nedbank)
Destination branch codeBank branch code
Destination account numberBeneficiary account number
Destination account nameBeneficiary account holder name
AmountEFT amount in major currency units
Beneficiary referenceReference shown on beneficiary’s bank statement
Unique EFT identifierUUID 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:

FieldDescription
Transaction date/timeThe date and time of the original card transaction (not the settlement date)
Transaction amountThe settled amount
Auth code6-character authorisation code from the original card transaction
UTIUnique 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.