Skip to content

Dynamic Product Catalog

Preview

This API is currently in preview. The schema and endpoints may change before general availability.

Overview

The Dynamic Product Catalog introduces a backend-driven product configuration model. Instead of hardcoding product flows in your application, products are defined as purchase forms where fields, validation, options, and checkout mapping are fully configurable from the backend.

Tenant-Specific Catalog

The catalog returned by /v2/catalog is unique to each tenant. Through the IIMMPACT Dashboard, you can:

  • View your costs — See wholesale pricing for each product
  • Set your markup — Configure fixed or percentage markup per product
  • Customize your catalog — Create custom groups, categories, and product ordering
  • Enable/disable products — Choose which products to offer your users

This means the API returns your personalized catalog with your pricing and structure.

Prerequisites

Before using the Catalog API, ensure you have:

  1. API Credentials - IdToken (Bearer) from User Authentication
  2. Base URL - https://api.iimmpact.com for production
  3. Webhook endpoint (optional) - HTTPS endpoint for real-time catalog sync

Environments

EnvironmentBase URLPurpose
Productionhttps://api.iimmpact.comLive transactions
Sandboxhttps://sandbox-api.iimmpact.comTesting with simulated data

Sandbox Testing

Use the sandbox environment to test your integration without processing real transactions. The sandbox returns realistic responses with test data.

Rate Limits

EndpointLimitBurst
GET /v2/catalog60 requests/min10
GET /v2/options120 requests/min20
POST /v2/webhooks10 requests/min2

When rate limited, the API returns 429 Too Many Requests with a Retry-After header.

Key Benefits

BenefitDescription
No App UpdatesAdd or modify products without client releases
Unified Field ModelInputs, amounts, and selections are all "fields" with consistent handling
Explicit FulfillmentClear declaration of how fields map to payment requests
Multi-Tenant ReadySame schema serves multiple apps with customizable catalogs

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         Your Application                            │
├─────────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────────┐   │
│  │ Catalog      │  │ Options      │  │ Dynamic Form Builder     │   │
│  │ Cache        │  │ Fetcher      │  │ (renders fields)         │   │
│  └──────┬───────┘  └──────┬───────┘  └──────────────┬───────────┘   │
│         │                 │                          │              │
│         └─────────────────┴──────────────────────────┘              │
│                              │                                      │
└──────────────────────────────┼──────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────┐
│                         IIMMPACT API                                │
├─────────────────────────────────────────────────────────────────────┤
│  GET /v2/catalog              │  GET /v2/options                    │
│  - Returns full product       │  - Returns items for select fields  │
│    catalog with fields        │  - Supports reference & dynamic     │
│  - Cached on device           │  - Paginated for large lists        │
└─────────────────────────────────────────────────────────────────────┘

Endpoints

EndpointPurpose
GET /v2/catalogReturns the complete product catalog with hierarchical structure and field configurations
GET /v2/optionsReturns selectable items for select fields (billers, plans, amounts)
POST /v2/webhooksRegister webhook for catalog/options sync notifications

Core Concepts

Everything is a Field

The key insight: inputs, amount selection, and option selection are all fields with consistent structure.

json
{
  "id": "phone",
  "type": "text",
  "input_mode": "tel",
  "label": "Phone Number",
  "placeholder": "e.g. 0123456789",
  "required": true,
  "role": "account",
  "validation": {
    "pattern": "^01[0-9]{8,9}$",
    "message": "Enter valid Malaysian phone number"
  }
}

Field Types

TypeDescriptionCommon input_modeExample
textFree-form text inputtext, tel, numericPhone, NRIC, reference numbers
numberNumeric inputnumericPlayer ID, quantities
selectSelection from listPlans, billers, denominations
moneyCurrency amount with decimalsdecimalFlexible payment amounts

Field Roles

Fields have roles that determine how they map to the payment request:

RolePurposeMaps To
accountIdentifies the recipienttopup.account
pricingDetermines payment amounttopup.amount
noneAdditional datatopup.extras.*

Data Sources

Select fields can have different data sources:

TypeWhen to UseCaching
referenceStatic lists (amounts, billers, game packages)Cache locally
dynamicUser-specific (plans, accounts)Fetch after dependencies filled

Pricing Structure

Each product includes pricing information with two components:

  1. Cost — Your wholesale cost (what IIMMPACT charges you)
  2. Markup — Your configured markup (what you charge on top)
json
{
  "pricing": {
    "cost": {
      "model": "percentage_discount",
      "percentage_rate": 2.0
    },
    "markup": {
      "model": "fixed",
      "fixed_amount": { "amount": "0.50", "currency": "MYR" }
    }
  }
}

Cost Models

ModelExampleCalculation
percentage_discountCB (2% off)cost = face_value × (1 - rate/100)
fixed_discountTNB (RM 0.50 off)cost = face_value - fixed_amount
fixed_per_itemGamescost = item.cost (varies per denomination)

Markup Models (Dashboard Configurable)

ModelExampleCalculation
noneNo markupuser_pays = face_value
fixed+RM 0.50user_pays = face_value + fixed_amount
percentage+1%user_pays = face_value × (1 + rate/100)

Pricing Example

TNB electricity bill payment for RM 100:

Face Value:           RM 100.00
Your Cost:            RM  99.50  (fixed_discount: -RM 0.50)
Your Markup:          RM   0.50  (fixed: +RM 0.50)
────────────────────────────────
User Pays:            RM 100.50
Your Margin:          RM   1.00  (markup + cost savings)

B2B Data

Cost and markup information is for your backend only. Do not expose wholesale pricing to end users.

Fulfillment Mapping

Each product declares how its fields map to the payment request:

json
{
  "fulfillment": {
    "account": { "from_field": "phone" },
    "amount": { "from_field": "plan", "path": "price.amount" },
    "extras": {
      "subproduct_code": { "from_field": "plan", "path": "code" }
    }
  }
}

Quick Start

1. Fetch the Catalog

bash
curl -X GET "https://api.iimmpact.com/v2/catalog" \
  -H "Authorization: Bearer {idToken}"

2. Render Dynamic Form

For each product, iterate through fields and render appropriate inputs based on type.

3. Fetch Options for Select Fields

When a user interacts with a select field:

bash
curl -X GET "https://api.iimmpact.com/v2/options?product_code=HI&field_id=plan&account_number=0123456789" \
  -H "Authorization: Bearer {idToken}"

4. Build Payment Request

Use the product's fulfillment mapping to populate product, account, amount, and extras, then add your own refid for idempotency (see Make Payment).

What's Next

What Backend Can Change (No App Update)

  • Add/remove/reorder groups and categories
  • Add new products using existing field types
  • Modify field labels, placeholders, validation
  • Change denomination options (fixed amounts, min/max)
  • Update biller lists, payment codes
  • Enable/disable products

What Requires App Update

  • New field types (e.g., image_upload, signature)
  • Breaking schema changes
  • New product_type values

Webhooks

Register a webhook to receive real-time notifications when the catalog or options change. Webhooks send the full payload — your backend simply replaces the existing data.

Events

EventTriggerPayload
catalog.syncAny product/pricing changeFull catalog (same as GET /v2/catalog)
options.syncOptions changed for a productFull options for product+field

Registration

bash
POST /v2/webhooks
{
  "url": "https://your-api.com/iimmpact/webhook",
  "secret": "whsec_your_secret_key"
}

Handling Webhooks

javascript
app.post("/iimmpact/webhook", async (req, res) => {
  // Verify signature
  const signature = req.headers["x-iimmpact-signature"];
  if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }

  const { event, data } = req.body;

  switch (event) {
    case "catalog.sync":
      // Full replace
      await db.catalog.replaceOne({ _id: "catalog" }, data, { upsert: true });
      break;

    case "options.sync":
      // Replace options for this product+field
      await db.options.replaceOne(
        { product_code: data.product_code, field_id: data.field_id },
        data,
        { upsert: true },
      );
      break;
  }

  res.status(200).send("OK");
});

Retry Policy

Failed webhooks (non-2xx response) are retried 3 times with exponential backoff (1min, 5min, 30min).

Dashboard Configuration

The IIMMPACT Dashboard allows you to customize your catalog before it's served via the API.

Pricing & Markup

SettingDescription
View CostSee your wholesale cost for each product
Set MarkupConfigure fixed amount or percentage markup
Per-ProductDifferent markup rules for different products

Catalog Organization

SettingDescription
Custom GroupsCreate your own top-level groups (e.g., "Popular", "Promos")
Custom CategoriesOrganize products into categories within groups
Product OrderingDrag-and-drop to reorder products within categories
Enable/DisableToggle products on or off for your catalog

Product Visibility

SettingDescription
Active ProductsOnly enabled products appear in your catalog
Hidden ProductsDisabled products are excluded from API response
New ProductsNewly added products are disabled by default

Instant Updates

Changes made in the dashboard are reflected immediately in your /v2/catalog response. If you've registered a webhook, you'll also receive a catalog.sync event.

Need Help?

ResourceLink
Technical Supportsupport@iimmpact.com
API Statushttps://status.iimmpact.com
Dashboardhttps://dashboard.iimmpact.com

IIMMPACT API Documentation