Payments Use Cases

Payments allow tenants to initiate or process a payment from a store of value - sometimes one on Eclipse and sometimes a card or store of value outside of Eclipse. In many ways, there is an overlap between payments and top-ups in that a top-up can often be seen as a payment to one's own wallet. As payments can result in funds going to non-Eclipse wallets, they are a superset of top-ups. (I.e. top-ups always result in funds ending up in an Eclipse Wallet while payments can result in funds going to an external bank/wallet/account).

When in doubt, use top-up APIs when the customer carrying out the transaction is going to be the recipient of the funds into their Eclipse wallet, and payments where the person or API doing the payment is not going to be the one sending and receiving the funds. The payments API can be used at the customer level or directly at the tenant level. Using it at the customer level allows Eclipse to deduce the payer information while at the tenant level, the API requires customer information to be passed in. From there on both APIs are identical.

Creating a payment involves 2 core pieces of data;
The first is the combination of paymentData and type. These determine where the money is going to. This can also be specified in the destinationWalletId field if the destination is a wallet. This grants a high degree of flexibility in the precise routing of payments to the intended merchant. For backwards compatibiltiy legacy fields paymentData and merchantWalletId can also be used to set this.
The second is the payment mechanism (i.e. where the money is coming from) which can be captured in fields like walletId, externalWalletId & externalWalletType, paymentCardData, and finally, cardOnFileId. Eclipse uses this info to decide how to get the funds from where it’s coming from to where it’s going to.

Due to the numerous payment mechanisms and payment flows, the payments API supports both single and multi-step payments depending on the type of payment and payment mechanism.

  • Multi-step payments involve a POST and then one or more PUT operations until the payment is fully processed. This is needed when the POST initiates a payment and then additional data is required to complete it.
  • Single-step payments involve a POST with all required information and the payment is done without further PUTs required.
  • As each payment type can involve different fields, they are documented separately but all use the same endpoint and JSON structure. Just some use more or fewer fields than others and may need more or fewer steps to achieve a final outcome.

Also, note that payments are often associated with the rendering or provisioning of a value-added service once the payment is made. This is orchestrated by Eclipse or by the VAS partner depending on what is being purchased. API callers can assume that Eclipse is taking care of ensuring that a payment cannot be made without the VAS being delivered and vice versa.

Finally payments can be initiated for a specific customer:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments

Or not for a specific customer:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/payments

The only difference between the two endpoints is that the first will use the customer's details whereas the second one requires the customer info to be passed in the request body.

South Africa Payment Types

The following payment types are specific to tenants operating in South Africa.

ZA_QRCODE

This payment type should be used when paying a Scan To Pay QR Code in South Africa. It can be a single or multi-step process.

Typically before initiating a transaction, a channel will first need to retrieve the QR details to display to the customer. This can be done by calling the wallet QR codes endpoint.

GET /eclipse-conductor/rest/v1/tenants/{tenantId}/wallets/qr-codes?code={qrCode}

Example response body:

{
  "walletId": 47111,
  "type": "ZA_MASTERPASS",
  "code": "6279201670",
  "amount": 100,
  "expires": "2026-04-20T22:00:00.000Z",
  "reference": "Test ref",
  "merchantName": "Johns bakery",
  "description": "QR code for Johns bakery",
  "additionalFields": [],
  "acceptedCardSchemes": "MASTER,VISA,MAESTRO",
  "acceptedPaymentMechanisms": "AMT,SECURE_CODE,CNP"
}

To initiate a transaction for a specific customer:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments

Or if not for a specific customer:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/payments

The only difference between the two endpoints is that the customer one will use the customer's details whereas a payment gateway needs customer information, whereas the second one requires the customer info to be passed in. Hence the second one has an additional field “phone” to indicate the phone number of the customer making the payment. For the second one, a phone number is required for Masterpass and should be in an international format starting with the country code (e.g. 27831234567).

Other than phone, the following are required fields:
externalUniqueId: A unique GUID to identity this payment and prevent unintended duplicate payments
paymentData: The decoded ten-digit masterpass QRCode e.g. 9876543210 (Clients scanning the QR might find different formats being returned, ie. https://regstest.oltio.co.za/qr/?c=248942699&a=12.34. Populate this field with exactly the same data as received when it was scanned)
type: ZA_QRCODE

The response to the POST will include information about the QRCode (amount and whether additional fields are required). The status will be PENDING if the POST has sufficient data to send to Masterpass and BUILDING if more data is still required.

Indicative response:

{"paymentId":3034,"status":"BUILDING","amount":15.00,"description":"Ukheshe Test 2021  - Me : Test QR","merchantName":"Ukheshe Test 2021  - Me","currency":"ZAR","partialPaymentAllowed":false,"acceptedCardSchemes":["MASTER","VISA","MAESTRO","AMEX","DINERS"],"acceptedPaymentMechanisms":["AMT","SECURE_CODE","SOV"]}

At this point, if the status is BUILDING then the next step is a PUT to update the payment further on

URL /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}

The data in the put should include how the QR must be paid and any additional fields needed for the QR.

Specifying the source store of value

There are 5 supported means of specifying the source store of value for paying a Masterpass QR:

  1. Provide a card on file Id for a previously added card on file. This must be a CoF belonging to the caller (JWT).
  2. For PCI-DSS-compliant tenants, the card data can be provided directly in the paymentCardData field.
  3. For tenants with their own store of value and prior integration, they can pass their own externalWalletId and externalWalletType (e.g. ABC12345 and MOBI_CHOICE)
  4. For tenants with a lodge card registered to do card rails payments on behalf of their closed-loop Eclipse digital wallet, the source Eclipse walletId can be provided. For more details please refer to Lodge card payments
  5. Providing none of the above will result in a completionUrl being returned where the customer can capture card data in a lightbox (iFrame) and complete 3DS and the payment.

The value of the paymentSecurityData field depends on the store of value paying the QRCode. If the tenant is the card issuer (bank) they can provide the 3DS fields such as cavv so as to skip 3DS. External stores of value may pass a token as additional authentication (TBD with the tenant).

  • callbackUrl: Where Eclipse will post the final result when Masterpass has completed the transaction (optional)
  • landingUrl: Where to navigate the customer at the end of a lightbox process if the customer has to complete card details / 3DS
  • Amount: Must be populated with the final total amount the customer will pay. (required)

If a tip is to be included the amount should include the tip portion. For example if an amount due is R100 and the customer opts to include a R10 tip, then the amount should be set to R110.

In addition the tip should be included as part of the additionalFields parameter as tipAmount:

"additionalFields": 
[
     {
         "id": "tipAmount",
         "value": "10.00"
     }
 ]
  • Payment Mechanism is not needed as it can be deducted from the other data.

Example PUT body specifying a card on file to pay with:

{"landingUrl":"http://www.blanksite.com/","cardOnFileId":"e58c8bcf-f085-436f-90e2-4916f4b90efc","amount":15.00}

Indicative response:

{"paymentId":3034,"externalUniqueId":"1fe9338f-06ed-4654-afdf-07b7c00c3c3e","status":"PENDING","paymentType":"CARD","description":"Ukheshe Test 2021  - Me : Test QR","amount":15.00,"completionUrl":"https://ukheshe.live/t/7amar","created":"2021-06-08T10:12:56.000Z","lastModified":"2021-06-08T10:12:56.767Z","paymentData":"9455383854"}

At this point, the customer can be navigated to the completionUrl to complete 3DS after which they will be sent to the landingUrl

When the payment completes (failed or successful), a callback will be done to the callbackURL with the result of the payment in the same format as if a GET was done on the paymentId.

If a Masterpass payment has a status of SUCCESSFUL then the card/wallet has been debited and the merchant has been notified of the successful transaction and the customer can get their goods/services.

Refer to the sandbox test accounts section for sample QR codes and use cases.

ZA_OZOW

This payment type allows you to build Ozow's real-time EFT functionality directly into Eclipse. This integration method gives you more flexibility but would require more effort than using the Ozow hosted method.

Ozow API Endpoints
Staging
Production

Prerequisites

  • A valid JWT for API calls
  • walletId

Required tenant configuration before getting started:

  • sd.external.services=REST,OzowAPI,https://stagingapi.ozow.com,^/ozow-api, , ,0,0, ,/ozow-api
  • tenant.config.
  • ozow.payment.config.siteCode=TSTSTE0001
  • ozow.payment.config.countryCode=ZA
  • ozow.payment.config.privateKey=215114531AFF7134A94C88CEEA48E
  • ozow.payment.config.apiKey=EB5758F2C3B4DF3FF4F2669D5FF5B
  • ozow.payment.config.generateShortUrl=true
  • ozow.payment.config.enableTestEnvironment=falseconfig.Pay
  • fees.amount.config.Pay.ZA_OZOW.EFT=0.1P | Fees for doing an ozow
  • fees.wallet.config.Pay.ZA_OZOW.EFT={WalletID} | Wallet ID to credit for fees charged for ozow
  • source.wallet.config.ZA_OZOW.EFT={WalletID} | Wallet ID to debit when a customer receives funds via ozow

Note:To create a reservation in the credited wallet, until the funds are cleared in the tenant pool account, it is essential to configure the below property. Additionally, payment matching relies on the provided payment reference during Ozow EFT. If no payment reference is provided during the Ozow EFT, the default reference "OZOW + paymentId" will be used which will be mapped to bankReference field on Ozow side.

  • reserveIncomingPayments.ZA_OZOW.EFT=true

Test Data:
Select Demo Bank
Username: [email protected]
Bank password: T3mpP@ssw0rd
OTP:12345

📘

Note

The above credentials are for the staging/test Ozow environment.

For production credentials a contract and account must be setup between the tenant and Ozow directly. Please get in touch with [email protected] to initiate this process.

Example request:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/payments
{
  "externalUniqueId": "ZA_OZOWd284ba3b-5fff-4316-801d-c6b14b90c783-10-1",
  "type": "ZA_OZOW",
  "amount": 1,
  "currency": "ZAR",
  "callbackUrl": "http://testserver.ukheshe.rocks/blank.html",
  "landingUrl": "https://www.google.com/",
  "walletId": 3129,
  "destinationWalletId":2
}

In this request the destinationWalletIdfield determines the destination wallet ID for this payment.

Example response:

{
  "paymentId": 10389,
  "externalUniqueId": "ZA_OZOWd284ba3b-5fff-4316-801d-c6b14b90c783-10-1",
  "status": "PENDING",
  "amount": 100,
  "description": "OZOW EFT Payment",
  "currency": "ZAR",
  "additionalFields": [],
  "acceptedCardSchemes": [],
  "cardPhone": "1234567890",
  "phone": "1234567890",
  "acceptedPaymentMechanisms": [],
  "completionUrl": "https://stagingpay.ozow.io/p/6AG6C4057b2",
  "paymentType": "EFT",
  "created": "2023-10-16T06:12:35.000Z",
  "paymentInstrumentInfo": {
    "cardPhone": "1234567890"
  },
  "fee": 0.1,
  "walletId": 3129,
  "customerId": 3761
}

The returned completionUrl field should be used to complete the payment process through Ozow - this includes:

  • Selecting the bank you wish to pay with your bank account.
  • Logging in with your selected bank account profile. I.e., username and password.
  • Entering an OTP to finalise your payment.

Once the Ozow payment process is completed the user will be redirected back to the URL specified in the landingUrl parameter.

ZA_PNP_CASH

This payment type allows cash in at PicknPay to be used as a payment method into a specific wallet. The payments endpoint returns a token that can be presented with cash at any PicknPay retailer to complete the payment.

Prerequisites

  • A valid JWT for API calls
  • walletId

Required tenant configuration before getting started:

  • fees.amount.config.Pay.ZA_PNP_DEPOSIT.EFT=0.1P | Fees amount
  • fees.wallet.config.Pay.ZA_PNP_DEPOSIT.EFT={WalletID} | Wallet ID to credit for fees
  • source.wallet.config.ZA_PNP_DEPOSIT.EFT={WalletID} | Wallet ID to debit when a customer receives funds

Example request:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
  "type": "ZA_PNP_CASH",
  "amount": 55,
  "callbackUrl": "http://www.google.com",
  "currency": "ZAR",
  "externalUniqueId": "wegesrghshdrgh",
  "destinationWalletId": "192875"
}

In this request the destinationWalletIdfield determines the destination wallet ID for this payment.

Example response:

{
  "paymentId": 74022,
  "externalUniqueId": "wegesrghshdrgh",
  "status": "PENDING",
  "amount": 55,
  "currency": "ZAR",
  "additionalFields": [],
  "acceptedCardSchemes": [],
  "cardPhone": "27723891235",
  "phone": "27723898123",
  "acceptedPaymentMechanisms": [],
  "paymentType": "TELLER",
  "created": "2023-11-17T18:55:52.000Z",
  "paymentInstrumentInfo": {
    "cardPhone": "27723898365"
  },
  "fee": 6,
  "customerId": 190771,
  "gatewayTransactionId": "100919669"
}

The returned field gatewayTransactionId holds the token to be displayed and used when completing the payment at the PicknPay retailer.

By default PicknPay tokens are set to expire at the end of the day after the token was generated. When generating a token the expiry can also be explicitly specified by setting the expires field. However if the expiry is specified, that expiry must be lower than the default to expire at the end of the day after it was issued.

Refer to Suggested prompts to guide customers for PicknPay Cash Top-ups for prompts on how to ensure a successful customer journey when doing PicknPay cash in at retailer payments.

To simulate a successful payment on the sandbox environment (as there is no PnP sandbox where tokens can be submitted as paid), use an amount of 101. This will tell the system to pretend the customer has paid the PnP token 10s after it was requested. This way, one would get the callbacks and the payment would change to SUCCESSFUL. E.g. use "amount":101

Similarly, if the amount is 102 then the PnP payment will be simulated as an expiry 10s after creation so that one would not wait for 1-2 days for an expiry simulation event.

Any other amounts will expire at the end of the next day.

Kenya Payment Types

The following payment types are specific to tenants operating in Kenya.

KE_DTB_STK_PUSH

This payment mechanism can be used on DTB Kenya tenants to request and receive a payment from an MPESA mobile number using the USSD Sim tool kit. The payer's phone will receive a USSD push message asking for confirmation to make the payment. If accepted, the amount would be debited from the MPESA wallet and credited to the wallet being paid.

The transaction would start as PENDING and then transition to either SUCCESSFUL or ERROR_PERM when done. This can take up to 10 depending on how quickly the request is processed on the phone.

Required tenant configuration:

  • fees.amount.config.Pay.KE_DTB_STK_PUSH=0.1P | Fees logic
  • fees.wallet.config.Pay.KE_DTB_STK_PUSH={WalletID} | Wallet ID to credit for fees charged
  • source.wallet.config.KE_DTB_STK_PUSH={WalletID} | Wallet ID to debit when a customer receives funds
POST/eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
  or
POST/eclipse-conductor/rest/v1/tenants/{tenantId}/payments  (for this path, phone must be provided)
Request:
{
   "destinationWalletId": "192875",
   "amount" : 123,
   "currency" : "KES",
   "externalUniqueId" : "dummy-0cfd3208-9c3b-45f7-8595-75dbc9257e2d0",
   "externalWalletId" : "2541231234",
   "externalWalletType" : "SFCM",
   "type" : "KE_DTB_STK_PUSH",
   "destinationWalletId": "192875"
}
Response:
{
   "amount" : 123,
   "created" : "2022-11-15T21:18:32.000Z",
   "currency" : "KES",
   "customerId" : 22188,
   "externalUniqueId" : "dummy-0cfd3208-9c3b-45f7-8595-75dbc9257e2d0",
   "fee" : 0,
   "merchantName" : "Joe Soap",
   "paymentId" : 54148,
   "paymentInstrumentInfo" : {
      "externalWalletId" : "2541231234",
      "externalWalletType" : "SFCM"
   },
   "paymentType" : "EXTERNAL_WALLET",
   "status" : "PENDING",
   "walletId" : 29762
}
➜  ~

The destinationWalletId field is used to indicate what wallet should be credited if the payment request is accepted.
externalWalletId indicates the phone number on MPESA that should be contacted to request payment from
externalWalletType only supports SFCM for now. (Safaricom Mobile)
phone is required if the payment is not posted against a specific customer. If posted against a customer, the customer's phone number from their profile is used. NB: This is the phone number of the person asking for the payment. The MPESA phone making the payment is in the externalWalletId field.

KE_DTB_MPESA_PROMPT

This payment type can be used by Kenyan tenants to request and receive a payment from an MPESA mobile number using the USSD Sim tool kit. This payment type allows payments from an Eclipse Wallet or from a DTB Bank account to a DTB bank account using the below API.

Prerequisites

  • Valid JWT
  • Destination Account Details
  • Payment gateway specified in the 'type' query parameter to KE_DTB_MPESA_PROMPT

Required tenant configuration:

  • fees.amount.config.Pay.KE_DTB_MPESA_PROMPT=0.1P | Fees logic
  • fees.wallet.config.Pay.KE_DTB_MPESA_PROMPT={WalletID} | Wallet ID to credit for fees charged
  • source.wallet.config.KE_DTB_MPESA_PROMPT={WalletID} | Wallet ID to debit when a customer receives funds
POST /eclipse-conductor/rest/v1/tenants/{customerId}/customers/{paymentId}/payments

{
    "externalUniqueId": "c4906be3-0727-4c20-be04-0e2dd8dedd5f",
    "type": "KE_DTB_MPESA_PROMPT",
    "amount": 1,
    "currency": "KES",
    "destinationWalletId": "192875",
    "externalWalletId": "254729294292",
    "description": "test_KE_DTB_MPESA_PROMPT_DigitalPayment to 254729294292",
    "customFraudChecks": false
}
{
    "paymentId": 453785,
    "externalUniqueId": "c4906be3-0727-4c20-be04-0e2dd8dedd5f",
    "status": "PENDING",
    "amount": 1,
    "description": "test_KE_DTB_MPESA_PROMPT_DigitalPayment to 254729294292",
    "merchantName": "tXaCxFicPLoNKiI fAhPZecCneenBxO",
    "currency": "KES",
    "acceptedCardSchemes": [ ],
    "cardPhone": "254729294292",
    "phone": "254729294292",
    "acceptedPaymentMechanisms": [ ],
    "paymentType": "EFT",
    "created": "2023-09-15T10:26:10.000Z",
    "extraInfo": "{"dtbCallingCustomerCif":"a613746a-e8af-444f-9570-d90f2b80bbb7","dtbCallingCustomerId":710113,"dtbCallingCustomerOrganisation":"","dtbSourceCurrency":"KES","dtbSourcePhone":"254729294292","dtbDestinationBankCode":"","dtbDestinationCountryCode":"KE","dtbDestinationCurrency":"KES","dtbDestinationName":"tXaCxFicPLoNKiI fAhPZecCneenBxO","dtbDestinationPhone":"254729294292","dtbDestinationType":"DTB_WALLET"}",
    "paymentInstrumentInfo": {
        "externalWalletId": "254729294292",
        "cardPhone": "254729294292"
    },
    "fee": 0,
    "walletId": 832209,
    "customerId": 710113
}

KE_DTB_AIRTEL_PROMPT

This payment type can be used by Kenyan tenants to request and receive a payment from an Airtel mobile number using the USSD Sim tool kit. This payment type allows payments from an Eclipse Wallet or from a DTB Bank account to a DTB bank account using the below API.

Prerequisites

  • Valid JWT
  • Destination Account Details
  • Payment gateway specified in the 'type' query parameter to KE_DTB_AIRTEL_PROMPT

Required tenant configuration:

  • fees.amount.config.Pay.KE_DTB_AIRTEL_PROMPT=0.1P | Fees logic
  • fees.wallet.config.Pay.KE_DTB_AIRTEL_PROMPT={WalletID} | Wallet ID to credit for fees charged
  • source.wallet.config.KE_DTB_AIRTEL_PROMPT={WalletID} | Wallet ID to debit when a customer receives funds
POST /eclipse-conductor/rest/v1/tenants/{customerId}/customers/{paymentId}/payments
{
    "externalUniqueId": "3ff3706a-7664-47d5-8864-7746d01449fd",
    "type": "KE_DTB_AIRTEL_PROMPT",
    "amount": 100,
    "currency": "KES",
    "destinationWalletId": "192875",
    "externalWalletId": "254729294292",
    "description": "test_KE_DTB_AIRTEL_PROMPT_DigitalPayment to 254729294292",
    "customFraudChecks": false
}
{
    "paymentId": 453933,
    "externalUniqueId": "3ff3706a-7664-47d5-8864-7746d01449fd",
    "status": "PENDING",
    "amount": 100,
    "description": "test_KE_DTB_AIRTEL_PROMPT_DigitalPayment to 254729294292",
    "merchantName": "wKdKOYcesbSiKjZ sRRAuGZpSZkaijh",
    "currency": "KES",
    "acceptedCardSchemes": [ ],
    "cardPhone": "254729294292",
    "phone": "254729294292",
    "acceptedPaymentMechanisms": [ ],
    "paymentType": "EFT",
    "errorDescription": "DTB-999: Error processing POST call to https://10.254.122.3:2284/payments/apimoja after 45000ms with timeout 45000ms :  -- The timeout period of 45000ms has been exceeded while executing POST /payments/apimoja for server 10.254.122.3:2284",
    "created": "2023-09-15T11:45:04.000Z",
    "extraInfo": "{"dtbCallingCustomerCif":"eaaddd0d-db63-42bb-a73c-5cfa9d96eb84","dtbCallingCustomerId":710335,"dtbCallingCustomerOrganisation":"","dtbSourceCurrency":"KES","dtbSourcePhone":"254729294292","dtbDestinationBankCode":"","dtbDestinationCountryCode":"KE","dtbDestinationCurrency":"KES","dtbDestinationName":"wKdKOYcesbSiKjZ sRRAuGZpSZkaijh","dtbDestinationPhone":"254729294292","dtbDestinationType":"DTB_WALLET"}",
    "paymentInstrumentInfo": {
        "externalWalletId": "254729294292",
        "cardPhone": "254729294292"
    },
    "fee": 0,
    "walletId": 832501,
    "customerId": 710335,
    "gatewayTransactionId": "Payment-453933"
}

Global Payment Types

The following payment types are not specific to any region.

GLOBAL_EMVCO

This payment type should be used when paying an MCQR or Visa QRCode. These QR codes are typically supported across both in and outside of South Africa.

Typically before initiating a transaction, a channel will first need to retrieve the QR details to display to the customer. This can be done by calling the wallet QR codes endpoint.

GET /eclipse-conductor/rest/v1/tenants/{tenantId}/wallets/qr-codes?code={qrCode}

Example response body for a Visa QR code:

{
  "code": "0002010102120314400088100743845204525153037105402425802ZA5912Example sandbox6012JOHANNESBURG6228072400000011000000000000000163045AFB",
  "amount": 42,
  "currency": "710",
  "merchantName": "Example sandbox",
  "merchantCity": "JOHANNESBURG",
  "additionalFields": [],
  "acceptedCardSchemes": "VISA",
  "acceptedPaymentMechanisms": "VISAQR"
}

To initiate a transaction for a specific customer:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments

Or if not for a specific customer:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/payments

The only difference between the two endpoints is that the customer endpoint will use the customer's details, whereas the second endpoint requires the customer info to be passed in. The second has an additional field “phone” to indicate the phone number of the customer making the payment. This is required for Masterpass and should be in an international format starting with the country code (e.g. 27831234567).

The data in the POST should include how the QR must be paid and any additional fields needed for the QR.
There are 5 supported means of specifying the source store of value for paying a QR code of type GLOBAL_EMVQRCODE:

  1. Provide a card on file Id for a previously added card on file. This must be a CoF belonging to the caller (JWT). For Visa, this must be a Visa Card.
  2. For PCI-DSS-compliant tenants, the card data can be provided directly in the paymentCardData field.
  3. For tenants with their own store of value and prior integration, they can pass their own externalWalletId and externalWalletType (e.g. ABC12345 and MOBI_CHOICE)
  4. For MCQR the Eclipse walletId to be debited can be provided
  5. Providing none of the above will result in a completionUrl being returned where the customer can capture card data in a lightbox (iFrame) and complete 3DS and the payment.

The value of the paymentSecurityData field depends on the store of value paying the QRCode. If the tenant is the card issuer (bank) they can provide the 3DS fields such as cavv so as to skip 3DS. External stores of value may pass a token as additional authentication (TBD with the tenant).
callbackUrl: Where Eclipse will post the final result when the transaction is complete (optional)
landingUrl: Where to navigate the customer at the end of a lightbox process if the customer has to complete card details / 3DS

Example request body for MCQR:

{
	"amount":5.0,
	"callbackUrl":"https://webhook.site/4146c62c-7e6e-40d8-9649393c3f31cedd",
	"currency":"ZMW",
	"phone":"260971145911",
	"walletId":2184866,
	"type":"GLOBAL_EMVQRCODE",
	"paymentData":{base64 encoded string of the QR that was scanned for this particular payment},
	"externalUniqueId":"83bbe884-a8d0-4543-aa40-bf19854676da"
}

Example response body for MCQR:

{
	"paymentId":455224,
	"externalUniqueId":"4a222654-ff04-4a07-bf28-3925928eac93",
	"status":"SUCCESSFUL",
	"amount":5.000000000,
	"description":"MCQR Payment to Merchant",
	"currency":"ZMW",
	"additionalFields":[],
	"acceptedCardSchemes":[],
	"cardPhone":"26097111234",
	"phone":"26097111234",
	"acceptedPaymentMechanisms":[],
	"paymentType":"WALLET",
	"created":"2023-04-13T12:19:37.000Z",
	"paymentData":{base64 encoded string of the QR that was scanned for this particular payment},
	"paymentInstrumentInfo":
	{	
		"cardPhone":"26097111234"
	},
	"fee":0,
	"walletId":2184123,
	"organisationId":1234
}

Example request body for Visa QR:

{
	"additionalFields":[],
	"cardOnFileId":"46831225-6e23-4a2c-a843-1b147644964c",
	"externalUniqueId":"ed8ae007-d055-4ef6-8120-06f3c580c53a",
	"description":"QR Payment to Pay@",
	"type":"GLOBAL_EMVQRCODE",
	"currency":"ZAR",
	"paymentData":{base64 encoded string of the QR that was scanned for this particular payment},
	"paymentMechanism":"CARD",
	"note":"QR Payment:Merchant XYZ",
  "amount":123
}

Example response body for Visa QR:

{
	"paymentId":48633,
	"externalUniqueId":"87628b95-6624-44dd-84e0-f8d013d4ff6d",
	"status":"PENDING",
	"amount":42,
	"description":"Merchant sandbox",
	"merchantName":"Merchant sandbox",
	"merchantId":"0766521",
	"currency":"ZAR",
	"additionalFields":[],
	"acceptedCardSchemes":[],
	"cardPhone":"271450000013",
	"phone":"271450000013",
	"acceptedPaymentMechanisms":[],
	"paymentType":"CARD",
	"created":"2023-04-21T12:29:12.000Z",
	"paymentData":{base64 encoded string of the QR that was scanned for this particular payment},
	"paymentInstrumentInfo":
		{
			"cardBin":"XX",
			"cardType":"00",
			"cardLast4":"XX",
			"cardName":"XXX",
			"cardPhone":"271450000013"
		},
	"fee":0,
	"customerId":261223,
	"note":"QR Payment:Merchant sandbox",
	"gatewayTransactionId":"5f91add9-b7f3-5frfg-b90e-15489b7f8101"
}

If a completion URL is returned the customer can be navigated to the completionUrl to complete 3DS after which they will be sent to the landingUrl when the payment completes (failed or successful), a callback will be done to callbackUrl with the result of the payment in the same format as if a GET was done on the paymentId.

If an EMVCo QR payment has a status of SUCCESSFUL then the card/wallet has been debited and the merchant has been notified of the successful transaction and the customer can get their goods/services.

Refer to the sandbox test accounts section for sample QR codes and use cases.

GLOBAL_PAYMENT_LINK

Payment links can be created as a simple means of requesting a payment which will clear into a specific wallet. Once the link is generated, it can be shared with the payer, who can open the link in a browser and decide how to make the payment by choosing one of many payment mechanisms depending on the tenant configuration. These may include cards, closed-loop wallet providers, cash deposit instructions, EFT instructions etc. Currently, the payment method is limited to cards only.

To generate a payment link, pass the currency, amount, type and GUID in externalUniqueId. The destination walletId should be populated in the destinationWalletId field.

Prerequisites

  • Valid JWT
  • Payment links uses Eclipse Hosted Checkout to complete the payment process. The Hosted Checkout configuration needs to be complete (see Hosted Checkout for full details). E.g. the paymentType parameter must be added to the global property public.tenant.{tenantId} - allowed values are mastercard, ozow and pnpcash

To initiate a transaction for a specific customer:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments

Example payload:

{
  "type":"GLOBAL_PAYMENT_LINK",
  "destinationWalletId": "192875",
  "amount":123,
  "currency":"ZAR",
  "externalUniqueId":"193b88b5-a448-418a-84ed-0c8f15c957fd5", 
  "callbackUrl":"https://letmeknowwhendone.com/abc",
}

Example Response:

{
  "paymentId":65678,
  "externalUniqueId": "193b88b5-a448-418a-84ed-0c8f15c957fd5",
  "status":"PENDING",
  "amount":123.000000,
  "currency":"ZAR",
  "acceptedCardSchemes": [],
  "cardPhone": "2723456789",
  "phone": "2723456789",
  "acceptedPaymentMechanisms": [],
  "completionUrl":"https://ukheshe.live/t/5vV4A",
  "paymentType": "LINK",
  "created": "2023-04-21T12:29:12.000Z",
  "paymentInstrumentInfo": {
    "cardPhone": "2723456789"
  },
  "fee": 0,
  "walletId": 12345,
  "customerId": 54321
}

Or if not for a specific customer:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/payments

Example payload:

{
  "type":"GLOBAL_PAYMENT_LINK",
  "amount":123,
  "callbackUrl": "https://letmeknowwhendone.com/abc",
  "destinationWalletId": "192875",
  "currency":"ZAR",
  "externalUniqueId":"183b88b5-a448-418a-84ed-0c8f15c95c5b",
}

Example Response:

{
  "paymentId":3117,
  "externalUniqueId": "183b88b5-a448-418a-84ed-0c8f15c95c5b",
  "status":"PENDING",
  "amount":123.000000,
  "currency":"ZAR",
  "acceptedCardSchemes": [],
  "acceptedPaymentMechanisms": [],
  "completionUrl":"https://ukheshe.live/t/e94EE",
  "paymentType": "LINK",
  "created": "2023-04-22T12:29:12.000Z",
  "paymentInstrumentInfo": {},
  "fee": 0,
  "walletId": 12345
}

The customer can then be sent the completionUrl or it will open for them in their browser and they can complete the payment. When the payment completes, a callback is done to the callbackUrl with the result. A payment link can only be paid once.

The tinyUrl returned in completionUrl is only valid for 24h. If a longer duration is needed then the URL can be fetched to get the final destination and used instead. The actual underlying payment link never expires.

GLOBAL_REUSABLE_PAYMENT_LINK

This is, similar to GLOBAL_PAYMENT_LINK, used to generate a payment link for a user. However, it differs in the following ways:

Reusability

The globally reusable payment link remains valid indefinitely, However, when the tenant shares this link with the customer for payment purposes, they retain the flexibility to set an expiration date. The payment link can be used as many times as requested, making it suitable for multiple payments.

Customization

The destinationWalletId field is used to set the destination merchant wallet for facilitating payments. This grants a high degree of flexibility in the precise routing of payments to the intended merchant. For backwards compatibility legacy fields paymentData and merchantWalletId can also be used to set this.

Query Parameters

The payment link returned is a baseUrl with some predefined query parameters like (tenantId=&interactionType=makePayment&paymentId=), and when using payment link for payment, predefined and additional query parameters must also be provided with base URL. The additional query parameters (amount, description, reference, expiryDate, uniqueId) can be set according to tenant requirements, allowing tenants to fix the amount, description, and reference for the payment link. These query parameters include:

  • amount: Specifies the payment amount.
  • description: Provides a description of the payment.
  • reference: Includes a reference associated with the payment.
  • expiryDate (Optional Parameter): This parameter allows tenant to set an expiration date for a payment link that the tenant provides to their customers. It is used to specify the date after which the link will no longer be valid for payment. the expiry date format must be yyyy-MM-dd
  • uniqueId (Optional Parameter): This parameter is designed to ensure uniqueness and prevent customers from making multiple payments using the same link. It accepts a random UUID (Universally Unique Identifier) of up to 200 characters in length. This unique identifier helps maintain the integrity of the payment process by guaranteeing that each link is used only once by the customers.
  • qrcode (optional Parameter): If passed then the amount, description, reference, etc. are all retrieved from the associated QR code already created in Eclipse. This allows tenants to easily create payment links to accompany existing QR Codes. When query parameter qrcode is passed, no other query parameters are needed as all are retrieved from the QR Code definition. Though amount, description and reference can be passed as override query parameters. Example payment link URL: https://eclipse-java-sandbox.ukheshe.rocks/eclipse-conductor/rest/v1/payment-links/12536/payment-redirects?qrcode=3808771596

Securing Query Parameters

To prevent users from modifying certain query parameters, the creation of global reusable links mandates that tenants include an HMAC key within the additional parameters. This HMAC key serves as a critical component for executing an HMAC-SHA256 Base64 encoding operation on the query parameters. Tenants are required to employ this HMAC key to generate a HMAC-SHA256 Base64-encoded signature of the query parameters, and this signature must be included as a query parameter alongside others when customers initiate payments. Eclipse, as the verifying entity, meticulously examines and verifies this signature, guaranteeing the integrity of query parameters and preventing any tampering by users.

Example:

  1. Provide HMAC secret key when creating re-usable payment link:
"additionalFields": [
        {
            "id": "HMACKey",
            "value": "9B815B722E2CC6A1937A5F50F03FD84B2B54AEFE"
        }
    ]
  1. Generate a signature for the query parameters:
Secret key: 
HMACSHA256 of “amount=150&description=Payment&reference=Payment” with HMAC key:9B815B722E2CC6A1937A5F50F03FD84B2B54AEFE
is:
Base64: VmojFsBBdj26AzVcs9NtGW935WzqzG2q3f7TQPKQIOQ=
  1. Append the returned completion URL with signature query parameter:
https://eclipse-java-sandbox.ukheshe.rocks/eclipse-conductor/rest/v1/payment-links/434984/payment-redirects?amount=150&description=Payment&reference=Payment&signature=VmojFsBBdj26AzVcs9NtGW935WzqzG2q3f7TQPKQIOQ=

📘

Note

  • Only the following parameters need to be verified with an HMAC signature: amount, description, reference
  • Other fields can be passed as is and should be used to generate the HMAC signature.
  • When generating the HMAC signature for query parameters, it is imperative that they be arranged in alphabetical order.

The HMAC Key is passed in the additionalFields field as HMACKey (see example request body below). Below is Java example for generating a random AES256 bit key to generate the HMAC Key:

  KeyGenerator generator = KeyGenerator.getInstance("AES");
  generator.init(256);
  String key = generator.generateKey().getEncoded().toString();
  System.out.println("HmacKey :: " + key);

Payment Process

Upon a customer's interaction with the generated payment link in their web browser, they are seamlessly redirected to a hosted payment page. This page offers an array of payment options, including CARD PAYMENT, PNP CASH, SCAN TO PAY and OZOW, facilitating the completion of the payment process in a user-friendly and secure environment.

Callbacks

Tenants have the flexibility to define a specific callback URL, which serves as the designated notification endpoint. This URL is set during the creation of a global reusable payment link. Whenever a payment is successfully made through this link, the tenant will receive notifications at the specified URL. This mechanism ensures that tenants are promptly informed of any payment transactions associated with the payment link

Prerequisites

  • Valid JWT
  • Payment links uses Eclipse Hosted Checkout to complete the payment process. The Hosted Checkout configuration needs to be complete (see Hosted Checkout for full details). E.g. the paymentType parameter must be added to the global property public.tenant.{tenantId} - allowed values are mastercard, ozow and pnpcash

Create a Global Reusable Payment Link

Note a payment can be made against a specific customer with:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments

Or not specific to a customer with:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/payments

Example request:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/payments
{
  "externalUniqueId": "2321423435434734877342353",
  "landingUrl": "https://google.com",
  "callbackUrl": "https://google.com",
  "additionalFields": [
    {
      "id": "HMACKey",
      "value": "gkgkkf89498jfjfk489494"
    }
  ],
  "currency": "ZAR",
  "customFraudChecks": false,
  "destinationWalletId": "3298",
  "type": "GLOBAL_REUSABLE_PAYMENT_LINK"
}

Example Response:

{
  "paymentId": 12255,
  "externalUniqueId": "2321423435434734877342353",
  "status": "PENDING",
  "currency": "ZAR",
  "additionalFields": [
    {
      "id": "merchantName",
      "value": "XYZ"
    },
    {
      "id": "HMACKey",
      "value": "gkgkkf89498jfjfk489494"
    }
  ],
  "acceptedCardSchemes": [
    
  ],
  "cardPhone": "27607901053",
  "phone": "27607901053",
  "acceptedPaymentMechanisms": [
    
  ],
  "completionUrl": "https://eclipse-java-sandbox.ukheshe.rocks/eclipse-conductor/rest/v1/payment-links/434984/payment-redirect",
  "paymentType": "LINK",
  "created": "2023-10-19T05:26:45.000Z",
  "paymentInstrumentInfo": {
    "cardPhone": "27607901053"
  },
  "fee": 0,
  "walletId": 3298,
  "customerId": 54
}

Make Payment

In generating the payment link to share with the customer the tenant needs to create the HMAC signature if query parameters amount, description, reference are passed.

Sample Customer PaymentLink

https://eclipse-java-sandbox.ukheshe.rocks/card-ui/index.html?tenantId=2&interactionType=makePayment&paymentId=12255&merchantName=XYZ&amount=1&description=TEST&reference=test&signature=M6s/a9iLuJC3TgkmojRecrG9QqzqgkxRtUfn5lePyxs=

Here signature, 'M6s/a9iLuJC3TgkmojRecrG9QqzqgkxRtUfn5lePyxs=', has been generated using HMAC-SHA256 and then encoded in BASE64. This signature was created based on the parameters in alphabetical order: 'amount=1&description=TEST&interactionType=makePayment&merchantName=XYZ&paymentId=12255&reference=test&tenantId=2'.

The customer can then be sent the completionUrl or it will open for them in their browser and they can complete the payment. When the payment completes, a callback is done to the callbackUrl specified when creating the reusable payment link with the result.

Partial Payments

Partial payments are supported by both GLOBAL_REUSABLE_PAYMENT_LINK and GLOBAL_PAYMENT_LINK payment types by setting the minAmount and maxAmount parameters available in the Payments API.

The following rules apply:

  • If amount is set to zero or null, the customer will be able to enter any amount for payment.
  • If minAmount is provided, the customer can pay any amount equal to or more than the minAmount specified.
  • If maxAmount is provided, the customer can pay any amount equal to or less than the maxAmount specified.
  • If minAmount and maxAmount are provided, the customer can pay any amount within the boundaries specified.

📘

Note

When a payment link of type GLOBAL_REUSABLE_PAYMENT_LINK is used in conjuction with a QR Code, the minAmount and maxAmount can be set on the payment link or on the associated QR code and the above rules apply. It is important to note that if the minAmount and maxAmount fields are specified on the payment link then the same values must be set on the associated QR code. If the values differ, an error will be generated.

GLOBAL_VAS

This payment type is for executing VAS purchases. For full details on this payment type including examples, please refer to VAS Use Cases.

GLOBAL_WALLET

This payment type is used for executing card payments destined for a particular wallet on Eclipse. This is most typically used in the Card Acquiring - E-commerce use case where card payments can be processed into a particular organisation wallet.

Prerequisites

  • If implemented in South Africa the tenant should be setup as a merchant on Scan To Pay.
  • An Eclipse tenant should be created for the merchant.
  • A placeholder customer should be created on the tenant against which the customer card on file details can be stored. This is the typical pattern utilised by tenants enabling e-commerce - where the tenant already has an existing customer management platform and just uses Eclipse to tokenise and store the card on file details. However the full customer details could also be stored in Eclipse.
  • Optionally an organisation and organisation wallet should be created on the tenant. This wallet is owned by the tenant and the ledger of this wallet will contain all the transactions that are processed by the merchant.
  • A System Wallet should be created as the source wallet for all card payments. When a payment is processed this wallet will be debited and the merchant wallet will be credited.
  • If Scan To Pay is used as the card payment process the following tenant configs should be populated:
  1. masterpass.config.apiUser
  2. masterpass.config.apiPassword
  3. masterpass.config.aesKey
  4. masterpass.config.cnp.apiUser
  5. masterpass.config.cnp.apiPassword
  6. source.wallet.config.ZA_MASTERPASS_IN.CARD.SERVER - set to the source system wallet ID.
  7. fees.amount.config.Pay.ZA_MASTERPASS_IN.CARD.SERVER - any fees applicable, typically set to 0 for this use case.
  8. fees.wallet.config.Pay.ZA_MASTERPASS_IN.CARD.SERVER - destination wallet for fees, only applicable if fees.amount.config.Pay.ZA_MASTERPASS_IN.CARD.SERVER is set.

Typically the tenant will use the Eclipse captive portal to capture and display any card details. This can be customised according to the tenants branding by following the steps documented here.

Step 1 - Optionally retrieve stored card on file details

If the tenant is storing tokenised customer card on file details on a placeholder customer on Eclipse they can retrieve these card details and then perform mapping on their platform to present the correct cards to the correct customers in their channel.

Below is an example request and response - the {customerId} path parameter would be the customerId of the placeholder customer created as part of the pre-requisites.

GET eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/cards-on-file
{
  "alias" : "Customer XYZ Card on file",
  "bin" : "424242",
  "cardOnFileId" : "1ec1245665-aa49-4806-b132-c41231c01e9",
  "expires": "2023-11-01T00:00:00.000Z",
  "last4Digits" : "4242",
  "status" : "ACTIVE"
}

Step 2 - Initiate Payment and store card on file details

Once all the pre-requisites have been met the tenant just needs to initiate and complete a payment using the payments API. The {customerId} path parameter should be the customerId of the placeholder customer created as part of the pre-requisites. The type field should be set to GLOBAL_WALLET and the paymentData field should be set to the merchant wallet ID (the wallet setup on the organisation as part of the prerequisites).

There are various options for initiating card payments documented under the Payments Use Cases - below is an example request where a landingUrl is provided and therefore Eclipse returns a completionUrl to capture card details and complete 3DS. In addition the storeCardOnFile field is set to true, meaning any card details captured will be saved against the placeholder customer for future retrieval.

POST eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
  "type": "GLOBAL_WALLET",
  "amount": 6000,
  "currency": "ZAR",
  "externalUniqueId": "rhfabcdfggthygfgfgh",
  "destinationWalletId": "197252",
  "paymentMechanism": "CARD",
  "storeCardOnFile": true,
  "landingUrl": "http://www.google.com",
  "callbackUrl": "http://www.google.com",
  "phone": "27723888364"
}

Below is an example response:

{
  "paymentId": 54726,
  "externalUniqueId": "rhfabcdfggthygfgfgh",
  "status": "PENDING",
  "amount": 6000,
  "description": "Ukheshe Test 2021  : Transaction Details",
  "merchantName": "Ukheshe Test 2021 ",
  "currency": "ZAR",
  "partialPaymentAllowed": false,
  "additionalFields": [],
  "acceptedCardSchemes": [
    "MASTER",
    "VISA",
    "MAESTRO",
    "AMEX"
  ],
  "cardPhone": "27723891234",
  "phone": "27723891234",
  "acceptedPaymentMechanisms": [
    "AMT",
    "SECURE_CODE",
    "CNP"
  ],
  "completionUrl": "https://eclipse-java-sandbox.ukheshe.rocks/t/wXYR37",
  "paymentType": "CARD",
  "created": "2023-06-27T09:03:05.000Z",
  "lastModified": "2023-06-27T09:03:07.992Z",
  "paymentData": "6481005932",
  "paymentInstrumentInfo": {
    "cardPhone": "27723891234"
  },
  "fee": 0,
  "customerId": 1901324,
  "gatewayTransactionId": "MP-PR-44134774"
}

To complete the payment the tenant should navigate to the URL returned in the completionUrl field - this will redirect to a captive portal hosted within the Eclipse PCI environment to provide any card details and also to complete 3DS. Once the transaction is completely the payment details will be posted to the URL provided in the callbackUrl in the request.

GLOBAL_TOG

This payment type is for executing Tap On Glass payments. Please refer to the Tap On Phone with Visa Acceptance Cloud (VAC) use case for full details.

GOOGLE_PAY

Google Pay allows a user to store card details to their Google Account and then use those details to pay on sites, in apps, and in stores in a fast, easy and secure way.

Eclipse supports Google Pay as means to securely retrieve a customers card details from Google and use them to complete any Eclipse payment that takes card details as the payment method, e.g. ZA_QR_CODE, GLOBAL_WALLET, GLOBAL_VAS.

The high level process is as follows:

  1. The tenant application integrates to Google Pay to include a Google Pay button and to send payment requests to Google Pay. The details to integrate to Google Pay are documented here and there are specific brand guidelines to adhere to documented here.
  2. Google Pay returns an encrypted payload including the card details to the tenant application.
  3. The tenant application calls Eclipse for any payment type that supports card details as the payment method (e.g. ZA_QR_CODE, GLOBAL_WALLET, GLOBAL_VAS) and includes the encrypted payload in the encryptedPaymentCardData field:
"encryptedPaymentCardData": 
{
    "base64EncryptedPayload": "XYZ",
    "type": "GOOGLE_PAY"
}
  1. Eclipse decrypts the encrypted payload and then processes the card payment as usual.

Here is an example request to Eclipse to process a payment of type ZA_QR_CODE using the encrypted payload returned from Google Pay:


POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
  "externalUniqueId": "TEST963852",
  "amount": 7,
  "callbackUrl": "https://webhook.site/3ebf48d7-0ad7-418d-b7c7-b0be39b97f5d",
  "currency": "ZAR",
  "description": "This is Google Pay testing (*&^%$# 651352",
  "encryptedPaymentCardData": {
    "base64EncryptedPayload": "eyJzaWduYXR1cmUiOiJNRVlDSVFDemw4WDAwcEswVmRqNStRMEtNZjRoSm12Znp6TE8vT2NGUlhHK01POXYvd0loQU1Cd1ZoMmwxdFcwbkp6YmsrYkl0K094TE9xTXhoRVlheFRTNUhUQ0JPQ2siLCJpbnRlcm1lZGlhdGVTaWduaW5nS2V5Ijp7InNpZ25lZEtleSI6IntcImtleVZhbHVlXCI6XCJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUvaGJrdFh6eUFPSkYzYXdEVEJYak9RangxRFQ1OW9kdTlDYWd4MUhUTEY0OGI3SlBhbUpoOEQzQzdUM2t5azdZUjMvV2xubDlqbnc3bjlxRGplb1pvUVxcdTAwM2RcXHUwMDNkXCIsXCJrZXlFeHBpcmF0aW9uXCI6XCIxNzExNDkzMTE2NDAwXCJ9Iiwic2lnbmF0dXJlcyI6WyJNRVVDSUZaSGFkSCtPMlVPU2dmcENsWkN3eTRPS3FlcGtSckFidDJHUXp5MEVaS2tBaUVBcnMvRWNjNVZZVGRUaFI1UVdETFUycVRVNnkxTjlYNitURGcxdW55TXhqOFx1MDAzZCJdfSwicHJvdG9jb2xWZXJzaW9uIjoiRUN2MiIsInNpZ25lZE1lc3NhZ2UiOiJ7XCJlbmNyeXB0ZWRNZXNzYWdlXCI6XCJyaGkrVm96cjVMVi9RaklhdEVhbWFJTFlaOGZsVHRGYTlpa1NnZTBIeUp0RHZvd0NweEo4ZWdLOFBHM3R1VkZBYTU4UEhkazBKYTFWTEVpcng5UWczNHFTZUZIT2RiOUxTanlMQXFTa285aHNjdlFWanh6RzZneEYwcTEzclZLSDVQcFdicXR3Zyt5Rkxra1JCL1ZlNTMySFR6dXVzQUVTTVZzczh5UHhWV09YZ0ZJd2ZkT2xTTk9hVzluRXJBZmdrRVhoVXMyQ0xtTUZ0S1czekVpV3lqeFNESUl1UzFqV1l5WkZnZXNVbWV0eURDcG5vS3J4dU9yYjRoajQ1dkxJbDNuOHF5SVRrZlFMeGdEWVl2NndMekhJcHBFZEVDdURjWE9XUzl0TWhzdG1HTzVFWk52UW1rTGJPekhLZjhTeGp2OWt1ZEJPSFVlb0c4eGZSUWlPS1BGbjJqZEw4OVpIYlJWclZ5dkYzYkZVclg2WGc0a1YwV2t0VGFCR3pVWnN1dGRDb0FBSDBQQWc4QThhOGRVVnYzQzIyVjdENnRGanhpdzJLaVhRR2RIT2xFMDZQb0hFZFhCcXdHRVU1cTU5THdHdTN1QTl1NzJLWHhaajRpdTVQRDY5YVF5cjNRYUVzdUlVQ2NaTlJRWUlRdFFPQ1MzM1VnY1lTdEt5TTJLRDFtcW9oOElVdzdzb3JXMWswaUZaeWZSNHRIVUNTTlIybFVMVE4yTE12amJFamxxOENLTklGVVVJaFJ0aU5XSTg4ZUZWY3dBU1o2SnhcIixcImVwaGVtZXJhbFB1YmxpY0tleVwiOlwiQkJrWHpNandyeVBNckI0dC81cHdyMGhRZFF4SUtWQ01WbTM3SDF2b3A2QUpCMTdVWlJIM2FpSWVNL2twQjBERWtxaGlETnBxRVd2QnJVYUlJSWxjOEdnXFx1MDAzZFwiLFwidGFnXCI6XCJodm9ZRW0xTmdBVnU1bkRoRjQ1TkxDbDZmOUFnZ2JHZUxwY3RRWm5HY1RzXFx1MDAzZFwifSJ9",
    "type": "GOOGLE_PAY"
  },
  "type": "ZA_QRCODE",
  "paymentData": "2308923752"

}

An example response (this is no different from the usual response for a payment of this type):

{
  "paymentId": 14872,
  "externalUniqueId": "TEST963852",
  "status": "PENDING",
  "amount": 7,
  "description": "Ukheshe Test 2021  - PTS Nedbank Ruleset : drdgdfgx",
  "merchantName": "Ukheshe Test 2021  - PTS Nedbank Ruleset",
  "currency": "ZAR",
  "partialPaymentAllowed": false,
  "additionalFields": [],
  "acceptedCardSchemes": [
    "MASTER",
    "VISA",
    "MAESTRO",
    "AMEX"
  ],
  "cardPhone": "27987654321",
  "phone": "27987654321",
  "acceptedPaymentMechanisms": [
    "AMT",
    "SECURE_CODE",
    "CNP"
  ],
  "completionUrl": "https://eclipse-java-develop.ukheshe.rocks/t/64uqb",
  "paymentType": "CARD",
  "created": "2024-03-20T04:58:46.000Z",
  "lastModified": "2024-03-20T04:58:47.168Z",
  "paymentData": "2308923752",
  "paymentInstrumentInfo": {
    "cardBin": "411111",
    "cardType": "00",
    "cardLast4": "1111",
    "cardName": "Ukheshe Google Pay 3993",
    "cardPhone": "27987654321"
  },
  "fee": 0,
  "customerId": 3993,
  "gatewayTransactionId": "MP-PR-4672233",
  "paymentTerminalData": {}
}

Lodge card payments

A lodge card allows customers to pay QR codes (payment type ZA_QRCODE or GLOBAL_EMVCO) from a closed loop Eclipse digital wallet using a tenant or Ukheshe lodge card to do the card rails payment on behalf of the customer.

The following configurations are required to enable this scenario:

  1. A special lodge card user must be created and the lodge cards added to this customer as cards on file - if multiple cards are present, cards are selected for payment by round-robin
  2. Tenant configuration parameter closedLoopCardOnFileUserId must be set to the lodge card user ID
  3. Tenant configuration parameter ${card_on_file_id}.pin must specify the pin of the cards on file - this data is encrypted
  4. Tenant configuration parameter destination.wallet.config.ZA_MASTERPASS.EXTERNAL_WALLET.GLOBAL_ECLIPSE must be set to the destination system wallet for lodge card payments

📘

Note

For South Africa where Scan to Pay is used as the card payment processor, any lodge cards should be added to the Scan to Pay whitelist.

Lodge card flow of funds

Payment Reversals

Once a payment is successful, the recipient can choose to reverse the payment back to the payer. This functionality depends on the payment type as some payment methods are impractical to reverse or simply do not support this technically.

In order to reverse a payment, the PUT endpoint can be used to change the status of the payment to REVERSED:

If the gateway supports this, then the API will return and indicate that the payment status is now REVERSED. Eclipse will take care of ensuring the funds are debited from the payment destination wallet and credited to the customer's payment source.

Payment Refunds

Successful payments can be refunded depending on the payment type. There is a marked difference between refunds and reversals:

  • A partial or full refund can be done - the refund amount can not exceed the original amount.
  • Multiple partial refunds can be done on the same payment - the sum of all refund amounts can not exceed the original amount.
  • A refund initiates an entirely new transaction.

For supported payment types refunds can be initiated in the Eclipse Admin Portal by navigating to the payments tab on on a particular customer, selecting the details of a payment and initiating a refund:

This can also be done using the Payment Refund API. Example request:

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}/refunds
{
	"amount": 20,
	"description": "test",
  "callbackUrl": "https://webhook.site/967d45f9-2df3-4193-9fdc-2974c02786a2",
  "externalUniqueId": "54j6nmu34e"
}

Example response:

{
    "refundId": 37,
    "paymentId": 437115,
    "amount": 20.000000000,
    "description": "test",
    "status": "PENDING",
    "created": "2023-04-22T13:04:52.000Z",
    "lastModified": "2023-04-22T13:04:53.866Z",
    "externalUniqueId": "54j6nmu34e",
    "gatewayTransactionId": "MP-4745931"
}

If the callbackUrl parameter is set the result is posted to that URL. The object posted is the same as the refund entity returned on the get refund endpoint and includes the following fields: refundId, amount, status and externalUniqueId, for example:

{
  "refundId": 37,
  "amount": 12,
  "status": "SUCCESSFUL",
  "externalUniqueId": "3t524335yerhdfhfg"
}

Payment Status State Diagram

Payments have the following potential statuses:

  • BUILDING: Being built up and does not have sufficient information to submit downstream and become PENDING
  • PENDING: Being processed by the downstream gateway
  • SUCCESSFUL: Successfully completed
  • ERROR_PERM: Failed and won’t ever succeed,
  • ERROR_TEMP: Currently having an error but it's being retried and may succeed or permanently fail. (e.g. the downstream provided got a system error processing our last request for a status update)
  • TIMEOUT: Failed as the process was not finalised in time
  • CANCELLED: Cancelled while in PENDING status
  • REVERSED: Reversed after being SUCCESSFUL
624

Payment Status State Diagram