Appearance
Dynamic Product Catalog
Preview
This API is active and recommended for new integrations. The schema may evolve 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 price adjustments — Configure fixed or percentage adjustments 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:
- API Credentials - API Key + HMAC-SHA256 signing from API Key Authentication
- Base URL -
https://api.iimmpact.comfor production - Webhook endpoint (optional) - HTTPS endpoint for real-time catalog sync
Environments
| Environment | Base URL | Purpose |
|---|---|---|
| Production | https://api.iimmpact.com | Live transactions |
| Staging | https://staging.iimmpact.com | Testing with simulated data |
Staging Environment
Use the staging environment to test your integration without processing real transactions. Staging returns realistic responses with test data.
Key Benefits
| Benefit | Description |
|---|---|
| No App Updates | Add or modify products without client releases |
| Unified Field Model | Inputs, amounts, and selections are all "fields" with consistent handling |
| Explicit Fulfillment | Clear declaration of how fields map to payment requests |
| Multi-Tenant Ready | Same 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
| Endpoint | Purpose |
|---|---|
GET /v2/catalog | Returns the complete product catalog with hierarchical structure and field configurations |
GET /v2/options | Returns selectable items for select fields (billers, plans, amounts) |
GET /v2/reseller/catalog/webhook | Get current webhook configuration (URL, enabled status, secret presence) |
POST /v2/reseller/catalog/webhook | Register webhook URL and generate secret |
PUT /v2/reseller/catalog/webhook | Enable or disable webhook delivery |
DELETE /v2/reseller/catalog/webhook | Remove webhook configuration and disable delivery |
POST /v2/reseller/catalog/webhook/rotate | Rotate webhook secret |
Core Concepts
Everything is a Field
The key insight: inputs, amount selection, and option selection are all fields with consistent structure.
However, where the pricing data comes from depends on the field type:
selectfields require fetching options from/v2/options(fixed amounts, plans, packages)moneyfields have min/max validation directly in the catalog response (flexible amounts)
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
| Type | Description | Common input_mode | Example |
|---|---|---|---|
text | Free-form text input | text, tel, numeric | Phone, NRIC, reference numbers |
number | Numeric input | numeric | Player ID, quantities |
select | Selection from list | — | Plans, billers, denominations |
money | Currency amount with decimals | decimal | Flexible payment amounts |
Where Pricing Data Lives
A common question: "Do I need to call the Options API for this product?"
| Pricing Model | Field Type | Where Data Lives | Example Products |
|---|---|---|---|
| Fixed amounts | select | Options API (/v2/options) | Digi Prepaid (RM 5, 10, 30) |
| Flexible range | money | Catalog (validation.min/max) | TNB, JomPAY (RM 1 - RM 30,000) |
| Dynamic plans | select | Options API (with account_number) | Hotlink Internet, PTPTN |
Decision rule: If the pricing field is type: "select", call /v2/options. If it's type: "money", use validation.min/max from the catalog directly.
Field Roles
Fields have roles that determine how they map to the payment request:
| Role | Purpose | Maps To |
|---|---|---|
account | Identifies the recipient | account |
pricing | Determines payment amount | amount |
none | Additional data | extras.* |
Data Sources
Select fields can have different data sources:
| Type | When to Use | Caching |
|---|---|---|
reference | Static lists (amounts, billers, game packages) | Cache locally |
dynamic | User-specific (plans, accounts) | Fetch after dependencies filled |
Pricing Structure
Each product includes pricing information with three fields:
- Cost — Your wholesale cost (what IIMMPACT charges you)
- Price Adjustment — Reseller-specific fixed/percentage adjustment
- Loss Risk Flag — Indicates if current adjustment can produce negative margin
json
{
"pricing": {
"cost": {
"model": "percentage_discount",
"percentage_rate": 0.98
},
"price_adjustment": {
"type": "fixed",
"value": 0.50,
"currency": "MYR"
},
"has_loss_risk": false
}
}Cost Models
| Model | Example | Calculation |
|---|---|---|
percentage_discount | CB (2% off) | cost = price × rate (e.g. 0.98) |
fixed_discount | TNB (RM 0.50 off) | cost = price - abs(fixed_amount) |
Price Adjustment Models (Dashboard Configurable)
| Type | Example | Calculation |
|---|---|---|
fixed | +0.50 | user_pays = price + value |
percentage | 0.98 | user_pays = price × value |
Pricing Example
TNB electricity bill payment for RM 100 with cost.fixed_amount=-0.50 and price_adjustment.fixed=+0.50:
Price: RM 100.00
Your Cost: RM 99.50 (fixed_discount: -RM 0.50)
Price Adjustment: RM 0.50 (fixed: +RM 0.50)
────────────────────────────────
User Pays: RM 100.50
Your Margin: RM 1.00B2B Data
Cost and price_adjustment 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 "X-Api-Key: YOUR_API_KEY" \
-H "X-Timestamp: 1704067200" \
-H "X-Nonce: req-1704067200-a1b2c3d4e5f6" \
-H "X-Signature: v1=BASE64_HMAC_SIGNATURE"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 "X-Api-Key: YOUR_API_KEY" \
-H "X-Timestamp: 1704067200" \
-H "X-Nonce: req-1704067200-a1b2c3d4e5f6" \
-H "X-Signature: v1=BASE64_HMAC_SIGNATURE"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).
Complete Flow Examples
Fixed Denominations (e.g., Digi Prepaid)
Products with predefined amounts use select fields that require the Options API:
1. GET /v2/catalog
→ Product "D" has a `select` field with role "pricing"
2. GET /v2/options?product_code=D&field_id=amount
→ Returns [RM 5, RM 10, RM 30, RM 50, RM 100]
3. User selects RM 30
4. POST /v2/topup
→ { product: "D", account: "0123456789", amount: "30.00" }Flexible Amounts (e.g., TNB, JomPAY)
Products with amount ranges use money fields with validation in the catalog:
1. GET /v2/catalog
→ Product "TNB" has a `money` field with validation: { min: 10, max: 60000 }
2. No Options API call needed for the amount field
3. User enters RM 150.00 (validated against min/max)
4. POST /v2/topup
→ { product: "TNB", account: "123456789012", amount: "150.00" }Dynamic Plans (e.g., Hotlink Internet)
Products with user-specific options use select fields with dependencies:
1. GET /v2/catalog
→ Product "HI" has a `select` field with data_source.depends_on: ["phone"]
2. User enters phone number: 0178855286
3. GET /v2/options?product_code=HI&field_id=plan&account_number=0178855286
→ Returns plans available for this specific number
4. User selects "Unlimited Weekly Pass RM12"
5. POST /v2/topup
→ { product: "HI", account: "0178855286", amount: "12.00", extras: { subproduct_code: "..." } }What's Next
- Catalog API Reference - Full catalog endpoint documentation
- Options API Reference - Options endpoint for select fields
- Catalog Webhooks - Real-time catalog change notifications
- Migration Guide - Migrating from product-list to catalog
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
Webhooks
Register a webhook to receive real-time push notifications when the catalog changes — products, options, categories, and groups. Each HTTP request contains one event (product.updated, option.created, etc.) signed with HMAC-SHA256.
| Feature | Detail |
|---|---|
| Events | 12 event types across products, options, categories, groups |
| Delivery | One event per POST request to your HTTPS endpoint |
| Security | HMAC-SHA256 signature in X-Webhook-Signature header |
| Retries | Up to 5 attempts with exponential backoff |
See the Catalog Webhooks page for the full event table, payload format, signature verification code, retry policy, and endpoint reference.
Dashboard Configuration
The IIMMPACT Dashboard allows you to customize your catalog before it's served via the API.
Pricing Configuration
| Setting | Description |
|---|---|
| View Cost | See your wholesale cost for each product |
| Price Adjustment | Configure fixed or percentage price_adjustment values |
| Per-Product | Set different adjustment rules by product |
Catalog Organization
| Setting | Description |
|---|---|
| Custom Groups | Create your own top-level groups (e.g., "Popular", "Promos") |
| Custom Categories | Organize products into categories within groups |
| Product Ordering | Drag-and-drop to reorder products within categories |
| Enable/Disable | Toggle products on or off for your catalog |
Product Visibility
| Setting | Description |
|---|---|
| Active Products | Use is_active=true to return enabled only |
| Hidden Products | Hidden products are excluded unless include_hidden=true |
| New Products | Newly added products are disabled by default |
Instant Updates
Changes made in the dashboard are reflected in your /v2/catalog response. If you've registered a webhook, you'll receive per-resource events (for example product.updated).
Need Help?
| Resource | Link |
|---|---|
| Technical Support | support@iimmpact.com |
| API Status | https://status.iimmpact.com |
| Dashboard | https://dashboard.iimmpact.com |
