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:

  1. Retrieve the VAS catalog
  2. 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.
  3. Prepare catalog query - this is optional and the entire catalog can be retrieved.
  4. 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
  5. 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}
📘

Note

Currently only MTN And Vodacom are supported networks

Step 2 - Get the list of VAS partners & products

GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs

Step 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" }
    ]
  }
]

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

📘

Only required if information is still missing

This PUT call is only needed to supply fields that weren't included in the original POST — in the worked example above, that's amount. If the tenant config attempt.onestep.payment.completion.enabled is true (the default for tenants) and the POST already includes everything the payment needs — walletId, amount, and currency — the payment service attempts to complete the payment automatically as part of that POST call, and this PUT step is not required.

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
  1. 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/catalogs

Step 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

📘

Only required if information is still missing

This PUT call is only needed to supply fields that weren't included in the original POST — in the worked example above, that's amount. If the tenant config attempt.onestep.payment.completion.enabled is true (the default for tenants) and the POST already includes everything the payment needs — walletId, amount, and currency — the payment service attempts to complete the payment automatically as part of that POST call, and this PUT step is not required.

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 ACS

Once 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.

USSD String

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 Stellr

Introduction

Stellr services can be integrated with Eclipse as an open feature platform. It provides a comprehensive catalog of vouchers that tenants can use to manage airtime, data, and bill payment products. Stellr defines its own product categories on its side — Eclipse does not map them to a fixed set of product types the way it does for some other providers.

Prerequisites

  • A valid JWT for API calls.
  • Tenant config mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.StellrMobileRecharge
  • Tenant config stellr.config.baseUrl={baseUrl}
  • Tenant config stellr.config.apiKey={apiKey}
  • Tenant config destination.wallet.config.VAS.13={destination walletId}
  • Tenant config fees.wallet.config.VAS={fee walletId}

Step 1 – Fetch Catalog

GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs

Filter on Stellr's Partner ID 13 (partnerName contains stellr) and select the productId from the catalog to proceed with the payment process.

Example Response (filtered to Stellr's entry):

[
  {
    "partnerId": 13,
    "partnerName": "stellr",
    "providerId": 13,
    "products": [
      {
        "additionalFields": [],
        "fixedPriceIncl": 100,
        "partnerId": 13,
        "pinnedProduct": false,
        "productDescription": "Nija UAT test product",
        "productId": "800045021161",
        "productName": "Nija Test Product 1",
        "productTypeName": "Digital - Commission"
      }
    ]
  }
]
📘

Catalog is cached for 24 hours

Eclipse caches the Stellr product catalog for 24 hours rather than calling Stellr's catalog endpoint on every request. A newly added or changed Stellr product can take up to 24 hours to appear.

Step 2 - Initiate a Payment

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
{
  "externalUniqueId": "WPS-18642422-1dee-4c8f-b2b3-a005cc0de642",
  "type": "GLOBAL_VAS",
  "paymentData": "13_800045021161",
  "amount": 100,
  "currency": "ZAR",
  "walletId": 9331455,
  "additionalFields": [
    { "id": "msisdn", "value": "0772216623" }
  ]
}

In this use case the paymentData field is set to the partnerId and productId, i.e. 13_800045021161

PartnerId = 13

productId = 800045021161

amount is required for Stellr — use the catalog product's fixed price if one is set (fixedPriceIncl), otherwise a value within the product's minimum/maximum amount.

Example Response:

{
  "paymentId": 4496948,
  "externalUniqueId": "WPS-18642422-1dee-4c8f-b2b3-a005cc0de642",
  "status": "SUCCESSFUL",
  "amount": 100.000000000,
  "currency": "ZAR",
  "paymentData": "13_800045021161",
  "paymentReference": "800045021161",
  "description": "VAS purchase Digital - Commission PartnerId-13 : Nija UAT test product",
  "paymentType": "WALLET",
  "walletId": 9331455,
  "fee": 1,
  "gatewayTransactionId": "Payment-4496948",
  "phone": "27189408694",
  "additionalFields": [
    { "id": "msisdn", "value": "0772216623" }
  ]
}

Stellr returns a success response once the payment is completed successfully.

📘

Single-step or two-step — same pattern as every VAS provider in this guide

This POST already includes walletId, amount, and currency — everything the payment needs to complete. With the tenant config attempt.onestep.payment.completion.enabled set to true (the default for tenants), the payment service attempts to complete the payment automatically as part of this same POST call, so no separate PUT is needed. If you don't have the wallet ID or amount at initiation time, POST without them and follow with a PUT to /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId} supplying whatever was missing to complete the payment in a second step.

📘

Why the token is (almost always) already on this response

status: SUCCESSFUL above confirms the wallet debit. When Eclipse's confirmation call to Stellr's own API resolves, the token/voucher payload is written directly onto the payment via an internal PUT /rest/v1/payments/{paymentId}/info call (EclipseVasService.recordVasOutcomeOnPayment) — and the completing call (this POST, or the PUT in a two-step flow) waits on that outcome for up to vas.result.wait.seconds (default 60 seconds) before responding. So extraInfo is usually already populated by the time you get a response at all. If Stellr is unusually slow and the wait window elapses first, a later GET /payments/{paymentId} returns the same populated extraInfo once it lands — no special fields query parameter is needed; GET always returns whatever is currently on the payment record.

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_T089775335322

Prepare 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

📘

Only required if information is still missing

This PUT call is only needed to supply fields that weren't included in the original POST — in the worked example above, that's amount. If the tenant config attempt.onestep.payment.completion.enabled is true (the default for tenants) and the POST already includes everything the payment needs — walletId, amount, and currency — the payment service attempts to complete the payment automatically as part of that POST call, and this PUT step is not required.

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/catalogs

Filter 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

📘

Only required if information is still missing

This PUT call is only needed to supply fields that weren't included in the original POST — in the worked example above, that's walletId and amount. If the tenant config attempt.onestep.payment.completion.enabled is true (the default for tenants) and the POST already includes everything the payment needs — walletId, amount, and currency — the payment service attempts to complete the payment automatically as part of that POST call, and this PUT step is not required.

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/catalogs

Filter 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

📘

Only required if information is still missing

This PUT call is only needed to supply fields that weren't included in the original POST — in the worked example above, that's amount. If the tenant config attempt.onestep.payment.completion.enabled is true (the default for tenants) and the POST already includes everything the payment needs — walletId, amount, and currency — the payment service attempts to complete the payment automatically as part of that POST call, and this PUT step is not required.

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:

  1. mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.DTBQueryUtilityRecharge
  2. 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_10202300000582380

The 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

📘

Note

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

  1. mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.DTBQueryUtilityRecharge
  2. 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-CATALOG

API 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

📘

Note

The 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

📘

Note

The 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}/payments

Example 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

📘

Note

The 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/payments

Example 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_2240000621955

The 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

📘

Note

The 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_256779999703

The 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-DSTV

17 - 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

📘

Only required if information is still missing

This PUT call is only needed to supply fields that weren't included in the original POST — in the worked example above, that's amount. If the tenant config attempt.onestep.payment.completion.enabled is true (the default for tenants) and the POST already includes everything the payment needs — walletId, amount, and currency — the payment service attempts to complete the payment automatically as part of that POST call, and this PUT step is not required.

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.

Zimbabwe VAS providers

The following VAS provider is specific to tenants operating in Zimbabwe.

Purchase Electricity through ZETDC

Introduction

ZETDC (Zimbabwe Electricity Transmission and Distribution Company) issues prepaid electricity tokens against a customer's meter number. Eclipse integrates with the ZETDC aggregator (esolutions.co.zw) through ZetdcVasProvider, following the standard two-stage VAS pattern used elsewhere in this guide: a validation call against the meter number, followed by a purchase call that returns the electricity token.

The provider is registered under provider/network ID 30.

Prerequisites

  • A valid JWT for API calls.
  • Tenant config mobilerecharge.providers=com.ukheshe.services.mobilerecharge.provider.ZetdcVasProvider
  • Tenant config source.wallet.config.VAS.30={sourceWalletId} — the float wallet debited for the purchase. This does not need to be a dedicated VAS wallet; any active wallet with sufficient balance can be configured here.
  • Tenant config destination.wallet.config.VAS.30={destinationWalletId} — the settlement wallet credited on a successful purchase.
  • Tenant config zetdc.vas.config.baseUrl={aggregator path}, default /zetdc/billpayments/vend
  • Tenant config zetdc.vas.config.vendorNumber={vendorNumber}, default VE19257147501
  • Tenant config zetdc.vas.config.terminalId={terminalId}, default POS001
  • Tenant config zetdc.vas.config.allowedCurrencies={comma-delimited list}, default USD,ZWG
  • Tenant config zetdc.vas.config.meterNumberRegex, default ^[0-9]{11}$

Step 1 - Validate the meter and fetch the catalog

The catalog query for ZETDC follows the shape {providerId}_ZETDC_{meterNumber}_{amount}_{currency}.

GET /eclipse-conductor/rest/v1/tenants/{tenantId}/vas/catalogs?catalogQuery=30_ZETDC_14316800680_10_ZWG

Eclipse validates the meter number against ZETDC and returns the customer name/address in the catalog response:

[
  {
    "partnerId": 30,
    "partnerName": "ZETDCVasProvider",
    "providerId": 30,
    "products": [
      {
        "productId": "ZETDC_14316800680",
        "productName": "ZETDC_PREPAID",
        "pinnedProduct": false,
        "additionalFields": [
          { "id": "customerName", "defaultValue": "MOCK CUSTOMER" },
          { "id": "customerAddress", "defaultValue": "123 Mock Street" }
        ]
      }
    ]
  }
]
📘

Note

Sandbox test meter number 14316800680 returns a mock customer (MOCK CUSTOMER, 123 Mock Street) against the sandbox ZETDC aggregator.

Step 2 - Initiate Payment

Like Stellr and every other VAS provider in this guide, ZETDC supports both a single-step and a two-step completion pattern:

  • Single-step — supply walletId, amount, and currency on the POST. If the tenant config attempt.onestep.payment.completion.enabled is true (the default), the payment service completes the payment as part of this same call.
  • Two-step — POST without walletId/amount, then follow with a PUT to /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId} supplying them once known.

Single-step example

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
Authorization: Bearer <JWT>
Content-Type: application/json

{
    "externalUniqueId": "{{$randomUUID}}",
    "paymentData": "30_ZETDC_14316800680",
    "type": "GLOBAL_VAS",
    "additionalFields": [
        { "id": "msisdn", "value": "0773176741" }
    ],
    "amount": 10,
    "currency": "ZWG",
    "walletId": 254496353
}

paymentData is {providerId}_ZETDC_{meterNumber} i.e. 30_ZETDC_14316800680. Unlike Conlog Botswana or ACS electricity, ZETDC has no separate meterNumber additionalField — the meter number is carried entirely inside paymentData/catalogQuery. msisdn is still required, as it is for every VAS provider.

Two-step example (POST without wallet/amount, then PUT to complete)

POST /eclipse-conductor/rest/v1/tenants/{tenantId}/customers/{customerId}/payments
Authorization: Bearer <JWT>
Content-Type: application/json

{
    "externalUniqueId": "vas-e000da58-3681-4720-acbf-4e3bdeea2ed3",
    "paymentData": "30_ZETDC_14316800680",
    "type": "GLOBAL_VAS",
    "amount": 32,
    "currency": "USD",
    "additionalFields": [
        { "id": "msisdn", "value": "263123456789" },
        { "id": "catalogQuery", "value": "30_ZETDC_14316800680_32_USD" }
    ]
}

Example Response (POST — walletId is still missing, so the payment can't complete yet)

{
    "paymentId": 4507000,
    "externalUniqueId": "vas-e000da58-3681-4720-acbf-4e3bdeea2ed3",
    "status": "BUILDING",
    "amount": 32.000000000,
    "currency": "USD",
    "description": "VAS purchase ELECTRICITY PartnerId-30 : ZETDC electricity token for meter 14316800680",
    "additionalFields": [
        { "id": "msisdn", "value": "263123456789" },
        { "id": "catalogQuery", "value": "30_ZETDC_14316800680_32_USD" }
    ],
    "paymentType": "UNKNOWN",
    "paymentData": "30_ZETDC_14316800680",
    "paymentReference": "ZETDC_14316800680",
    "fee": 0,
    "gatewayTransactionId": "Payment-4507000"
}
PUT /eclipse-conductor/rest/v1/tenants/{tenantId}/payments/{paymentId}
Authorization: Bearer <JWT>
Content-Type: application/json

{
    "walletId": 254693976,
    "amount": 32,
    "additionalFields": [
        { "id": "msisdn", "value": "263123456789" },
        { "id": "catalogQuery", "value": "30_ZETDC_14316800680_32_USD" }
    ]
}

Example Response (PUT — completes the payment; note extraInfo is already populated)

{
    "paymentId": 4507000,
    "externalUniqueId": "vas-e000da58-3681-4720-acbf-4e3bdeea2ed3",
    "status": "SUCCESSFUL",
    "amount": 32,
    "currency": "USD",
    "description": "VAS purchase ELECTRICITY PartnerId-30 : ZETDC electricity token for meter 14316800680",
    "additionalFields": [
        { "id": "msisdn", "value": "263123456789" },
        { "id": "catalogQuery", "value": "30_ZETDC_14316800680_32_USD" }
    ],
    "paymentType": "WALLET",
    "paymentData": "30_ZETDC_14316800680",
    "paymentReference": "ZETDC_14316800680",
    "extraInfo": "{\"voucherCode\":\"71899296371909876506|272.0|0.1|1786750329|2720|480|0.15\",\"instructions\":\"Key this token into your electricity meter to load the units you bought.\",\"reference\":\"TOK9357055251\",\"resultText\":\"{\\\"transactionReference\\\":\\\"ESO42654245580\\\",\\\"utilityAccount\\\":\\\"14316800680\\\",\\\"token\\\":\\\"71899296371909876506|272.0|0.1|1786750329|2720|480|0.15\\\",\\\"fixedCharges\\\":\\\"RE Levy(6%)|12345678|150|0|0.06\\\",\\\"arrears\\\":\\\"Debt Recovery|898766677|800|0|7700\\\",\\\"narrative\\\":\\\"Transaction processed successfully\\\",\\\"currencyCode\\\":\\\"USD\\\",\\\"vendorReference\\\":\\\"TOK9357055251\\\",\\\"responseCode\\\":\\\"00\\\"}\"}",
    "walletId": 254693976,
    "fee": 0,
    "gatewayTransactionId": "Payment-4507000"
}

Why the token is (almost always) already there on this response

When the recharge callback resolves, Eclipse writes the token payload directly onto the payment via an internal PUT /rest/v1/payments/{paymentId}/info call (EclipseVasService.recordVasOutcomeOnPayment). The completing call — whichever one it is, the PUT above or a single-step POST — waits (joins) on that outcome for up to vas.result.wait.seconds (default 60 seconds) before responding, so in the overwhelming majority of cases the token is already in extraInfo by the time you get a response at all.

If ZETDC is unusually slow and the wait window elapses first, the payment still completes and a later GET /payments/{paymentId} returns the exact same populated extraInfo once it lands:

Example Response (GET, any time after)

{
    "paymentId": 4507000,
    "externalUniqueId": "vas-e000da58-3681-4720-acbf-4e3bdeea2ed3",
    "status": "SUCCESSFUL",
    "amount": 32.000000000,
    "currency": "USD",
    "description": "VAS purchase ELECTRICITY PartnerId-30 : ZETDC electricity token for meter 14316800680",
    "additionalFields": [
        { "id": "msisdn", "value": "263123456789" },
        { "id": "catalogQuery", "value": "30_ZETDC_14316800680_32_USD" }
    ],
    "paymentType": "WALLET",
    "paymentData": "30_ZETDC_14316800680",
    "paymentReference": "ZETDC_14316800680",
    "extraInfo": "{\"voucherCode\":\"71899296371909876506|272.0|0.1|1786750329|2720|480|0.15\",\"instructions\":\"Key this token into your electricity meter to load the units you bought.\",\"reference\":\"TOK9357055251\",\"resultText\":\"{\\\"transactionReference\\\":\\\"ESO42654245580\\\",\\\"utilityAccount\\\":\\\"14316800680\\\",\\\"token\\\":\\\"71899296371909876506|272.0|0.1|1786750329|2720|480|0.15\\\",\\\"fixedCharges\\\":\\\"RE Levy(6%)|12345678|150|0|0.06\\\",\\\"arrears\\\":\\\"Debt Recovery|898766677|800|0|7700\\\",\\\"narrative\\\":\\\"Transaction processed successfully\\\",\\\"currencyCode\\\":\\\"USD\\\",\\\"vendorReference\\\":\\\"TOK9357055251\\\",\\\"responseCode\\\":\\\"00\\\"}\"}",
    "walletId": 254693976,
    "fee": 0,
    "gatewayTransactionId": "Payment-4507000"
}

Decoded extraInfo

extraInfo is a flat, stringified JSON object — not an array. Un-escaping it, and its nested resultText string, gives:

{
  "voucherCode": "71899296371909876506|272.0|0.1|1786750329|2720|480|0.15",
  "instructions": "Key this token into your electricity meter to load the units you bought.",
  "reference": "TOK9357055251",
  "resultText": {
    "transactionReference": "ESO42654245580",
    "utilityAccount": "14316800680",
    "token": "71899296371909876506|272.0|0.1|1786750329|2720|480|0.15",
    "fixedCharges": "RE Levy(6%)|12345678|150|0|0.06",
    "arrears": "Debt Recovery|898766677|800|0|7700",
    "narrative": "Transaction processed successfully",
    "currencyCode": "USD",
    "vendorReference": "TOK9357055251",
    "responseCode": "00"
  }
}
FieldDescription
voucherCodeThe STS token string, pipe-delimited (token|units|price|timestamp|...) — only the first segment is what the customer keys into the meter. Same value as resultText.token.
instructionsHuman-readable copy for the customer, ready to display as-is.
referenceEclipse/vendor transaction reference. Same value as resultText.vendorReference.
resultText.tokenThe STS token string — see voucherCode above.
resultText.vendorReference / resultText.transactionReferenceEclipse-side and ZETDC-side transaction references.
resultText.narrativeHuman-readable status text from ZETDC.
resultText.fixedChargesLevies/charges applied to the purchase, pipe-delimited.
resultText.arrearsOutstanding debt-recovery balance on the meter, if any — surface this to the customer when present.
resultText.responseCode"00" indicates success.
📘

voucherCode / instructions / reference are universal, not ZETDC-specific

This outer wrapper (EclipseVasService.recordVasOutcomeOnPayment) is built the same way for every VAS/mobile-recharge provider — it is not something specific to ZETDC. Only the inner resultText content is provider-specific: ZETDC's is the curated set of named fields shown above, while other providers (e.g. Stellr) put a different, provider-defined payload inside resultText. Always check for resultText and parse defensively rather than hard-coding one provider's inner shape.

Settlement

On successful purchase, Eclipse transfers funds from the source wallet (source.wallet.config.VAS.30) to the destination wallet (destination.wallet.config.VAS.30) via the standard wallet-transfer pipeline. Reversal on failure is handled automatically by the generic payment-service/wallet reversal machinery — no separate reversal call is required.

Using ZETDC via IPOS (Postilion card-present POS transactions)

In addition to the channel-facing REST flow above, ZETDC electricity purchases can also be initiated from a physical POS terminal over the IPOS/Postilion ISO 8583 switch connection. This reuses the same ZetdcVasProvider integration and the same source.wallet.config.VAS.30 / destination.wallet.config.VAS.30 wallet configuration — only the trigger differs: a card transaction at a merchant terminal rather than a REST call from an app or portal.

How it's triggered

A POS terminal connected through Postilion sends an ISO 8583 message (MTI 0100 Authorisation Request, followed by MTI 0200 Financial Request) with processing-code transaction type 28, carrying the merchandise-dispatch payload in field 127, sub-element 22 (structured data):

  • A PrepaidMerchandise XML block with NetworkID="ZETDC" and a ProductID
  • The meter number, under structured-data key MeterNumber (or nested inside PosStructuredData)
  • The tenant ID, carried in field 42 (Card Acceptor ID Code)

Eclipse's Postilion service matches the NetworkID="ZETDC" value and:

  1. On the 0100 auth leg, validates the meter (the same validation used in Step 1 above) and returns the customer name/address into the ISO response structured data — no wallet movement occurs at this stage.
  2. On the 0200 financial leg, resolves the source and destination wallets from the same source.wallet.config.VAS.30 / destination.wallet.config.VAS.30 tenant config used by the REST flow, creates and finalises a payment exactly as in Step 2 above, and polls for the token.
  3. Injects the returned token into the ISO response structured data (keys Token, TransactionRef, Narrative) so the POS terminal can print it on the customer's receipt.
📘

Note

Reversal (ISO MTI 0420) requires no bespoke handling at the Postilion layer — the wallet debit is reversed automatically by the same generic payment-service reversal machinery used by the REST flow.

Additional prerequisites for IPOS

  • Tenant config postilion.msd.supported.extended.txtype must include the extended transaction type carried by the terminal (defaults to 9200,9000).
  • The tenant's inbound card-program processor (postilionInboundProcessor, optionally suffixed per card program) must resolve to a processor that supports credit transaction types. If it resolves to a processor that unconditionally rejects credit/debit transactions, merchandise-dispatch requests — including ZETDC — are declined before they reach the VAS handler.
📘

Note

IPOS/Postilion is an additional entry point into the same provider and wallet configuration used by the REST channel flow — enabling one does not require or exclude the other. A tenant can offer ZETDC purchases through a mobile app or portal (REST) and through in-store POS terminals (IPOS/Postilion) at the same time, sharing the same source and destination wallets.



Did this page help you?