Eclipse Initiated Notifications (Webhooks)

There are certain circumstances under which Eclipse will initiate API calls to a tenant's domain. Typical examples of this are notification of transactions on a particular store-of-value within Eclipse, or in cases where the Eclipse wallet is a facade to an external SoV on the tenant's platform and and API call is needed to authorise a debit or a credit. This section will describe the typical use cases where such calls are used, how they are configured and their corresponding payloads (models).

Security

It must be noted that all calls to 3rd party platform in these use cases will have an Eclipse-Signature header, as described in the 'Encryption and Integrity section''. It is vital that all tenant endpoints implement a check to be sure all their endpoints expecting calls from Eclipse are from Eclipse before processing them.

Source IP Addresses

Callbacks / webhooks (from Eclipse) in case tenants whish to whitelist, are as follows:
79.125.40.127
54.220.185.240
18.134.2.182
3.11.195.109

For Sandbox, the source IP for callbacks / webhooks is:
34.255.93.65

Wallet Movement Notification

This webhook is triggered to a 3rd party URL for all movements on a wallet based on the wallet's configuration, as specified by it's type and type configuration. For every wallet, there is an associated wallet-type. Each wallet-type can have a configuration parameter called, 'walletMovementWebhookUrl' which can be populated with any URL that Eclipse is able to call. A screenshot illustrating this config can be seen below.

It is important to note that this API call is performed once only. Eclipse will asynchronously send the request and will not retry if the API call fails.

In some cases where the transfer uses eventual consistency (such as digital to PTS card wallets), the notification can be sent before PTS has updated its balance. To avoid this, a delay can be configured on the wallet type so that any notifications for that wallet type are delayed. This is set via 'walletMovementWebhookDelayMs' and can be set on PTS wallet types to something like 3000 so that the notification happens 3 seconds after the transaction and gives time for PTS to be aware of the transaction.

An example of the payload for this callback is as follows:

{
  "transactionId": "123",
  "walletId": 51588,
  "type": "Cr",
  "date": "2022-11-10T17:52:31.000+02:00",
  "amount": 1.00,
  "fee": 0,
  "currency": "ZMW",
  "description": "blah blah",
  "authorisationCode": "CBHVYZ",
  "externalId": "231409331575",
  "externalUniqueId": "baff409432820bee9092f49147a704f0"
}

A description of these fields and their validation criteria are as follows:

@NotNull(message = "Value '${validatedValue}' for Transaction's transactionId is invalid: It is mandatory")
    @Schema(description = "Unique identifier for the transaction generated by the wallet/card system")
    protected String transactionId;
    @NotNull(message = "Value '${validatedValue}' for Transaction's walletId is invalid: It is mandatory")
    @Positive(message = "Value '${validatedValue}' for Transaction's walletId is invalid: It must be positive")
    @Schema(description = "The walletId of the transaction")
    protected long walletId;
    @Schema(description = "Transaction type")
    protected String type;
    @Schema(description = "ISO 8601 of the transaction")
    protected ZonedDateTime date;
    @Schema(description = "Amount. Negative for debits, positive for credits. Amounts are in major currency unit")
    protected BigDecimal amount;
    @Schema(description = "Fee. The additional fee charged as part of the transaction")
    protected BigDecimal fee;
    @Schema(description = "Currency of the transaction. E.g. USD, ZAR, NGN etc")
    protected String currency;
    @Schema(description = "Closing balance in the currency of the wallet.")
    protected BigDecimal balance;
    @Schema(description = "Transaction description")
    protected String description;
    @Schema(description = "Auth code for card transactions")
    protected String authorisationCode;
    @Schema(description = "External identifier for the transaction which can be used for reconcilliation. Need not be unique")
    protected String externalId;
    @Schema(description = "The externally provided unique identifier for the transaction")
    protected String externalUniqueId;
    @Schema(description = "If this was a transfer then this field will contain the other walletId which was debited/credited")
    protected Long otherWalletId;
    @Schema(description = "Any location information about the transaction such as IP address or GPS")
    protected String location;

Wallet Movement Authorization

Related to wallet movement notifications is the ability to send debit notifications to the tenant for authorization before the debit is processed - if the tenant does not authorize then Eclipse will roll back any ledger changes done. This gives tenants the ability to auth transactions synchronously and supports the use case where a tenant has their own ledger and they want this to mirror the Eclipse wallet ledger.

There are 2 wallet-type configuration parameters that apply to this scenario:
1. preDebitTenantAuthUrl -URL that Eclipse will do a POST to with the details of any transfer debit from the wallet and only if an HTTP response code < 300 is returned will Eclipse process the transaction. This gives tenants the ability to auth transactions synchronously. The call must return within 3 seconds as this is the timeout of the request. The tenants URL path must have eclipseauthrequest in the path.
2. preDebitTenantAuthSkipForUserId - Transfers by this userId will not result in preDebitTenantAuthUrl being called even if it is configured. Tenants can use this to not to a back-to-back auth on transactions when not required (e.g. the tenant initiated the transfers themselves)

Consolidated Callbacks for Unsolicited Deposits/Payments

For longer running transactions like payments, topups and withdrawals callbacks on transaction completion including transaction details and status are important for tenants to receive. Typically for tenant initiated payments, withdrawals or topups a callback URL can be specified by the tenant when initiating that transaction and the full transaction object is posted to that URL when the transaction completes.

However there are certain transactions that are not tenant initiated, that tenants would also like to be notified on - for example an EFT payment into a wallet or a QR code payment into a wallet.

To be notified on any unsolicited deposits/payments (e.g. an EFT payment is done into a wallet, or a QR code is paid into a wallet), the completed transaction object can be posted to a URL. This URL can be set at an organisation level by including an attachment of type consolidatedCallbacks that specifies the notification URL. If the payment is for a wallet associated to that organisation then the notification will be sent to that URL. Alternatively this can be set at a tenant level by setting tenant configuration consolidatedCallbacks to the specific URL.

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/organisations/{organisationId}/attachments
{
  "attachmentType": "consolidatedCallbacks",
  "mediaType": "text/plain",
  "type": "consolidatedCallbacks",
  "info": "https://webhook.site/91368c6c-6581-4434-9500-06ae5d36694b"
}

An example of the payload for the callback when an EFT payment is done is as follows:

{
  "externalUniqueId": "+VNp9bmNHwnjjskFPTWInv2aUD2rg/HYGjqPRHWQ8vU=",
  "walletId": 3129,
  "amount": 10.000000000,
  "created": "2023-11-01T09:26:00Z",
  "paymentReference": "JVAHS6G3",
  "fee": 0.10000000000000000000000000000,
  "description": "JVAHS6G3",
  "retrievalReferenceNumber": 0,
  "paymentType": "ATM",
  "paymentId": 10491,
  "customerId": 3761,
  "currency": "ZAR",
  "status": "SUCCESSFUL"
}

An example of the payload for the callback when a QR payment is done is as follows:

{
    "paymentId": 74881,
    "externalUniqueId": "MP-IN-4589207-SUCCESS",
    "status": "SUCCESSFUL",
    "amount": 100.000000000,
    "description":"QR Code Paymeny",
    "currency": "ZAR",
    "additionalFields": [],
    "acceptedCardSchemes": [],
    "cardPhone": "9726999279",
    "phone": "9726999279",
    "acceptedPaymentMechanisms": [],
    "paymentType": "CARD",
    "authCode": " DEBUG",
    "retrievalReferenceNumber": 809260,
    "created": "2023-11-22T10:26:59.000Z",
    "paymentData": "6244523710",
    "paymentInstrumentInfo": {
        "cardBin": "424242",
        "cardType": "CREDIT",
        "cardLast4": "4242",
        "cardName": "TESTING",
        "cardPhone": "9726999279"
    },
    "fee": 0E-9,
    "paymentReference": "7165124d-5e53-49b6-b644-b3474c8d6ccb",
    "walletId": 204149,
    "organisationId": 11869,
    "associatedPaymentId": 74878,
    "gatewayTransactionId": "MP-IN-4589207-SUCCESS"
}