VAS Use Cases
Eclipse has integrations to a number of VAS providers covering a wide range of services from airtime, electricity, bill payments, etc. Typically the process for purchasing VAS involves 4 steps:
- Retrieve the VAS catalog
- Get network partner ID for mobile number - this is optional and relevant only for airtime VAS. Here you retrieve the partner ID for the provided mobile number, this queries the relevant mobile number portability database.
- Prepare catalog query - this is optional and the entire catalog can be retrieved.
- Initiate VAS payment - typically the payment data consists of the partnerId and productId of a product in the VAS catalog separated with a "_" e.g. 2_ABC123
- Complete VAS Payment
Here are details for specific providers.
South Africa VAS providers
The following VAS providers are specific to tenants operating in South Africa.
Purchase VAS from Scan to Pay
Introduction
Scan to Pay is a QR code payment solution for seamless and contactless transactions. Scan to Pay revolutionizes the way merchants and consumers interact financially.
For merchants, Scan to Pay offers the flexibility to create and manage static or dynamic QR codes, enabling them to accept payments effortlessly. Whether you're a local store, restaurant, or an online business, our platform ensures a smooth payment experience for your customers.
Consumers benefit from the convenience, safety, and security of Scan to Pay. Consumers can simply scan the QR code, confirm the transaction, and they're done! No need to worry about carrying cash or cards.
One feature of Scan to Pay is to efficiently enable consumers to purchase VAS products of their choosing within the application.
Prerequisites
- A valid JWT for API calls.
- tenant config mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.MasterpassRechargeProvider
- tenant config oltio.config.username={scan_to_pay_username}
- tenant config oltio.config.password={password}
- tenant config destination.wallet.config.VAS.1={destination walletId}
Step 1 - Verify mobile number (MSISDN) network
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/{msisdn}
NoteCurrently only MTN And Vodacom are supported networks
Step 2 - Get the list of VAS partners & products
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogsStep 3 - Filter the catalog
Once the catalog is returned, the channel must filter it based on the MSISDN provided in step 1.
Select the productId from the catalog to proceed with the payment process (e.g., "productId": "VD11").
Below is an example of a filtered catalog response:
[
{
"partnerId": 5,
"partnerName": "Vodacom",
"providerId": 1,
"products": [
{ "partnerId": 5, "productTypeName": "SMS", "productId": "VS02", "productName": "SMS20" },
{ "partnerId": 5, "productTypeName": "SMS", "productId": "VS03", "productName": "SMS50" },
{ "partnerId": 5, "productTypeName": "SMS", "productId": "VS04", "productName": "SMS100" },
{ "partnerId": 5, "productTypeName": "DATA", "productId": "VD11", "productName": "DATA75MB" },
{ "partnerId": 5, "productTypeName": "DATA", "productId": "VD12", "productName": "DATA240MB" },
{ "partnerId": 5, "productTypeName": "DATA", "productId": "VD13", "productName": "DATA400MB" },
{ "partnerId": 5, "productTypeName": "DATA", "productId": "VD14", "productName": "DATA600MB" },
{ "partnerId": 5, "productTypeName": "DATA", "productId": "VD50", "productName": "DATA2.5GB" },
{ "partnerId": 5, "productTypeName": "AIRTIME", "productId": "01", "productName": "100 Minutes" },
{ "partnerId": 5, "productTypeName": "AIRTIME", "productId": "03", "productName": "500 Minutes" },
{ "partnerId": 5, "productTypeName": "AIRTIME", "productId": "05", "productName": "250 Minutes" }
]
}
]Initiating a VAS Payment
For FrontierWeb Services, the POST to /payments performs both the pre-vend (validation) and the vend (fulfilment) steps in a single call. The response is returned synchronously once both have completed. There is no separate PUT step required for FrontierWeb (unlike Scan to Pay or ACS).
The paymentData field follows one of two formats depending on the product:
- Airtime (fixed-price products):
{partnerId}_{productId}_0— e.g.20_501_0 - Two-stage products (utility token, DSTV):
{partnerId}_{vendProductId}_{prevendProductId}— e.g.20_1248_1247(Utility Token + Utility Pre-Vend)
PartnerId for FrontierWeb Services is 20.
Use Case 1 — Utility Token (Electricity)
The purpose of this integration is to process utility token purchases. The pre-vend validates the meter number against the upstream utility (Conlog Botswana); the vend issues the token. The token and customer receipt are returned in the extraInfo field.
Prerequisites
- A valid JWT for API calls.
- Tenant config
fees.amount.config.Pay.GLOBAL_DEFERRED.WALLET.{partnerId}.{productCategory}=feeAmount - Tenant config
fees.wallet.config.Pay.GLOBAL_DEFERRED.WALLET=destinationWalletId(fee destination) - Tenant config
destination.wallet.config.VAS.{partnerId}.{productCategory}=destinationWalletId(VAS settlement destination)
Initiate Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"externalUniqueId": "{{$randomUUID}}",
"paymentData": "20_1248_1247",
"type": "GLOBAL_VAS",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
},
{
"id": "meterNumber",
"value": "21500123456"
}
],
"amount": 180,
"currency": "BWP",
"walletId": 2536583
}Example Response
{
"paymentId": 4007245,
"externalUniqueId": "2c6d4298-d9c8-4616-82ef-c1f7e446cec7",
"status": "SUCCESSFUL",
"amount": 13.000000000,
"description": "VAS purchase PartnerId-20 : Utility Token",
"currency": "BWP",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
},
{
"id": "meterNumber",
"value": "21500123456"
}
],
"paymentType": "WALLET",
"created": "2025-12-08T11:09:49.000Z",
"lastModified": "2025-12-08T11:09:50.124Z",
"paymentData": "20_1248_1247",
"extraInfo": "[{\"callbackId\":72628017,\"result\":\"...token, customerReceipt and electricityResponse payload...\"}]",
"fee": 4,
"paymentReference": "1248_1247",
"walletId": 2536583,
"customerId": 8586330,
"gatewayTransactionId": "Payment-4007245"
}
NoteSandbox test meter numbers:
00300123452or21500123456(Conlog Botswana fixture). In sandbox, invalid meter numbers may still returnstatus: SUCCESSFULas pre-vend validation against the live utility provider is bypassed in non-production environments.
Use Case 2 — DSTV Recharge
The purpose of this integration is to allow customers to pay DSTV subscriptions. The pre-vend validates the DSTV account number; the vend recharges the account.
Prerequisites
- A valid JWT for API calls.
- Tenant config
fees.amount.config.Pay.GLOBAL_DEFERRED.WALLET.{partnerId}.{productCategory}=feeAmount - Tenant config
fees.wallet.config.Pay.GLOBAL_DEFERRED.WALLET=destinationWalletId - Tenant config
destination.wallet.config.VAS.{partnerId}.{productCategory}=destinationWalletId
Initiate Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"externalUniqueId": "{{$randomUUID}}",
"paymentData": "20_1260_1259",
"type": "GLOBAL_VAS",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
},
{
"id": "accountNumber",
"value": "12345678"
}
],
"amount": 33,
"currency": "BWP",
"walletId": 2536583
}In this use case the paymentData field is set to {partnerId}_{vendProductId}_{prevendProductId} i.e. 20_1260_1259
PartnerId = 20
VendProductId = 1260 (Bots DSTV Recharge)
PrevendProductId = 1259 (Bots DSTV Balance)
The response shape mirrors the Utility Token response above.
Use Case 3 — Airtime Purchase
LFSB wallet holders can purchase airtime from Orange, BE Mobile, and Mascom. Airtime products are fixed-price, so the amount value is determined by the selected productId and does not need to be supplied on the request.
Prerequisites
- A valid JWT for API calls.
- Tenant config
fees.amount.config.Pay.GLOBAL_DEFERRED.WALLET.{partnerId}.{productCategory}=feeAmount - Tenant config
fees.wallet.config.Pay.GLOBAL_DEFERRED.WALLET=destinationWalletId - Tenant config
destination.wallet.config.VAS.{partnerId}.{productCategory}=destinationWalletId
Initiate Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"externalUniqueId": "{{$randomUUID}}",
"paymentData": "20_501_0",
"type": "GLOBAL_VAS",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
}
],
"currency": "BWP",
"walletId": 2536583
}In this example 20_501_0 purchases BE MOBILE 20 (productId 501). The trailing _0 indicates no pre-vend product is required for fixed-price airtime.
Example Response
{
"paymentId": 4007260,
"externalUniqueId": "59802001-ac18-4695-9e9f-a0e3a359826b",
"status": "SUCCESSFUL",
"amount": 20.000000000,
"description": "VAS purchase PartnerId-20 : BE MOBILE 20",
"currency": "BWP",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
}
],
"paymentType": "WALLET",
"created": "2025-12-08T11:12:39.000Z",
"paymentData": "20_501_0",
"extraInfo": "[{\"callbackId\":72628059,\"result\":\"...saleItemList containing serialNumber, pinNumber, expiryDate...\"}]",
"fee": 5,
"paymentReference": "501_0",
"walletId": 2536583,
"customerId": 8586330,
"gatewayTransactionId": "Payment-4007260"
}For pinned airtime products (e.g. BE MOBILE), the voucher serial and PIN are returned inside extraInfo.result.saleItemList. Channels should parse these and surface them to the customer.
Response Field Reference
- paymentId — Eclipse-generated unique identifier for the payment. Use this for status enquiries via
GET /payments/{paymentId}. - externalUniqueId — The idempotency key supplied by the channel on the request. Eclipse rejects duplicate
externalUniqueIdvalues within the tenant. - status — Terminal or intermediate state of the payment. See Transaction Status Codes below.
- amount — Amount transacted, in major currency units. Determined by
productIdfor fixed-price products. - description — Human-readable description, populated by Eclipse based on the partner and product.
- currency — ISO 4217 currency code. Must match the wallet currency.
- additionalFields — Echoes the additional fields supplied on the request (
msisdn,meterNumber,accountNumber). - paymentType — The payment instrument used. For wallet-funded VAS this will be
WALLET. - paymentData — Echoes the
paymentDatavalue from the request. - extraInfo — Provider-specific payload as a stringified JSON. For utility tokens contains the token number, customer receipt, KWh units, and tariff details. For airtime contains the voucher serial and PIN. Channels must parse and surface this content to the customer.
- paymentReference — Reference used for reconciliation. Composed of
{vendProductId}_{prevendProductId}. - fee — Transaction fee applied per tenant config.
- gatewayTransactionId — Eclipse internal gateway reference.
- tracingContext — W3C trace context. Useful when raising support tickets to correlate with Eclipse server logs.
- errorDescription — Populated only on
status ERROR_PERMorERROR_TEMP.
Transaction Status Codes
- SUCCESSFUL — Pre-vend and vend both completed. Token, voucher or recharge has been delivered. Terminal state. Action expected from channel: Render token, PIN, or receipt to the customer from
extraInfo. - PENDING — Eclipse has accepted the request but the upstream provider has not yet confirmed completion. Action expected from channel: Wait for callback (if
callbackUrlwas supplied) or pollGET /payments/{paymentId}. Do not retry thePOST—externalUniqueIdwill reject duplicates. - BUILDING — Intermediate state seen only when a separate
PUTis required to finalise the payment (does not apply to FrontierWeb single-shot flows). Action expected from channel: N/A for FrontierWeb. - ERROR_PERM / ERROR_TEMP — The transaction did not complete. Funds have been reversed on the source wallet. Action expected from channel: Inspect
errorDescriptionand the application error envelope (code,traceId). Surface a user-facing error and allow retry with a newexternalUniqueId.
For the full Eclipse application error code list, see the Application Error Codes page.
The error envelope returned by Eclipse on a failed call follows this shape:
[
{
"type": "BUSINESS",
"severity": "INFO",
"description": "Invalid voucher for the users network. User is on network id 0 but voucher is for network id 20",
"code": "IAE001",
"traceId": "9099797c1668796c2ba0b371b76a45df",
"spanId": "c06f2d77d914b3fb"
}
]Asynchronous Callbacks
In the standard happy path, FrontierWeb VAS payments complete synchronously and the POST returns status: SUCCESSFUL with the token or voucher in extraInfo. However, channels should still implement callback handling to cover cases where the upstream provider is slow or unavailable and Eclipse returns status: PENDING.
To receive a callback when a PENDING payment finalises, supply a callbackUrl on the original POST:
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"externalUniqueId": "{{$randomUUID}}",
"paymentData": "20_1248_1247",
"type": "GLOBAL_VAS",
"callbackUrl": "https://channel.tenant.example.com/eclipse/vas/callback",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
},
{
"id": "meterNumber",
"value": "21500123456"
}
],
"amount": 180,
"currency": "BWP",
"walletId": 2536583
}Eclipse will POST the full payment object (same shape as the synchronous response above) to callbackUrl once the payment reaches a terminal state (SUCCESSFUL, FAILED, or ERROR).
NoteAll callbacks from Eclipse to the channel carry an
Eclipse-Signatureheader. Channels must verify this signature before processing the payload. See the Encryption and Integrity page for the verification procedure.
Source IP allow-list
Channels that whitelist inbound traffic should permit calls from the following Eclipse source IPs:
- Production:
79.125.40.127,54.220.185.240,18.134.2.182,3.11.195.109 - Sandbox:
34.255.93.65
Custom headers
Additional headers can be configured on the tenant via the webhookAdditionalHeaders property (comma-delimited key1,value1,key2,value2).
Retries
Eclipse will retry callbacks on non-2xx responses. Retry behaviour is documented on the CallbackURL Retries page.
Polling alternative
If callback infrastructure is not available, channels can instead poll GET /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId} until the payment reaches a terminal status. Polling should be capped (e.g. 30 seconds at 2-second intervals) to avoid hot loops.
Settlement
On successful VAS payment, Eclipse triggers a notification for funds to move from the customer's source wallet to the configured VAS destination wallet (destination.wallet.config.VAS.{partnerId}.{productCategory}) and the fee destination wallet (fees.wallet.config.Pay.GLOBAL_DEFERRED.WALLET). For tenants where the source wallet is fronted by an external bank trust account (e.g. Access Bank), Eclipse emits a settlement notification to trigger the corresponding bank-side movement.
Step 4 - Initiate Making a Payment by a Customer
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"additionalFields": [
{
"id": "msisdn",
"value": "value"
}
],
"landingUrl": "https://www.google.com/",
"callbackUrl": "http://www.callback.com",
"externalUniqueId": "abcd1234",
"paymentData": "5_VD50",
"type": "GLOBAL_VAS",
"currency": "ZAR",
"walletId": XXX
}In this use case the paymentData field is set to the partnerId and productId (i.e. 5_VD50)
PartnerId = 5
productId = VD50
Step 5 - Update Necessary Fields to complete the Payment
PUT /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}
Passed tenantId and paymentId for update payment along with below request payload.
{
"amount": 155,
"walletId":XXX,
"landingUrl": "https://www.google.com/"
}Scan to Pay returns a success response string once the payment is completed successfully.
Purchase VAS from ACS
Introduction
ACS services can be integrated with Eclipse as an open feature platform. It provides a comprehensive catalog of APIs that tenants can use to manage airtime, data, and electricity bundles.
Prerequisites
- A valid JWT for API calls.
- tenant config mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.AcsMobileRecharge
- tenant config destination.wallet.config.VAS.1={destination walletId}
Step 1 - Prepare MSISDN
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/{msisdn}Step 2 - List of VAS partners & products
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogsStep 3 - Channel to filter the catalog
Once the catalog is returned, the channel filters it based on the MSISDN provided in step 1.
Select the productId from the catalog to proceed with the payment process (e.g., "productId": "M511").
Below is a list from one of the providers:
[
{
"partnerId": 4,
"partnerName": "MTN",
"providerId": 1,
"products": [
{ "partnerId": 4, "productTypeName": "SMS", "productId": "M502", "productName": "SMS30" },
{ "partnerId": 4, "productTypeName": "SMS", "productId": "M504", "productName": "SMS100" },
{ "partnerId": 4, "productTypeName": "DATA", "productId": "M511", "productName": "DATA350MB" },
{ "partnerId": 4, "productTypeName": "DATA", "productId": "M512", "productName": "DATA500MB" },
{ "partnerId": 4, "productTypeName": "DATA", "productId": "M513", "productName": "DATA1GB" },
{ "partnerId": 4, "productTypeName": "DATA", "productId": "M514", "productName": "DATA2GB" },
{ "partnerId": 4, "productTypeName": "DATA", "productId": "M550", "productName": "DATA100MB" },
{ "partnerId": 4, "productTypeName": "AIRTIME", "productId": "01", "productName": "MTN R30 Call" },
{ "partnerId": 4, "productTypeName": "AIRTIME", "productId": "03", "productName": "MTN R60 Call" },
{ "partnerId": 4, "productTypeName": "AIRTIME", "productId": "05", "productName": "MTN R180 Call" },
{ "partnerId": 4, "productTypeName": "AIRTIME", "productId": "11", "productName": "MTN R10 Recharge"},
{ "partnerId": 4, "productTypeName": "AIRTIME", "productId": "M500", "productName": "MTN Pinless" }
]
}
]Step 4 - Initiate Making a Payment by a Customer
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"additionalFields": [
{
"id": "msisdn",
"value": "xxxxxxxxxxxxx"
}
],
"landingUrl": "https://www.google.com/",
"callbackUrl": "http://www.blankwebsite.com",
"externalUniqueId": "abcd1234a",
"paymentData": "4_M512",
"type": "GLOBAL_VAS",
"currency": "ZAR",
"walletId": XXX
}In this use case the paymentData field is set to the partnerId and productId (i.e. 4_VD50)
PartnerId = 4
productId = VD50
Step 5 - Update Necessary Fields for Payment
PUT /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}
Passed tenantId and paymentId for update payment along with below request payload.
{
"amount": 49,
"walletId":xxxxx,
"landingUrl": "https://www.google.com/"
}ACS returns a success response string once the payment is completed successfully.
Electricity VAS purchases via ACSOnce a user has purchased an electricity voucher via ACS, a dummy code is visible in the Sandbox environment.
In production, this voucher code is called an UnPin.The UnPin is sent to the user via SMS and should also appear on the successful electricity purchase screen in the channel.
This UnPin cannot be used until the user dials the number below.
The meter number can be found on the user's prepaid meter.
After dialing the number, the user will receive another SMS containing a PIN, which must be entered into the prepaid meter.The channel should display both the UnPin and the USSD number string above the successful electricity purchase screen.
Purchase VAS from Kganya
Introduction
Kganya services can be integrated with Eclipse as an open feature platform. It provides a comprehensive catalog of APIs that tenants can use to manage bills and data bundles.
Prerequisites
- A valid JWT for API calls.
- Tenant config mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.KganyaMobileRecharge
- Tenant config kganya.config.baseUrl={baseUrl}
- Tenant config kganya.config.apiKey={apiKey}
- Tenant config destination.wallet.config.VAS.16={destination walletId}
Step 1 - Prepare catalogQuery
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs?catalogQuery=16_0310564280_T089775335322Prepare a catalog query - e.g. 16_0310564280_T089775335322
- PartnerId - 16 for Kganya
- Mobille number (0) if not available - 0310564280
- ID Number - T089775335322
Select the productId from the catalog to proceed with the payment process (e.g., "productId": "0310564280_T089775335322_1").
Step 2 - Initiate Making a Payment by a Customer
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"additionalFields": [
{
"id": "msisdn",
"value": "xxxxxxxxxxxxx"
}
],
"landingUrl": "https://www.google.com/",
"callbackUrl": "http://www.blankwebsite.com",
"externalUniqueId": "abcd1234a",
"paymentData": "16_0310564280_T089775335322_3",
"type": "GLOBAL_VAS",
"currency": "ZAR",
"walletId": XXX
}In this use case the paymentData field is set to the partnerId and productId i.e. 16_0310564280_T089775335322_3
PartnerId - 16
ProductId - 0310564280_T089775335322_3
Step 3 - Update Necessary Fields for Payment
PUT /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}
{
"amount": xxx,
"walletId": xxx,
"landingUrl": "https://www.google.com/"
}Kganya returns a success response string once the payment is completed successfully.
Purchase VAS from Pay@
Pay@ services can be integrated with Eclipse as an open feature platform. The Pay@ system supports real-time transaction flows, reconciliation, and fund settlement between networks/retailers and bill payment authorizers or issuers.
It provides a comprehensive catalog of APIs that tenants can use to manage various bill payments.
Prerequisites
- A valid JWT for API calls.
- Tenant config mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.PayAtRecharge
- Tenant config destination.wallet.config.VAS.14={destinationWalletId}
Step 1 – Fetch Catalog
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogsFilter based on Pay@ Partner ID 14 and select the productId from the catalog to proceed with the payment process.
Step 2- Initiate a Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"additionalFields": [
{
"id": "accountNumber",
"value": "xxxxxxxxxxxx"
}
],
"callbackUrl": "http://www.blankwebsite.com",
"externalUniqueId": "9e60398d-6ddd-4f46-b6cd-2081c872b2ea",
"paymentData": "14_14577",
"type": "GLOBAL_VAS"
}In this use case the paymentData field is set to the partnerId and productId i.e. 14_14577
PartnerId - 14
ProductId - 14577
Step 3- Update Fields for Payment
PUT /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}
{
"amount": 150,
"walletId": XXX,
"externalUniqueId":"9e60398d-6ddd-4f46-b6cd-2081c872b2ea"
}Pay@ returns a success response string once the payment is completed successfully.
Purchase VAS from EasyPay
EasyPay services can be integrated with Eclipse as an open feature platform.
It provides a comprehensive catalog of APIs that tenants can use to manage bill payments, vend airtime, SMS packs, and data bundles.
Prerequisites
- A valid JWT for API calls.
- Tenant config mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.EasyPayMobileRecharge
- Tenant config destination.wallet.config.VAS.15=${destinationWalletId}
Step 1 – Fetch Catalog
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogsFilter based on EasyPay Partner ID 15 and select the productId from the catalog to proceed with the payment process.
Step 2 - Initiate a Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"additionalFields": [
{
"id": "msisdn",
"value": "xxxxxxxxxxxxx"
}
],
"landingUrl": "https://www.google.com/",
"callbackUrl": "http://www.blankwebsite.com",
"externalUniqueId": "29agd6z317d519e87211",
"paymentData": "15_1764",
"type": "GLOBAL_VAS",
"phone": "xxxxxxxxxxxxx",
"walletId": XXX
}In this use case the paymentData field is set to the partnerId and productId i.e. 15_1764
PartnerId - 15
ProductId - 1764
Step 3 - Update Fields for Payment
PUT/eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}
Passed tenantId and paymentId for update payment along with below request payload.
{
"amount": 150,
"walletId": XXX,
"externalUniqueId":"29agd6z317d519e87211"
}EasyPay returns a success response string once the payment is completed successfully.
Kenya VAS providers
The following VAS providers are specific to tenants operating in Kenya.
Pay Tax through Diamond Trust Bank
DTB integrations allow the ability to forcustomer to query their Payment Registration Number (PRN) against the Kenya Revenue Authority (KRA) and then pay the tax amount.
Prerequisites
- A valid JWT for API calls.
Below are the tenant configs that need to be configured when paying tax through Diamond Trust Bank:
- mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.DTBQueryUtilityRecharge
- destination.wallet.config.VAS.19=${destinationWalletId}
Step 1 – Validate PRN and get amount owed
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs?19_ETAX_10202300000582380The catalog query is partnerId_taxUtilitCode_prn. Partner ID for DTB Tax payments is 19 and the utility code is ETAX.
[
{
"partnerId": 19,
"partnerName": "dtbQueryUtility",
"providerId": 19,
"products": [
{
"partnerId": 19,
"productId": "ETAX_1020230000058238",
"productName": "ETAX",
"pinnedProduct": false,
"additionalFields": [
{
"id": "SystemCode",
"defaultValue": "PG"
},
{
"id": "EslipNumber",
"defaultValue": "1020230000058238"
},
{
"id": "PaymentAdviceDate",
"defaultValue": "2023-06-19T13:25:12"
},
{
"id": "TaxpayerPin",
"defaultValue": "P051094777L"
},
{
"id": "TaxpayerFullName",
"defaultValue": "Call Fast Services Limited"
},
{
"id": "TotalAmount",
"defaultValue": "52008620"
},
......Step 2 - Initiate a Payment
NoteThe wallet type of the walletId specified in the body determines if the source of the transaction is an Eclipse wallet or a DTB Bank Account.
paymentData field is {partnerId}{taxUtilitCode} {prn}. Partner ID for DTB Tax payments is 19 and the utility code is ETAX.
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"externalUniqueId": "772021c2-bc1b-4a83-8c26-2ea2fe210836",
"type": "GLOBAL_VAS",
"paymentData": "19_ETAX_1020230000060915",
"amount": 52008620,
"currency": "KES",
"additionalFields": [ ],
"walletId": 830989,
"customFraudChecks": false
}{
"paymentId": 453209,
"externalUniqueId": "772021c2-bc1b-4a83-8c26-2ea2fe210836",
"status": "PENDING",
"amount": 52008620,
"currency": "KES",
"additionalFields": [ ],
"acceptedCardSchemes": [ ],
"cardPhone": "254729294292",
"phone": "254729294292",
"acceptedPaymentMechanisms": [ ],
"paymentType": "EFT",
"created": "2023-09-15T09:11:14.000Z",
"extraInfo": "{"dtbCallingCustomerCif":"65594662-bc39-4c0d-8c7c-bc7cf6012fb9","dtbCallingCustomerId":709193,"dtbCallingCustomerOrganisation":"","dtbSourceBankCode":"","dtbSourceCountryCode":"KE","dtbSourceCurrency":"KES","dtbSourceName":"kuBQcxDilafNzey RQPgcyyEQNZdBLF","dtbSourcePhone":"254729294292","dtbSourceType":"DTB_WALLET","dtbDestinationCurrency":"KES"}",
"paymentInstrumentInfo": {
"cardPhone": "254729294292"
},
"fee": 0,
"paymentReference": "1020230000060915",
"walletId": 830989,
"customerId": 709193
}Typically you will immediately receive a PENDING response. If the callbackUrl was populated a callback will be sent to that URL when the payment is finalised (either successful or error). Alternatively a call can be made to the GET payment by paymentId endpoint.
Purchase VAS through Diamond Trust Bank
Eclipse has integrations to DTB to offer a wide range of VAS services where tenants can pay various bills, Vend airtime, SMS and data bundles.
Prerequisites
- A valid JWT for API calls.
Below are the tenant configs that need to be configured when purchasing VAS through Diamond Trust Bank:
- mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.DTBQueryUtilityRecharge
- destination.wallet.config.VAS.19=${destinationWalletId}
Step 1 – Fetch Catalog
The catalog query is {partnerId}_LOCAL-CATALOG. Partner ID for DTB VAS payments is 1.
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs?catalogQuery=19_LOCAL-CATALOGAPI Returned Multiple products with Partner Id 19. Select productid from catalogs to further initiate the payment process (i.e. "productId": "1")
Step 2 - Initiate a Payment
NoteThe wallet type of the walletId specified in the body determines if the source of the transaction is an Eclipse wallet or a DTB Bank Account.
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"externalUniqueId": "4490d40f-f2ef-4ee6-878c-2885fd4d990c",
"type": "GLOBAL_VAS",
"paymentData": "19_KE-STARTIMES_1234567890",
"amount": 100,
"currency": "KES",
"additionalFields": [ ],
"walletId": 836788,
"description": "VAS KE-STARTIMES payment for 1234567890",
"customFraudChecks": false
}Here paymentData is partnerId_productId/utility_code_optional_reference
e.g. 19_KE-STARTIMES_1234567890
{
"paymentId": 453215,
"externalUniqueId": "019f240f-163f-43c2-a9b4-273b50e910a9",
"status": "PENDING",
"amount": 100,
"description": "VAS KE-STARTIMES payment for 1234567890",
"currency": "KES",
"additionalFields": [ ],
"acceptedCardSchemes": [ ],
"cardPhone": "254729294292",
"phone": "254729294292",
"acceptedPaymentMechanisms": [ ],
"paymentType": "EFT",
"created": "2023-09-15T09:11:16.000Z",
"extraInfo": "{"dtbCallingCustomerCif":"65594662-bc39-4c0d-8c7c-bc7cf6012fb9","dtbCallingCustomerId":709193,"dtbCallingCustomerOrganisation":"","dtbSourceBankCode":"","dtbSourceCountryCode":"KE","dtbSourceCurrency":"KES","dtbSourceName":"kuBQcxDilafNzey RQPgcyyEQNZdBLF","dtbSourcePhone":"254729294292","dtbSourceType":"DTB_WALLET","dtbDestinationAccountNumber":"KE-STARTIMES","dtbDestinationCurrency":"KES"}",
"paymentInstrumentInfo": {
"cardPhone": "254729294292"
},
"fee": 0,
"paymentReference": "1234567890",
"walletId": 830989,
"customerId": 709193
}Typically you will immediately receive a PENDING response. If the callbackUrl was populated a callback will be sent to that URL when the payment is finalised (either successful or error). Alternatively a call can be made to the GET payment by paymentId endpoint.
Uganda VAS Providers
The following VAS providers are specific to tenants operating in Uganda.
Purchase VAS through Diamond Trust Bank
Below are the tenant configs that need to be configured for Diamond Trust Bank tenants so that Astra can make calls to DTB Uganda APIs:
- dtb.config.oauthEndpoint = /dtbug/oauth/1.0/
- dtb.config.clientId = VVICUoWyVpyscQdQdNdPFUjI
- dtb.config.clientSecret = KAPmTTLoTGrw-zbmxBINtDgAQvzuoxGaVeKe
VAS Related Configs
- mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.DTBUGRechargeVasProvider
- destination.wallet.config.VAS.21=${destinationWalletId}
List of VAS partners & products
Retrieve catalog items for DTB UG.
Prerequisites
- A valid JWT for API calls.
GET /eclipse-conductor/rest/v1/tenants/6658/vas/catalogs?catalogQuery=21_LOCAL-CATALOG• catalogQuery: 21_LOCAL-CATALOG
Example Response
[
{
"partnerId": 21,
"partnerName": "DTBUGVasProvider",
"providerId": 21,
"products": [
{
"partnerId": 21,
"productTypeName": "BILL",
"productId": "NWSC",
"productCategory": "BILL",
"productDescription": "NWSC water payment",
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 21,
"productTypeName": "BILL",
"productId": "ETAX",
"productCategory": "BILL",
"productDescription": "URA Tax Returns payment",
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 21,
"productTypeName": "BILL",
"productId": "UMEME",
"productCategory": "BILL",
"productDescription": "Make UMEME Bill payments",
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
}
]
}
]
NWSC Bill Payment
This VAS integration is used to process water bill payments for DTB UG’s tenants. The integration will make calls to these two API’s i.e. the getCustomerDetails which provides customer details and paymentsAPI which handles the final payments processed through the Fiorano payments gateway.
Prerequisites
- A valid JWT for API calls.
- Valid customer reference number and area.
Step One: Query Account Details
Fetch Catalog
GET /eclipse-conductor/rest/v1/tenants/11666/vas/catalogs?catalogQuery=21_NWSC_21117391_Kampala• catalogQuery: 21_NWSC_21117391_Kampala
• 21117391 represents the client’s reference number.
• Kampala represents the client’s area
Example Response
[
{
"partnerId": 21,
"partnerName": "DTBUGVasProvider",
"providerId": 21,
"products": [
{
"partnerId": 21,
"productId": "NWSC_21117391",
"productName": "NWSC",
"pinnedProduct": false,
"additionalFields": [
{
"id": "CustRef",
"defaultValue": "21117391"
},
{
"id": "PropertyRef",
"defaultValue": "21/34/19/175"
},
{
"id": "CustName",
"defaultValue": "ROBERT MWESIGYE"
},
{
"id": "Area",
"defaultValue": "Kampala"
},
{
"id": "OutstandingBal",
"defaultValue": "71683"
},
{
"id": "CustomerError",
"defaultValue": "NONE"
},
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
}
]
}
]Step Two: Initiate Payment
NoteThe wallet type of the walletId specified in the body determines if the source of the transaction is an Eclipse wallet or a DTB Bank Account.
Initiate Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/paymentsExample Payload
{
"externalUniqueId":"{{$guid}}",
"type":"GLOBAL_VAS",
"paymentData":"21_NWSC_21117391",
"amount":71683,
"currency":"UGX",
"additionalFields":[
{
"id":"destinationBranchCode",
"value":"001"
},
{
"id":"destinationName",
"value":"ROBERT MWESIGYE"
}
],
"walletId":206744,
"description":"21117391",
"customFraudChecks":false
}UMEME - Electricity Bill Payment
The purpose of this integration is to allow clients to query their UMEME account and make payments for electricity bills. This integration utilizes a single endpoint with two methods i.e. the GET method for fetching customer details and the POST method for posting the bill payment and notifying UMEME through Fiorano.
Step One: Query Account Details
Get Account Details
GET /eclipse-conductor/rest/v1/tenants/6658/vas/catalogs?catalogQuery=21_UMEME_200166426• catalogQuery=21_UMEME_200166426
• 200166426 represents the client’s reference number.
Example Response
[
{
"partnerId": 21,
"partnerName": "DTBUGVasProvider",
"providerId": 21,
"products": [
{
"partnerId": 21,
"productId": "UMEME_200166426",
"productName": "UMEME",
"pinnedProduct": false,
"additionalFields": [
{
"id": "customerRef",
"defaultValue": "200166426"
},
{
"id": "customerType",
"defaultValue": "POSTPAID"
},
{
"id": "customerName",
"defaultValue": "BAFUKAWA RONALD"
},
{
"id": "statusDescription",
"defaultValue": "SUCCESS"
},
{
"id": "balance",
"defaultValue": "-21103"
},
{
"id": "statusCode",
"defaultValue": "0"
},
{
"id": "credit",
"defaultValue": "0"
},
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
}
]
}
]
Step Two: Initiate Bill Payment
Initiate Payment
NoteThe wallet type of the walletId specified in the body determines if the source of the transaction is an Eclipse wallet or a DTB Bank Account.
POST /eclipse-conductor/rest/v1/tenants/6658/customers/184132/paymentsExample Payload
{
"externalUniqueId":"{{$guid}}",
"type":"GLOBAL_VAS",
"paymentData":"21_UMEME_200166426",
"amount":29182,
"currency":"UGX",
"additionalFields":[
{
"id":"destinationBranchCode",
"value":"001"
},
{
"id":"destinationName",
"value":"BASEKANAKYO DEBULA"
},
{
"id":"destinationType",
"value":"UMEME_ACCOUNT"
},
{
"id":"destinationPhone",
"value":"704263087"
}
],
"walletId":206744,
"description":"POSTPAID",
"customFraudChecks":false
}Example Response
{
"paymentId": 142607,
"externalUniqueId": "48d9b276-ad03-4ee9-9a4b-6377eb383502",
"status": "PENDING",
"amount": 29182.000000000,
"description": "POSTPAID",
"currency": "UGX",
"additionalFields": [
{
"id": "destinationBranchCode",
"value": "001"
},
{
"id": "destinationName",
"value": "BASEKANAKYO DEBULA"
},
{
"id": "destinationType",
"value": "UMEME_ACCOUNT"
},
{
"id": "destinationPhone",
"value": "704263087"
}
],
"acceptedCardSchemes": [],
"acceptedPaymentMechanisms": [],
"paymentType": "EFT",
"created": "2024-01-26T15:14:53.000Z",
"extraInfo": "{\"dtbCallingCustomerCif\":\"b74f7ecb-5730-4718-ab26-32cb31f9b19f\",\"dtbCallingCustomerId\":184132,\"dtbCallingCustomerOrganisation\":\"\",\"dtbSourceAccountNumber\":\"8000020000016\",\"dtbSourceBankCode\":\"\",\"dtbSourceCountryCode\":\"UG\",\"dtbSourceCurrency\":\"UGX\",\"dtbSourceName\":\"Daphine Kajoina\",\"dtbSourcePhone\":\"256775555466\",\"dtbSourceType\":\"DTB_WALLET\",\"dtbDestinationType\":\"UMEME_ACCOUNT\",\"dtbDestinationAccountNumber\":\"UMEME\",\"dtbDestinationBankCode\":\"001\",\"dtbDestinationCountryCode\":\"KE\",\"dtbDestinationCurrency\":\"UGX\",\"dtbDestinationName\":\"BASEKANAKYO DEBULA\",\"dtbDestinationPhone\":\"704263087\"}",
"paymentInstrumentInfo": {},
"fee": 0E-9,
"paymentReference": "200166426",
"walletId": 206744,
"customerId": 184132,
"gatewayTransactionId": "fa5acd83-9d3f-4571-b290-7f0f29c2fc8e"
}
URA Tax Payments
Step 1 – Validate PRN and get the amount owed
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs?21_ETAX_2240000621955The catalog query is partnerId_taxUtilitCode_prn. The partner ID for DTB UG Tax payments is 21 and the utility code is ETAX.
[
{
"partnerId": 21,
"partnerName": "DTBUGVasProvider",
"providerId": 21,
"products": [
{
"partnerId": 21,
"productId": "ETAX_2240000621955",
"productName": "ETAX",
"pinnedProduct": false,
"additionalFields": [
{
"id": "Prn",
"defaultValue": "2240000621955"
},
{
"id": "Tin",
"defaultValue": "1001307092"
},
{
"id": "TaxpayerName",
"defaultValue": "DAMBAK ENTERPRISES LIMITED"
},
{
"id": "Amount",
"defaultValue": "25000"
},
{
"id": "ExpiryDt",
"defaultValue": "08-FEB-24"
},
{
"id": "StatusCode",
"defaultValue": "T"
},
{
"id": "StatusDesc",
"defaultValue": "RECEIVED AND CREDITED"
},
{
"id": "Currency"
},
{
"id": "PaymentRegDt",
"defaultValue": "20-NOV-23"
},
{
"id": "IsSentToBank",
"defaultValue": "Y"
},
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
}
]
}
]Step 2 - Initiate a Payment
NoteThe wallet type of the walletId specified in the body determines if the source of the transaction is an Eclipse wallet or a DTB Bank Account.
paymentData field is {partnerId}{taxUtilitCode} {prn}. The partner ID for DTB UG Tax payments is 21 and the utility code is ETAX.
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"externalUniqueId":"{{$guid}}",
"type":"GLOBAL_VAS",
"paymentData":"21_ETAX_1001307092"
"amount":25000,
"currency":"UGX",
"additionalFields":[
{
"id":"destinationBranchCode",
"value":"001"
},
{
"id":"destinationName",
"value":"DAMBAK ENTERPRISES LIMITED"
}
],
"walletId":207016,
"description":"2240000621955",
"customFraudChecks":false
}{
"paymentId": 150417,
"externalUniqueId": "6797d402-1734-46f3-8066-73a3a2bc3860",
"status": "PENDING",
"amount": 25000.000000000,
"description": "2240000621955",
"currency": "UGX",
"additionalFields": [
{
"id": "destinationBranchCode",
"value": "001"
},
{
"id": "destinationName",
"value": "DAMBAK ENTERPRISES LIMITED"
}
],
"acceptedCardSchemes": [],
"acceptedPaymentMechanisms": [],
"paymentType": "EFT",
"errorDescription": ": ",
"created": "2024-02-02T13:00:16.000Z",
"extraInfo": "{\"dtbCallingCustomerCif\":\"a7cfe6d1-dc34-4e56-b537-0a0ac21b3bde\",\"dtbCallingCustomerId\":723689,\"dtbCallingCustomerOrganisation\":\"\",\"dtbSourceAccountNumber\":\"7053960002\",\"dtbSourceBranchCode\":\"001\",\"dtbSourceBankCode\":\"\",\"dtbSourceCountryCode\":\"UG\",\"dtbSourceCurrency\":\"UGX\",\"dtbSourceName\":\"James Madison\",\"dtbSourcePhone\":\"27987654321\",\"dtbSourceType\":\"DTB_BANK_ACCOUNT\",\"dtbDestinationBankCode\":\"001\",\"dtbDestinationCountryCode\":\"UG\",\"dtbDestinationCurrency\":\"UGX\",\"dtbDestinationName\":\"DAMBAK ENTERPRISES LIMITED\"}",
"paymentInstrumentInfo": {},
"fee": 0E-9,
"paymentReference": "1001307092",
"walletId": 207016,
"customerId": 723689
}Typically you will immediately receive a PENDING response. If the callback URL was populated a callback will be sent to that URL when the payment is finalised (either successful or error). Alternatively, a call can be made to the GET payment by paymentId endpoint.
Fund your MTN wallet through DTB Uganda
Prerequisites
A valid JWT for API calls.
Property
Below are the tenant configs that need to be configured for transferring funds to an MTM Mobile Money Wallet through Diamond Trust Bank:
- mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.DTBUGRechargeVasProvider
- destination.wallet.config.VAS.XX=${destinationWalletId}
Step1 Validate the MTN number
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs?21_MTN_256779999703The catalog query is partnerId_taxUtilitCode_customerRef. Partner ID for DTB MTN wallet topup is 21 and the utility code is MTN. 21_MTN_256779999703
Step2 Initiate a Payment
POST: /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"externalUniqueId": "9c04cede-e105-488b-9211-ab21bf3e1db9",
"type": "GLOBAL_VAS",
"paymentData": "21_MTN_256779999703",
"amount": 29182,
"currency": "UGX",
"additionalFields": [
{
"id": "destinationBranchCode",
"value": "001"
},
{
"id": "destinationName",
"value": "Martha N"
},
{
"id": "destinationType",
"value": "MTN_WALLET"
},
{
"id": "destinationPhone",
"value": "256779999703"
}
],
"walletId": 204142,
"description": "Transfer from bank to wallet",
"customFraudChecks": false
}{
"paymentId": 172565,
"externalUniqueId": "2b204a21-d686-489e-980c-9c1ff3c1ca1a",
"status": "PENDING",
"amount": 29182.000000000,
"description": "Transfer from bank to wallet",
"currency": "UGX",
"additionalFields": [
{
"id": "destinationBranchCode",
"value": "001"
},
{
"id": "destinationName",
"value": "Martha N"
},
{
"id": "destinationType",
"value": "MTN_WALLET"
},
{
"id": "destinationPhone",
"value": "256779999703"
}
],
"acceptedCardSchemes": [],
"acceptedPaymentMechanisms": [],
"paymentType": "EFT",
"errorDescription": ": ",
"created": "2024-02-21T07:31:33.000Z",
"extraInfo": "{\"dtbCallingCustomerCif\":\"a7cfe6d1-dc34-4e56-b537-0a0ac21b3bde\",\"dtbCallingCustomerId\":723689,\"dtbCallingCustomerOrganisation\":\"\",\"dtbSourceAccountNumber\":\"7115418418\",\"dtbSourceBranchCode\":\"001\",\"dtbSourceBankCode\":\"\",\"dtbSourceCountryCode\":\"UG\",\"dtbSourceCurrency\":\"UGX\",\"dtbSourceName\":\"James Madison\",\"dtbSourcePhone\":\"27987654321\",\"dtbSourceType\":\"DTB_WALLET\",\"dtbDestinationType\":\"MTN_WALLET\",\"dtbDestinationAccountNumber\":\"MTN\",\"dtbDestinationBankCode\":\"001\",\"dtbDestinationCountryCode\":\"UG\",\"dtbDestinationCurrency\":\"UGX\",\"dtbDestinationName\":\"Martha N\",\"dtbDestinationPhone\":\"256779999703\"}",
"paymentInstrumentInfo": {},
"fee": 0E-9,
"paymentReference": "256779999703",
"walletId": 204142,
"customerId": 723689,
"paymentTerminalData": {}
}Global VAS providers
The following VAS providers are not specific to any region.
Purchase VAS from Cellulant
Introduction
Cellulant services to integrate with Eclipse as an open feature platform. It has an extensive catalog of API’s available for tenants to manage the Transfer money, Refunds, Pay various bills, Vend airtime and data bundles. Cellulant supported multiple services in many countries/regions.
Prerequisites
- A valid JWT for API calls.
- Eclipse provides global vas catalogs for tenants.
It is recommended to search service code from catalogs within the tenant.
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs.Step 1 – Create Json
First create a json file based on provided service codes for a particular country. Added those json data in the property table against mobilerecharge.cellulant.bundles.{tenantId} key. Defined country code for selected tenant. (i.e. cellulant.config.countryCode={countryCode})
Step 2 - Fetch vas Catalogs
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs.Based on tenantId return all the service codes as a catalogs from configured json data. Choose a voucher from catalogs list and prepare one catalog query for selected services.
Step 3 - Prepare CatalogQuery
GET /eclipse-conductor/rest/v1/tenants/242/vas/catalogs?catalogQuery=17_254707720002_042381176772_KE-DSTV17 - partnerId for cellulant
254707720002 - Mobile number, If not available then pass 0
042381176772 - Account number
KE-DSTV - Service code
Based on catalogQuery they returned products for defined service. Select productid from catalogs to further initiate the payment process (i.e., "productid": "254707720002_042381176772_KE-DSTV_DSTVTESTKE")
Step 4 - Initiate Making a Payment by a Customer
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
"additionalFields": [
{
"id": "msisdn",
"value": "xxxxxxxxxxxxx"
}
],
"landingUrl": "https://www.google.com/",
"callbackUrl": "http://www.blankwebsite.com",
"externalUniqueId": "abcd1234a",
"paymentData": "17_254707720002_042381176772_KE-DSTV_DSTVTESTKE",
"type": "GLOBAL_VAS",
"currency": "ZAR",
"walletId": XXX
}So here paymentData it could be (i.e. 17_254707720002_042381176772_KE-DSTV_DSTVTESTKE)
17 - PartnerId
254707720002_042381176772_KE-DSTV_DSTVTESTKE - productId
In response getting paymentId & amount along with all required extra information.
Step 5 - Update Necessary Fields for Payment
PUT /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}
Passed tenantId and paymentId for update payment along with below request payload.
{
"amount": 517,
"walletId":476,
"landingUrl": "https://www.google.com/"
}Cellulant returns a success response string once successful payment.
Botswana VAS providers
Purchase VAS from FrontierWeb Services
Introduction
FrontierWeb services provides an extensive catalog for tenants' clients to pay for digital subscriptions, airtime, data bundles, and electricity tokens. These services have been integrated into Eclipse.
Prerequisites
- A valid JWT for API calls.
- Eclipse provides global VAS catalogs for tenants.
Below are the tenant configs to be configured for FrontierWeb Services:
- mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.FrontierVasProvider
- destination.wallet.config.VAS.1={destination walletId}
Below are the global configs required for FrontierWeb Services:
mobilerecharge.config
- frontierProviderId={frontierProviderId}
- frontierNetworkName={frontierNetworkName}
- frontierNetworkId={frontierNetworkId}
frontier.vas.config
- merchantNumber={merchantNumber}
- merchantPassword={merchantPassword}
- terminalNumber={terminalNumber}
- floatingUser={floatingUser}
- userCode={userCode}
- userPassword={userPassword}
- userLevel={userLevel}
- applicationID={applicationID}
- processorNumber={processorNumber}
- soapActionUrl={soapActionUrl}
sd.external.services
- Add an entry with for frontier as REST,FRONTIER-VAS,https://rightpin.com/FrontierWS,^/frontier-vas, , ,0,0, ,/frontier-vas
PartnerId for FrontierWeb Services is 20.
Get List of VAS products
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs?catalogQuery=20[
{
"partnerId": 20,
"partnerName": "FrontierWebServices",
"providerId": 20,
"products": [
{
"partnerId": 20,
"productId": "500",
"productName": "BE MOBILE 10",
"productDescription": "BE MOBILE 10",
"fixedPriceIncl": 10.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "501",
"productName": "BE MOBILE 20",
"productDescription": "BE MOBILE 20",
"fixedPriceIncl": 20.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "504",
"productName": "BE MOBILE 100",
"productDescription": "BE MOBILE 100",
"fixedPriceIncl": 100.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "502",
"productName": "BE MOBILE 30",
"productDescription": "BE MOBILE 30",
"fixedPriceIncl": 30.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "503",
"productName": "BE MOBILE 50",
"productDescription": "BE MOBILE 50",
"fixedPriceIncl": 50.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1259",
"productName": "Bots DSTV Balance",
"productDescription": "Bots DSTV Balance",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1260",
"productName": "Bots DSTV Recharge",
"productDescription": "Bots DSTV Recharge",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1261",
"productName": "Box Office Payment",
"productDescription": "Box Office Payment",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "2069",
"productName": "BTC Check",
"productDescription": "BTC Check",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1446",
"productName": "BTC Sefalana Topup",
"productDescription": "BTC Sefalana Topup",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "491",
"productName": "MASCOM 10",
"productDescription": "MASCOM 10",
"fixedPriceIncl": 10.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "492",
"productName": "MASCOM 20",
"productDescription": "MASCOM 20",
"fixedPriceIncl": 20.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "494",
"productName": "MASCOM 100",
"productDescription": "MASCOM 100",
"fixedPriceIncl": 100.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "493",
"productName": "MASCOM 60",
"productDescription": "MASCOM 60",
"fixedPriceIncl": 60.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1574",
"productName": "Mascom Direct Ideal Topup",
"productDescription": "Mascom Direct Ideal Topup",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1910",
"productName": "Mascom Direct Ideal Pre-Vend",
"productDescription": "Mascom Direct Ideal Pre-Vend",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "496",
"productName": "ORANGE 20",
"productDescription": "ORANGE 20",
"fixedPriceIncl": 20.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "498",
"productName": "ORANGE 100",
"productDescription": "ORANGE 100",
"fixedPriceIncl": 100.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "497",
"productName": "ORANGE 50",
"productDescription": "ORANGE 50",
"fixedPriceIncl": 50.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "495",
"productName": "ORANGE 10",
"productDescription": "ORANGE 10",
"fixedPriceIncl": 10.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "2066",
"productName": "Orange Pre-vend Ideal",
"productDescription": "Orange Pre-vend Ideal",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "2065",
"productName": "Orange Topup Ideal",
"productDescription": "Orange Topup Ideal",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1247",
"productName": "Utility Pre Vend",
"productDescription": "Utility Pre Vend",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1290",
"productName": "Reprint Token",
"productDescription": "Reprint Token",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
},
{
"partnerId": 20,
"productId": "1248",
"productName": "Utility Token",
"productDescription": "Utility Token",
"fixedPriceIncl": 0.00,
"pinnedProduct": false,
"additionalFields": [
{
"id": "msisdn",
"title": "Phone number",
"type": "NUMERIC",
"regex": "^[0-9]{8,16}$"
}
]
}
]
}
]Initiating a VAS Payment
For FrontierWeb Services, the POST to /payments initiates both the pre-vend (validation) and the vend (fulfilment), but the call is asynchronous end-to-end. Eclipse responds immediately with status: SUCCESSFUL and deducts funds from the source wallet, but the extraInfo payload (token, voucher serial/PIN, customer receipt) is not populated on the POST response. Channels must poll GET /payments/{paymentId} for up to 2 minutes after the POST to retrieve extraInfo once Eclipse has confirmed the final state with the provider.
This async model was introduced to handle scenarios where the FrontierVasProvider times out on Eclipse's outbound call but the underlying transaction is still in progress at the upstream utility/network. Eclipse internally calls the provider's transaction-check API to confirm the true terminal state, then either populates extraInfo on the payment record or issues a reversal on the source wallet (status flips to FAILED).
All requests use the standard Eclipse authentication and content-type headers:
-
Header
Authorization: Bearer <JWT>— see the Authentication and Authorisation page for JWT issuance. -
Header
Content-Type: application/json.
ThepaymentDatafield follows one of two formats depending on the product: -
Airtime (fixed-price products):
{partnerId}_{productId}_0— e.g.20_501_0 -
Two-stage products (utility token, DSTV):
{partnerId}_{vendProductId}_{prevendProductId}— e.g.20_1248_1247(Utility Token + Utility Pre-Vend)
PartnerId for FrontierWeb Services is 20.
Retrieving the token / voucher (GET polling)
Because extraInfo is never populated on the synchronous POST response, channels must retrieve it via GET against the paymentId returned by the POST.
HTTP
GET /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}
Authorization: Bearer <JWT>
Accept: application/jsonJSON
The GET returns the full payment object. The below is an example response for a Utility Token purchase against Conlog Botswana — note the populated extraInfo field, which is a stringified JSON array.
{
"paymentId": 4304995,
"externalUniqueId": "2c6d4298-d9c8-4616-82ef-c1f7e446cec7",
"status": "SUCCESSFUL",
"amount": 100.000000000,
"description": "VAS purchase PartnerId-20 : Utility Token",
"currency": "BWP",
"additionalFields": [
{
"id": "msisdn",
"value": "75757459"
},
{
"id": "meterNumber",
"value": "21500123456"
}
],
"acceptedCardSchemes": [],
"cardPhone": "26775757459",
"phone": "26775757459",
"acceptedPaymentMechanisms": [
"WALLET",
"AMT",
"SECURE_CODE"
],
"paymentType": "WALLET",
"created": "2026-05-18T11:34:04.000Z",
"lastModified": "2026-05-18T11:34:04.000Z",
"paymentData": "20_1248_1247",
"extraInfo": "[{\"att\":\"preValidationResponse\",\"val\":\"{\\\"requestId\\\":\\\"d8d61e07-3b5d-4931-b17c-f60520d915ee\\\",\\\"transactionNumber\\\":\\\"28937440802605181334\\\",\\\"itemId\\\":1247,\\\"instructionSet\\\":\\\"\\\",\\\"merchantReceipt\\\":\\\"METER: 21500123456\\\\n\\\\nTT:02 SGC:990471 KRN:1 TI:01\\\\n\\\\nNAME: Conlog Botswana\\\\nADDRESS: 1 TEST BLOCK\\\\n\\\",\\\"customerReceipt\\\":\\\"\\\",\\\"printFinancialInfo\\\":false,\\\"responseCode\\\":0,\\\"thirdPartyResponse\\\":{\\\"thirdPartyErrorResponse\\\":null,\\\"prevendResponse\\\":{\\\"utilityDetails\\\":{\\\"utilityName\\\":\\\"\\\",\\\"address\\\":\\\"\\\",\\\"contactDetails\\\":\\\"\\\",\\\"taxRef\\\":\\\"\\\",\\\"doUpdate\\\":false},\\\"processorID\\\":215,\\\"processorDescription\\\":\\\"Conlog - Botswana\\\",\\\"address\\\":\\\"1 TEST BLOCK\\\",\\\"customerName\\\":\\\"Conlog Botswana\\\",\\\"meterNumber\\\":\\\"21500123456\\\",\\\"customerIDNumber\\\":null,\\\"standNumber\\\":\\\"////\\\",\\\"town\\\":\\\"\\\",\\\"remaningQuota\\\":\\\"\\\",\\\"oustandingCharges\\\":\\\"\\\",\\\"maxVendAmount\\\":1000.00,\\\"minVendAmount\\\":0,\\\"electricityExtensions\\\":{\\\"tariffsDescription\\\":\\\"\\\",\\\"tariffs\\\":\\\"\\\",\\\"customerMessage\\\":\\\"\\\",\\\"operatorMessage\\\":\\\"\\\",\\\"chargesDetails\\\":[],\\\"arrearsDetails\\\":[],\\\"tariffBlocks\\\":[],\\\"utilityDetails\\\":{\\\"utilityName\\\":\\\"\\\",\\\"address\\\":\\\"\\\",\\\"contactDetails\\\":\\\"\\\",\\\"taxRef\\\":\\\"\\\",\\\"doUpdate\\\":false}},\\\"linkedReferenceNum\\\":\\\"\\\",\\\"balance\\\":null,\\\"availableBalance\\\":null,\\\"creditLimit\\\":null},\\\"electricityResponse\\\":null,\\\"uniPinResponse\\\":null,\\\"carwashResponse\\\":null,\\\"billPaymentResponse\\\":null,\\\"airtimeTopUpResponse\\\":null,\\\"voucherResponse\\\":null},\\\"cellMessage\\\":null,\\\"receiptFormat\\\":0,\\\"receiptFormatVersion\\\":0,\\\"receiptFormatMerchant\\\":null,\\\"receiptFormatCustomer\\\":null}\"}]",
"paymentInstrumentInfo": {
"cardPhone": "26775757459"
},
"fee": 4,
"paymentReference": "1248_1247",
"walletId": 2536583,
"customerId": 8586330,
"gatewayTransactionId": "Payment-4304995",
"paymentTerminalData": {},
"tracingContext": "00-a023de9869f046ac653f4658116a369c-220c2a5e9df30572-03"
}Decoded extraInfo
The extraInfo field is a JSON-stringified array. Each entry has an att (attribute name identifying the phase) and a val (the phase response, itself a stringified JSON). After un-escaping the outer string and parsing the inner val, the structure looks like this:
[
{
"att": "preValidationResponse",
"val": {
"requestId": "d8d61e07-3b5d-4931-b17c-f60520d915ee",
"transactionNumber": "28937440802605181334",
"itemId": 1247,
"instructionSet": "",
"merchantReceipt": "METER: 21500123456\n\nTT:02 SGC:990471 KRN:1 TI:01\n\nNAME: Conlog Botswana\nADDRESS: 1 TEST BLOCK\n",
"customerReceipt": "",
"printFinancialInfo": false,
"responseCode": 0,
"thirdPartyResponse": {
"thirdPartyErrorResponse": null,
"prevendResponse": {
"processorID": 215,
"processorDescription": "Conlog - Botswana",
"address": "1 TEST BLOCK",
"customerName": "Conlog Botswana",
"meterNumber": "21500123456",
"maxVendAmount": 1000.00,
"minVendAmount": 0,
"electricityExtensions": {
"tariffsDescription": "",
"tariffs": "",
"customerMessage": "",
"operatorMessage": "",
"chargesDetails": [],
"arrearsDetails": [],
"tariffBlocks": []
}
},
"electricityResponse": null,
"voucherResponse": null
}
}
}
]The array can contain multiple entries — one per phase of the transaction (pre-validation, vend response, etc.). The phase carrying the token or voucher is identified by att:
- Utility token (Conlog Botswana): look for
thirdPartyResponse.electricityResponsecontaining the token, KWh units, and tariff details. - Pinned airtime (e.g. BE MOBILE): look for
thirdPartyResponse.voucherResponsecontaining thesaleItemListwithserialNumber,pinNumber, andexpiryDate. - DSTV recharge: look for
thirdPartyResponse.billPaymentResponsecontaining the recharge confirmation.
Channels must un-escape the outerextraInfostring, parse it as JSON, iterate the array, and read the appropriatethirdPartyResponse.*field for the product type.
Recommended polling pattern:
- Begin polling 5 seconds after the POST returns.
- Poll at 5-second intervals.
- Cap total polling duration at 2 minutes (24 attempts).
- Stop polling as soon as
extraInfois present on the response orstatustransitions toFAILED/ERROR.
Note that thestatusfield will returnSUCCESSFULon the POST and throughout the polling window even before the provider has confirmed — do not treatstatus: SUCCESSFULalone as a signal that the token has been issued. The presence of a populatedextraInfofield is the authoritative signal. If polling expires withoutextraInfobeing populated, raise a support ticket with thetracingContextvalue; do not retry the POST with the sameexternalUniqueId.
Channels that prefer a push model can supply a callbackUrl on the original POST — see Asynchronous Callbacks below.
Use Case 1 - Utility Token (Electricity)
The purpose of this integration is to process utility token purchases. The pre-vend validates the meter number against the upstream utility (Conlog Botswana); the vend issues the token. The token and customer receipt are returned in the extraInfo field.
Prerequisites
- A valid JWT for API calls.
- Tenant config fees.amount.config.Pay.GLOBAL_DEFERRED.WALLET.{partnerId}.{productCategory}=feeAmount
- Tenant config fees.wallet.config.Pay.GLOBAL_DEFERRED.WALLET=destinationWalletId (fee destination)
- Tenant config destination.wallet.config.VAS.{partnerId}.{productCategory}=destinationWalletId (VAS settlement destination)
Initiate Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
Authorization: Bearer <JWT>
Content-Type: application/json
{
"externalUniqueId": "{{$randomUUID}}",
"paymentData": "20_1248_1247",
"type": "GLOBAL_VAS",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
},
{
"id": "meterNumber",
"value": "21500123456"
}
],
"amount": 180,
"currency": "BWP",
"walletId": 2536583
}{
"paymentId": 4007245,
"externalUniqueId": "2c6d4298-d9c8-4616-82ef-c1f7e446cec7",
"status": "SUCCESSFUL",
"amount": 13.000000000,
"description": "VAS purchase PartnerId-20 : Utility Token",
"currency": "BWP",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
},
{
"id": "meterNumber",
"value": "21500123456"
}
],
"acceptedCardSchemes": [],
"cardPhone": "27847919825",
"phone": "27847919825",
"acceptedPaymentMechanisms": [
"WALLET",
"AMT",
"SECURE_CODE"
],
"paymentType": "WALLET",
"created": "2025-12-08T11:09:49.000Z",
"lastModified": "2025-12-08T11:09:50.124Z",
"paymentData": "20_1248_1247",
"extraInfo": "[{\"callbackId\":72628017,\"result\":\"...stringified JSON containing customer receipt, token number, KWh units, tariff details, electricityResponse...\"}]",
"paymentInstrumentInfo": {
"cardPhone": "27847919825"
},
"fee": 4,
"paymentReference": "1248_1247",
"walletId": 2536583,
"customerId": 8586330,
"gatewayTransactionId": "Payment-4007245",
"paymentTerminalData": {},
"tracingContext": "00-17cf8831a32a43f3370ba75356081445-b51bc51c2a65845b-01"
}On the POST, the response carries status: SUCCESSFUL and an empty/unpopulated extraInfo. The token (under electricityResponse.tokens), customer receipt, KWh units, and tariff details become available on the GET payment record once Eclipse has confirmed the vend with Conlog Botswana — typically within 5–30 seconds, but allow up to 2 minutes. Channels must poll GET /payments/{paymentId} and parse extraInfo to surface the token to the customer.
NoteSandbox test meter numbers:
00300123452or21500123456(Conlog Botswana fixture). In sandbox, invalid meter numbers may still returnstatus: SUCCESSFULas pre-vend validation against the live utility provider is bypassed in non-production environments.
Use Case 2 - DSTV Recharge
The purpose of this integration is to allow customers to pay DSTV subscriptions. The pre-vend validates the DSTV account number; the vend recharges the account.
Prerequisites
- A valid JWT for API calls.
- Tenant config fees.amount.config.Pay.GLOBAL_DEFERRED.WALLET.{partnerId}.{productCategory}=feeAmount
- Tenant config fees.wallet.config.Pay.GLOBAL_DEFERRED.WALLET=destinationWalletId
- Tenant config destination.wallet.config.VAS.{partnerId}.{productCategory}=destinationWalletId
Initiate Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
Authorization: Bearer <JWT>
Content-Type: application/json
{
"externalUniqueId": "{{$randomUUID}}",
"paymentData": "20_1260_1259",
"type": "GLOBAL_VAS",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
},
{
"id": "accountNumber",
"value": "12345678"
}
],
"amount": 33,
"currency": "BWP",
"walletId": 2536583
}In this use case the paymentData field is set to \{partnerId\}_\{vendProductId\}_\{prevendProductId\} i.e. 20_1260_1259
PartnerId = 20
VendProductId = 1260 (Bots DSTV Recharge)
PrevendProductId = 1259 (Bots DSTV Balance)
The response shape mirrors the Utility Token response above. As with utility tokens, extraInfo is not populated on the POST response and must be retrieved via GET polling.
Use Case 3 - Airtime Purchase
LFSB wallet holders can purchase airtime from Orange, BE Mobile, and Mascom. Airtime products are fixed-price, so the amount value is determined by the selected productId and does not need to be supplied on the request.
Prerequisites
- A valid JWT for API calls.
- Tenant config fees.amount.config.Pay.GLOBAL_DEFERRED.WALLET.{partnerId}.{productCategory}=feeAmount
- Tenant config fees.wallet.config.Pay.GLOBAL_DEFERRED.WALLET=destinationWalletId
- Tenant config destination.wallet.config.VAS.{partnerId}.{productCategory}=destinationWalletId
Initiate Payment
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
Authorization: Bearer <JWT>
Content-Type: application/json
{
"externalUniqueId": "{{$randomUUID}}",
"paymentData": "20_501_0",
"type": "GLOBAL_VAS",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
}
],
"currency": "BWP",
"walletId": 2536583
}In this example 20_501_0 purchases BE MOBILE 20 (productId 501). The trailing _0 indicates no pre-vend product is required for fixed-price airtime.
{
"paymentId": 4007260,
"externalUniqueId": "59802001-ac18-4695-9e9f-a0e3a359826b",
"status": "SUCCESSFUL",
"amount": 20.000000000,
"description": "VAS purchase PartnerId-20 : BE MOBILE 20",
"currency": "BWP",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
}
],
"acceptedCardSchemes": [],
"cardPhone": "27847919825",
"phone": "27847919825",
"acceptedPaymentMechanisms": [
"WALLET",
"AMT",
"SECURE_CODE"
],
"paymentType": "WALLET",
"created": "2025-12-08T11:12:39.000Z",
"paymentData": "20_501_0",
"extraInfo": "[{\"callbackId\":72628059,\"result\":\"...stringified JSON containing saleItemList with serialNumber, pinNumber, expiryDate...\"}]",
"paymentInstrumentInfo": {
"cardPhone": "27847919825"
},
"fee": 5,
"paymentReference": "501_0",
"walletId": 2536583,
"customerId": 8586330,
"gatewayTransactionId": "Payment-4007260",
"paymentTerminalData": {}
}As with utility tokens, the POST response returns status: SUCCESSFUL with an unpopulated extraInfo. For pinned airtime products (e.g. BE MOBILE), the voucher serial and PIN inside extraInfo.result.saleItemList become available on the GET payment record once Eclipse has confirmed the vend with the upstream network. Channels must poll GET /payments/{paymentId} and parse saleItemList to surface the voucher to the customer.
Response Field Reference
| Field | Description |
|---|---|
| paymentId | Eclipse-generated unique identifier for the payment. Use this for status enquiries via GET /payments/{paymentId}. |
| externalUniqueId | The idempotency key supplied by the channel on the request. Eclipse rejects duplicate externalUniqueId values within the tenant. |
| status | Terminal or intermediate state of the payment. See Transaction Status Codes below. |
| amount | Amount transacted, in major currency units. Determined by productId for fixed-price products. |
| description | Human-readable description, populated by Eclipse based on the partner and product. |
| currency | ISO 4217 currency code. Must match the wallet currency. |
| additionalFields | Echoes the additional fields supplied on the request (msisdn, meterNumber, accountNumber). |
| acceptedCardSchemes | List of card schemes accepted for this payment. Empty for wallet-funded VAS. |
| acceptedPaymentMechanisms | List of payment mechanisms supported for this payment (e.g. WALLET, AMT, SECURE_CODE). |
| cardPhone / phone | Customer contact number populated from the wallet record. |
| paymentType | The payment instrument used. For wallet-funded VAS this will be WALLET. |
| paymentInstrumentInfo | Nested object echoing details of the instrument used (e.g. cardPhone for wallet payments). |
| paymentData | Echoes the paymentData value from the request. |
| extraInfo | Provider-specific payload as a stringified JSON. Not populated on the POST response — retrieved via GET /payments/{paymentId} polling after Eclipse has confirmed the vend with the upstream provider (typically within 5–30 seconds, allow up to 2 minutes). For utility tokens contains the token number, customer receipt, KWh units, tariff details, and electricityResponse object. For pinned airtime contains the voucher serial and PIN inside saleItemList. Channels must parse and surface this content to the customer. |
| paymentReference | Reference used for reconciliation. Composed of {vendProductId}_{prevendProductId}. |
| fee | Transaction fee applied per tenant config. |
| walletId | Source wallet from which the payment was funded. |
| customerId | Eclipse customer ID associated with the payment. |
| gatewayTransactionId | Eclipse internal gateway reference. |
| paymentTerminalData | Terminal data object. Empty for VAS; populated for card-present transactions. |
| tracingContext | W3C trace context. Useful when raising support tickets to correlate with Eclipse server logs. |
| errorDescription | Populated only on status FAILED or ERROR. |
Transaction Status Codes
| Status | Meaning | Action expected from channel |
|---|---|---|
| SUCCESSFUL | Eclipse has accepted the request and deducted funds from the source wallet. Note that this status is returned immediately on the POST and does not by itself indicate that the upstream vend has completed — Eclipse asynchronously confirms the final state with the provider. | Poll GET /payments/{paymentId} (or wait for a callback) until extraInfo is populated, then render the token/PIN/receipt to the customer. Status may transition to FAILED if Eclipse's async confirmation determines the vend did not complete at the provider, in which case the wallet is reversed. |
| PENDING | Eclipse has accepted the request but the upstream provider has not yet confirmed completion. | Wait for callback (if callbackUrl was supplied) or poll GET /payments/{paymentId}. Do not retry the POST — externalUniqueId will reject duplicates. |
| BUILDING | Intermediate state seen only when a separate PUT is required to finalise the payment. Does not apply to FrontierWeb single-POST flows. | N/A for FrontierWeb. |
| FAILED / ERROR | The transaction did not complete. Funds have been reversed on the source wallet. | Inspect errorDescription and the application error envelope (code, traceId). Surface a user-facing error and allow retry with a new externalUniqueId. |
For the full Eclipse application error code list, see Application Error Codes.
The error envelope returned by Eclipse on a failed call follows this shape:
[
{
"type": "BUSINESS",
"severity": "INFO",
"description": "Invalid voucher for the users network. User is on network id 0 but voucher is for network id 20",
"code": "IAE001",
"traceId": "9099797c1668796c2ba0b371b76a45df",
"spanId": "c06f2d77d914b3fb"
}
]Asynchronous Callbacks
Every FrontierWeb VAS payment finalises asynchronously — the POST response returns status: SUCCESSFUL with funds deducted but without extraInfo. Channels have two options for retrieving the final extraInfo payload: polling (see Retrieving the token / voucher above) or callbacks.
To receive a callback when the async confirmation completes, supply a callbackUrl on the original POST. Eclipse will POST to this URL once it has confirmed the final state with the upstream provider. The callback body carries the same payment object shape as the GET response and will include the populated extraInfo. Status on the callback may be SUCCESSFUL (token/voucher issued, extraInfo populated) or FAILED / ERROR (wallet reversed).
POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
Authorization: Bearer <JWT>
Content-Type: application/json
{
"externalUniqueId": "{{$randomUUID}}",
"paymentData": "20_1248_1247",
"type": "GLOBAL_VAS",
"callbackUrl": "https://channel.tenant.example.com/eclipse/vas/callback",
"additionalFields": [
{
"id": "msisdn",
"value": "772216623"
},
{
"id": "meterNumber",
"value": "21500123456"
}
],
"amount": 180,
"currency": "BWP",
"walletId": 2536583
}Callback security
Callbacks from Eclipse to the channel are secured under the standard Eclipse webhook security model: TLS 1.2+ on the transport layer, and an Eclipse-Signature HTTP header carrying an HMAC-SHA256 signature of the timestamp and message body, signed with the tenant's HMACOutboundSignatureKey. The 5-minute replay window, optional RSA v2 signature mode, optional webhookAuthorizationHeader, and optional JWE full-payload encryption are all documented on the Encryption and Integrity page.
Source IP allow-list
Channels that whitelist inbound traffic should permit calls from the following Eclipse source IPs:
- Production:
79.125.40.127,54.220.185.240,18.134.2.182,3.11.195.109 - Sandbox:
34.255.93.65
Retries
Eclipse will retry callbacks on non-2xx responses. Retry behaviour is documented on the CallbackURL Retries page.
Polling alternative
If callback infrastructure is not available, channels can instead poll GET /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId} until extraInfo is populated or the payment reaches a terminal FAILED / ERROR status. Polling should be capped at 2 minutes (e.g. 24 attempts at 5-second intervals) to avoid hot loops.
Settlement
On successful VAS payment, Eclipse triggers a notification for funds to move from the customer's source wallet to the configured VAS destination wallet (destination.wallet.config.VAS.{partnerId}.{productCategory}) and the fee destination wallet (fees.wallet.config.Pay.GLOBAL_DEFERRED.WALLET). For tenants where the source wallet is fronted by an external bank trust account (e.g. Access Bank), Eclipse emits a settlement notification to trigger the corresponding bank-side movement.
Updated 8 days ago

