Skip to content

Catalog API

Returns the complete product catalog with field configurations and fulfillment mapping. Designed for device caching — fetch once, render dynamically.

Migrating from /v2/product-list?

See the Migration Guide for endpoint mapping and a checklist.

Endpoint

http
GET https://api.iimmpact.com/v2/catalog

Headers

HeaderDescriptionRequired
X-Api-KeyYour API keyYes
X-TimestampUnix timestamp in secondsYes
X-NonceUnique request identifierYes
X-SignatureHMAC-SHA256 signature (v1=...)Yes

See API Key Authentication for signing details.

Query Parameters

ParameterTypeRequiredDescription
product_codestringNoReturn only one product
is_activebooleanNoFilter by active status (default: true)
include_inactivebooleanNoInclude inactive products (default: false). Use when you need to retrieve all products regardless of active status

Example Request

bash
curl -X GET "https://api.iimmpact.com/v2/catalog" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Timestamp: 1704067200" \
  -H "X-Nonce: req-1704067200-a1b2c3d4e5f6" \
  -H "X-Signature: v1=BASE64_HMAC_SIGNATURE"

Response

json
{
  "last_updated": "2025-01-07T00:00:00Z",
  "tree": { "groups": [...] },
  "products": { "D": {...}, "M": {...} }
}
FieldTypeDescription
last_updatedstringISO 8601 timestamp of last catalog update
treeobjectHierarchical structure for UI navigation
productsobjectFlat map of products keyed by product_code

Cache Strategy

Use the last_updated field for cache freshness checks. This endpoint does not guarantee ETag or Last-Modified headers.

Tree

Navigation hierarchy: group → category → product codes.

json
{
  "groups": [
    {
      "id": "grp_mobile",
      "name": "Mobile",
      "icon_url": "https://cdn.iimmpact.com/icons/mobile.png",
      "categories": [
        {
          "id": "cat_prepaid",
          "name": "Prepaid Reload",
          "product_codes": ["D", "M", "C", "U"]
        }
      ]
    }
  ]
}

The tree controls UI ordering; products is a flat map for O(1) lookup.

Product

Each entry in the products map:

json
{
  "D": {
    "code": "D",
    "name": "Digi Prepaid",
    "note": "Prepaid reload for Digi mobile numbers",
    "image_url": "https://dashboard.iimmpact.com/img/D.png",
    "processing_time": "instant",
    "is_active": true,
    "denomination": "5,10,30,50,100",
    "denomination_currency": "MYR",
    "denomination_unit_price": 1.0,
    "fields": [...],
    "fulfillment": {...},
    "pricing": {...}
  }
}
FieldTypeDescription
codestringUnique product identifier
namestringDisplay name
notestring | nullOptional description
image_urlstringProduct logo URL
processing_timestringinstant, 24_hours, 3_days, link, or pin
is_activebooleanEffective status after reseller overlay
denominationstring | nullRaw denomination string from backend
denomination_currencystring | nullCurrency or unit code for the denomination (for example MYR, BDT, Diamonds)
denomination_unit_pricenumberMYR price per denomination unit. Standard MYR products return 1, while foreign-currency products can return values like 0.059 for BDT
fieldsarrayForm field definitions
fulfillmentobjectMapping to payment request
pricingobjectWholesale cost and adjustments
min_amountobject | nullCustom minimum amount override for pricing fields
max_amountobject | nullCustom maximum amount override for pricing fields

Display processing_time to users before checkout: instant = seconds, 24_hours = 1 business day, 3_days = 3 business days, link = fulfilled via a redemption link, pin = fulfilled as a PIN/voucher code.

For international topup and other non-MYR denomination products, multiply the displayed denomination by denomination_unit_price to derive the MYR face value before any reseller price adjustment.

Fields

Each field in the fields array defines a form input:

json
{
  "id": "phone",
  "type": "text",
  "input_mode": "tel",
  "label": "Phone Number",
  "placeholder": "e.g. 0123456789",
  "required": true,
  "order": 1,
  "role": "account",
  "validation": {
    "pattern": "^01[0-9]{8,9}$",
    "message": "Enter valid Malaysian phone number"
  }
}
PropertyTypeDescription
idstringUnique identifier within product
typestringtext, number, select, or money
input_modestringKeyboard hint: text, tel, numeric, email, decimal
labelstringDisplay label
placeholderstringInput placeholder text
requiredbooleanWhether field is required
ordernumberDisplay order (ascending)
rolestringaccount, pricing, or none
validationobjectpattern (regex), message (error text), min/max (for money/number)
data_sourceobjectSelect field options source
currencystringFor money fields only (default: MYR)

Field Types

TypeUse CaseExample Fields
textPhone, NRIC, account numbersinput_mode: "tel" for phones, "numeric" for NRICs
numberPlayer IDs, quantitiesNumeric keyboard
selectPlans, packages, billersOptions from /v2/options
moneyPayment amountsvalidation.min/max for range, input_mode: "decimal"

Select Fields

Select fields declare how to fetch their options via data_source:

json
{
  "data_source": {
    "type": "dynamic",
    "depends_on": ["phone"],
    "endpoint": "/options",
    "params": {
      "product_code": { "static": "HI" },
      "field_id": { "static": "plan" },
      "account_number": { "from_field": "phone" }
    }
  }
}
PropertyDescription
typereference = static list, cache locally. dynamic = user-specific, fetch per request
depends_onField IDs that must be filled before fetching (dynamic only)
endpointAlways /options — call via Options API
paramsQuery params: { "static": "value" } for constants, { "from_field": "id" } for user input

See Product Examples for complete select field flows.

Fulfillment

Maps form fields to the POST /v2/topup payment request. The product field is always the product's code. You provide your own refid and optional remarks.

json
{
  "fulfillment": {
    "account": { "from_field": "phone" },
    "amount": { "from_field": "plan", "path": "price.amount" },
    "extras": {
      "subproduct_code": { "from_field": "plan", "path": "code" },
      "ref2": { "from_field": "ref2", "omit_if_empty": true }
    }
  }
}
PropertyTypeDescription
from_fieldstringField ID to get value from
pathstringDot-path into the selected option object (e.g. price.amount)
omit_if_emptybooleanExclude from request if value is empty

Store the Full Option Object

For select fields, store the entire selected item from /v2/options — not just the code. The fulfillment path property accesses nested values like price.amount from this object.

The amount in the payment request is the transaction amount (from price.amount in options, or direct money input). See Product Examples for end-to-end flows.

Pricing

B2B Data

Pricing is for your backend only. Do not expose unit_price, discount, or price_adjustment to end users.

json
{
  "pricing": {
    "unit_price": "0.9710",
    "currency": "MYR",
    "discount": {
      "type": "percentage",
      "value": "2.9%"
    },
    "price_adjustment": null,
    "has_loss_risk": false
  }
}
FieldTypeDescription
unit_pricestringComputed unit price as a decimal string (e.g. "0.9710")
currencystringCurrency or unit code. Fiat currencies (e.g. MYR, IDR, BDT) for standard products, or game/virtual currencies (e.g. UC, Diamonds) for game top-up products
discountobjectWholesale discount applied to this product
price_adjustmentobject | nullOptional reseller price adjustment
has_loss_riskbooleantrue when adjustment can produce a loss at some denomination

Discount

The discount object describes the wholesale discount for the product:

FieldTypeDescription
typestringpercentage or fixed
valuestringHuman-readable discount value (e.g. "2.9%", "0%", "30 cent")

Percentage discountunit_price is the cost multiplier per RM 1 face value:

ExampleMeaningCost for RM 100
unit_price: "0.9710", value: "2.9%"2.9% discount off face value100 × 0.9710 = RM 97.10
unit_price: "1.0000", value: "0%"No discount100 × 1.0000 = RM 100.00

Fixed discountunit_price is a negative fixed amount deducted per transaction:

ExampleMeaningCost for RM 100
unit_price: "-0.3000", value: "30 cent"RM 0.30 fixed discount per transaction100 - 0.30 = RM 99.70
unit_price: "-0.6000", value: "60 cent"RM 0.60 fixed discount per transaction100 - 0.60 = RM 99.40

Price Adjustment

Optional. If null, no adjustment is applied.

TypeCalculationExample (RM 100)
fixeduser_pays = price + value100 + 0.50 = RM 100.50
percentageuser_pays = price × value100 × 1.03 = RM 103.00

See the Pricing Guide for margin strategies and the Product Examples for worked calculations.

Error Responses

400 — Validation Error

json
{
  "message": "The given data was invalid.",
  "errors": {
    "is_active": ["The value 'yes' is not valid."]
  }
}

401 — Authentication Failed

json
{
  "message": "Unauthorized",
  "metadata": { "status_code": "401" }
}

See API Key Authentication for the complete list of 401 causes.

Product Code No Match

Returns 200 OK with an empty products map (tree structure is preserved):

json
{
  "last_updated": "2025-01-07T00:00:00Z",
  "tree": { "groups": [...] },
  "products": {}
}

IIMMPACT API Documentation