zendit developers Logo
Search zendit documentation

zendit Catalog

In this guide, you will be introduced to the features of the zendit catalog and key concepts for integration.

For catalog management from the user console, please see the user guide.

Overview

zendit provides catalogs for Mobile Top Up, Digital Gift Cards, Prepaid Utilities and eSIMs.

Products are grouped by the catalog format they use and are separated into endpoints specific to the product type.

zendit offers the following product types for catalogs and purchases through the API:

  • Mobile Top Ups including:
    • Airtime value
    • Bundles
    • Data Plans
  • Digital Gift Cards
  • Prepaid Utilities
  • eSIMs including:
    • Standard plans with a set duration and data amount
    • Unlimited plans with a set duration

Key Concepts

The following sections will guide you through the key concepts of the zendit catalog.

Offers

The zendit catalog is based on the concept of an offer. Each offer has details about the product, the value delivered by the offer, the brand for the offer and pricing that may be set by the integrating partner to expose to their customers.

Offers have one of two price types: FIXED price items or RANGE price items.

FIXED Price Offers

FIXED price offers deliver a specific value for the product. The value delivered is predetermined on the catalog. As an example, a $10 value mobile topup for Claro delivering a set amount of GTQ based on the current FX rate for the offer.

RANGE Price Offers

RANGE price offers may be fulfilled based on the value (PRICE) to deliver within the boundaries of a minimum value, maximum value and in values within the increment for the offer. As an example, a CLARO range offer in USD is delivered at a price between 7 USD and 100 USD in increments of 1 USD. The offer may only be purchased in whole dollar increments when purchasing by PRICE.

RANGE price offers also support fulfillment by a ZEND value using the local currency.

Countries and Regions

The Zendit catalog can be filtered by Region and Country to narrow down searching for offers. When searching by Region, the following list of Regions are available:

  • Global
  • Africa
  • Asia
  • Caribbean
  • Central America
  • Eastern Europe
  • Western Europe
  • North America
  • Oceania
  • South America
  • South Asia
  • Southeast Asia
  • Middle East and North Africa

The Global region is surfaced for products that have worldwide support including some eSIM plans and Digital Gift Cards.

Countries on products use the ISO 3166-1 alpha-2 standard for. 2 letter country codes. For eSIMs, there are some non standard ISO codes such as XK for Kosovo that is recognized by the European Commission and the World Bank Databank but not currently in the ISO standard.

FX Rates in the Catalog

FX rates are subject to change in the catalog for values sent in local currency. While some FX rates are periodic and will retain a value over several days there are many offers that adjust the sent value based on a daily FX. Rates that adjust daily are refreshed and available at 08:30:00 UTC time daily.

Currency Divisors

When retrieving the catalog all Price, Cost and Send values contain a currency divisor. Numeric values are given in the lowest unit of currency (minor currency unit). For example, values for US Dollar (USD) are in pennies making a value of 1 = $0.01 and a value of 1500 = $15.00. To handle the display of pricing or delivery values, the currency divisor in the structure will assist in converting the currency into a display value.

For example, for XOF the currency divisor will be 1 since XOF doesn’t contain fractional units.

For USD the currency divisor will be 100 since USD supports up to 2 decimal places.

For JOD the currency divisor will be 1000 since JOD supports up the 3 decimal places.

When formatting a currency for display, use the numeric value given and divide it by the currency divisor. The resulting value will be formatted in the number of decimal places that the currency supports.

For example, when formatting 2375 XOF, take 2375 and divide by the currency divisor of 1 to get the resulting 2375 XOF.

When formatting 2375 USD, take 2375 and divide it by the currency divisor of 100 to get the resulting 23.75 USD.

When formatting 2375 JOD, take the 2375 and divide it by the currency divisor of 1000 to get the resulting 2.375 JOD.

Enabled vs. Disabled Offers

When retrieving the catalog, all offers are returned whether they are enabled or disabled. When evaluating a catalog item it is important to check whether the offer is enabled before exposing it to a user. Offers that are disabled in the catalog console will fail if attempted to be fulfilled. This is a security feature that allows catalog managers to turn on offers or turn them off.

Offer Subtypes

Offers may be filtered by their subtype when integrating with the catalog. Subtypes available include:

Mobile Top Up

  • Mobile Top Up
  • Mobile Bundle
  • Mobile Data

Mobile Top Up offers send a specific amount of value to the recipient.

Mobile Bundles deliver multiple services for the recipient including set amounts of voice, SMS, or data with some bundles delivering unlimited usage of some apps or unlimited voice or SMS usage. Bundles frequently have a set duration of time the bundle applies to the recipient.

Mobile Data delivers data services to recipients that may include specific amounts of data or unlimited data. Data plans frequently have a set duration of time that the data plan applies to the recipient.

eSIM

  • Standard
  • Fast
  • Faster
  • Fastest
  • Premium

eSIMs fall into 2 main types: Standard providing a fixed amount of data for a specified number of days and Unlimited Plans that provide specific amounts of high speed data per day and unlimited data at throttled speeds beyond. Please see the eSIM guide for more information.

Prepaid Utilities

  • Utilities

All prepaid utilities use the same subtype Utilities.

Digital Gift Cards

Digital Gift Cards have a flexible set of subtypes to categorize them based on the type of business be it Clothing & Accessories, Food & Beverage, etc. These subtypes may be used to categorize your catalog in your integration.

Catalog Pricing Structures

All offers contain a Cost and a Price structure. Products that deliver a local value will also contain a Sent structure. Refer to the API Documentation for more information.

Cost Structure

In the zendit catalog, each item has a cost provided in your wallet currency. The values included are:

FieldMeaning
currencyValues in the cost structure will be in the currency specified. This will be the same currency as your zendit wallet.
currencyDivisorThe currency divisor is useful for converting the integer values to decimal values as desired.
discountThe discount from the full value of the item to your cost for the item.
feeThe fixed amount of fee that may be applied to the product. Few products have a fee applied.
feePctA percentage based fee applied to the cost.
fixedThe price of a FIXED type offer exclusive of fees.
fxFor products that deliver a VALUE (Mobile Top Up, Digital Gift Cards, Prepaid Utilities) the FX rate from the cost to the sent value.
minThe minimum price of a RANGE type offer exclusive of fees.
maxThe maximum price of a RANGE type offer exclusive of fees

To understand the full cost of an item, use the cost field (fixed for FIXED offers, min/max for RANGE offers) and add the fee amounts to arrive at the full cost of the item.

Price Structure

The Price Structure is useful for partners who don’t have their own catalog system and wish to use zendit’s pricing module for setting the price of items to expose to customers purchasing products. Partners using their own catalog system and selling RANGE type offers will need to understand the values in this structure to submit transactions correctly in zendit. The values in the price structure are as follows:

FieldMeaning
currencyCurrency for the price. This will match the wallet currency.
currencyDivisorDivisor useful for converting integer prices to decimal values.
feeFee setup in the pricing module of the catalog to add to the product price presented to the customer.
fixedPrice to charge a customer for a FIXED type product.
fxThe FX applied for products that deliver VALUE to the local currency based on the price.
incrementThe increment amount supported by a RANGE type product.
marginThe margin on the product from the PRICE to the COST exclusive of fees.
maxThe maximum value that may be delivered by a RANGE product.
minThe minimum value that may be delivered by a RANGE product.
suggestedFixedzendit’s suggested price for a fixed price product.
suggestedFxzendit’s suggested FX to apply to a range product.

The Price structure allows the partner to handle pricing for an item to present to the user. For range products, the value must be between the minimum and maximum values and in increments as defined by the increment. For more information on how RANGE offers are handled, see the Transaction Guide.

Sent Structure

The Sent structure is provided when a product delivers a value in local currency including Mobile Top Up products (all subtypes), Digital Gift Cards (all subtypes) and Prepaid Utilities.

The sent structure contains the following values:

FieldMeaning
currencyThe currency for the local value that is sent.
currencyDivisorDivisor useful for converting integer prices to decimal values.
fixedThe value sent for a FIXED type product.
fxNot used in delivery, provided for backward compatibility with older integrations.
maxThe maximum amount of local value delivered for a RANGE product.
minThe minimum amount of local value delivered for a RANGE product.

Products that send a value in local currency, will provide the values the recipient will receive based on the Price of the product.

Integrating the zendit Catalog

The zendit catalog may be used directly in an integration providing the product details and customer facing pricing, may be cached locally by the integration with periodic refreshes (suggested update frequency for caches is 30 minutes) or for partners who have their own catalog systems, you may just use the Offer IDs to map products from your own catalog.

Depending on the caching strategy, all catalog items include an updatedAt timestamp with a date/time in UTC. When retrieving a catalog to update cache, the timestamps can be used to note whether an item has been updated since the last cache retrieval to ignore an update.

Using the Catalog from the API

When retrieving the catalog from the API or through an SDK, all items will be returned in a paginated manner.

zendit provides multiple catalog endpoints based on the product type.

The /topups Endpoints

All Mobile Top Up Products including Mobile Top Up, Mobile Bundle and Mobile Data products are available through the /topups catalog endpoints.

An example of a fixed topup product:

{
      "enabled": true,
      "offerId": "CLARO_GT_OPEN_0010",
      "country": "GT",
      "regions": [
        "Central America"
      ],
      "brand": "Claro",
      "brandName": "Claro",
      "productType": "TOPUP",
      "subTypes": [
        "Mobile Top Up"
      ],
      "notes": "",
      "shortNotes": "",
      "priceType": "FIXED",
      "send": {
        "currency": "GTQ",
        "currencyDivisor": 100,
        "fixed": 7660,
        "fx": 1
      },
      "price": {
        "currency": "USD",
        "currencyDivisor": 100,
        "fixed": 1000,
        "suggestedFixed": 1000,
        "fx": 7.66,
        "suggestedFx": 7.66,
        "margin": 0.11,
        "fee": 0
      },
      "cost": {
        "currency": "USD",
        "currencyDivisor": 100,
        "fixed": 890,
        "fx": 8.60674157,
        "fee": 0,
        "feePct": 0,
        "discount": 0.11
      },
      "durationDays": 0,
      "dataGB": 0,
      "dataUnlimited": false,
      "smsNumber": 0,
      "smsUnlimited": false,
      "voiceMinutes": 0,
      "voiceUnlimited": false,
      "createdAt": "2025-02-17T05:52:01.419Z",
      "updatedAt": "2026-02-16T00:00:00Z"
    }

Note the values to present for Mobile Bundle products:

  • durationDays – the duration of the bundle
  • dataGB – the amount of data delivered in GB
  • dataUnlimited – flag if data included is unlimted
  • smsNumber – a fixed number of SMS messages included
  • smsUnlimited – unlimited SMS messages included
  • voiceMinutes – number of voice minutes included
  • voiceUnlimited – unlimited voice minutes included

For Mobile Data products, a subset of the bundle properties are used including:

  • durationDays – the duration of the bundle
  • dataGB – the amount of data delivered in GB
  • dataUnlimited – flag if data included is unlimted

The /vouchers Endpoints

All Digital Gift Card and Prepaid Utility products use the /vouchers endpoints.

An example of a Digital Gift Card:

{
      "enabled": true,
      "offerId": "ADIDAS_US_001_EGIFT",
      "country": "US",
      "regions": [
        "North America"
      ],
      "brand": "Adidas",
      "brandName": "Adidas",
      "productType": "VOUCHER",
      "subTypes": [
        "Clothing & Accessories"
      ],
      "notes": "",
      "shortNotes": "",
      "priceType": "FIXED",
      "send": {
        "currency": "USD",
        "currencyDivisor": 100,
        "fixed": 500,
        "fx": 1
      },
      "price": {
        "currency": "USD",
        "currencyDivisor": 100,
        "fixed": 500,
        "suggestedFixed": 500,
        "fx": 1,
        "suggestedFx": 1,
        "margin": 0.044,
        "fee": 0
      },
      "cost": {
        "currency": "USD",
        "currencyDivisor": 100,
        "fixed": 478,
        "fx": 1.0460251,
        "fee": 0,
        "feePct": 0,
        "discount": 0.044
      },
      "requiredFields": [
        "recipient.firstName",
        "recipient.lastName"
      ],
      "deliveryType": "redemptionURL",
      "createdAt": "2025-02-17T05:52:04.212Z",
      "updatedAt": "2026-02-16T00:00:00Z"
    }

For the /voucher endpoints, it’s important to note the requiredFields structure and delivery types. For more information about working with vouchers, see the Digital Gift Cards and Prepaid Utilities Guide.

The /esim Endpoints

eSIM products use the /esim endpoints. An example eSIM:

{
      "enabled": true,
      "offerId": "ESIM-US-HI-30D-5GB-NOROAM",
      "regions": [
        "North America"
      ],
      "country": "US",
      "brand": "eSIM",
      "brandName": "eSIM",
      "productType": "ESIM",
      "subTypes": [
        "Standard"
      ],
      "notes": "eSIM Hawaii (USA) No Roaming",
      "shortNotes": "eSIM 30 Days,  5 GB",
      "priceType": "FIXED",
      "price": {
        "currency": "USD",
        "currencyDivisor": 100,
        "fixed": 925,
        "suggestedFixed": 925,
        "margin": 0.26162162,
        "fee": 100
      },
      "cost": {
        "currency": "USD",
        "currencyDivisor": 100,
        "fixed": 683,
        "fee": 0,
        "feePct": 0,
        "discount": 0.26162162
      },
      "durationDays": 30,
      "dataGB": 5,
      "dataUnlimited": false,
      "smsNumber": 0,
      "smsUnlimited": false,
      "voiceMinutes": 0,
      "voiceUnlimited": false,
      "dataSpeeds": [],
      "roaming": [],
      "createdAt": "2025-02-17T05:51:56.256Z",
      "updatedAt": "2026-02-16T00:00:00Z"
    }

On an eSIM, it’s important to note the dataGB, dataUnlimited, dataSpeeds and roaming sections. For more information on eSIM offers, see the eSIM Guide.

Catalog Example Code

All sample code for the catalog is written in TypeScript for Node.js with Express using the Zendit Node.js SDK. Template engine used in the example using Pug templates (sample template not included.)

import express, { Request, Response } from "express";
import { ZenditApi } from "@zenditplatform/zendit-sdk";
import { DtoESimOffersResponse } from "@zenditplatform/zendit-sdk";
import dotenv from 'dotenv';

// Load config from .env file
dotenv.config();
// Create instance of ZenditApi using the ZENDIT_API_KEY set in the .env file
const zendit = new ZenditApi(process.env.ZENDIT_API_KEY);

export const esimCatalog = express.Router();

// Get the catalog using the header acceptance to return either a page with a PUG template
// or the JSON from the catalog
esimCatalog.get("/catalog/esims", (req: Request, res: Response): void => {
    if (req.headers.accept == 'application/json') {
        // Render the JSON for the catalog
        sendJSON(req, res);
    } else {
        // Render the page for the catalog
        sendPage(req, res);
    }
})

// Sends the page version of the catalog using request filters and renders it with PUG templates
function sendPage(req: Request, res: Response) {
    // Catalog filters passed from the query sttring 
    
    // Set the _limit to the passed value or default to 10 items
    const _limit = req.query._limit == null ? 10 : Number(req.query._limit);
    // Set the _offset to the passed value or default to 0
    const _offset = req.query._offset == null ? 0 : Number(req.query._offset);
    // Set the brand to the passed value or default to an empty string (no filter)
    const brand = req.query.brand == null ? "" : String(req.query.brand);
    // Set the destination country to the passed value or default to an empty string (no filter)
    const country = req.query.country == null ? "" : String(req.query.country);
    // Set the subType to the passed value or default to an empty string (no filter)
    const subType = req.query.subType == null ? "" : String(req.query.subType);
    //Set the region to the passed value or default to an empty string (no filter)
    const region = req.query.regions == null ? "" : String(req.query.regions);

    // Get the list of eSIM offers matching the filters and then render it as JSON 
    zendit.esimOffersGet(_limit, _offset, brand, country, region, subType)
     .then(function (catalog) {
        // Render the catalog with a template
        res.render("catalog/esim", {catalog: catalog});
        
    })
    .catch(error => res.send("Error getting catalog from Zendit."));
}

// Sends the JSON version of the catalog using request flters and renders it in JSON
function sendJSON(req: Request, res: Response) {
    // Catalog filters passed from the query sttring 
    
    // Set the _limit to the passed value or default to 10 items
    const _limit = req.query._limit == null ? 10 : Number(req.query._limit);
    // Set the _offset to the passed value or default to 0
    const _offset = req.query._offset == null ? 0 : Number(req.query._offset);
    // Set the brand to the passed value or default to an empty string (no filter)
    const brand = req.query.brand == null ? "" : String(req.query.brand);
    // Set the destination country to the passed value or default to an empty string (no filter)
    const country = req.query.country == null ? "" : String(req.query.country);
    // Set the subType to the passed value or default to an empty string (no filter)
    const subType = req.query.subType == null ? "" : String(req.query.subType);
    //Set the region to the passed value or default to an empty string (no filter)
    const region = req.query.regions == null ? "" : String(req.query.regions);
   
   // Get the list of eSIM offers matching the filters and then render it as JSON
   zendit.esimOffersGet(_limit, _offset, brand, country, region, subType)
   .then(function (catalog) {
      res.json(catalog);
   })
   .catch(error => res.send("Error getting catalog from Zendit."));
   
}