Appearance
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:
- API Credentials - IdToken (Bearer) from User 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 |
| Sandbox | https://sandbox-api.iimmpact.com | Testing 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
| Endpoint | Limit | Burst |
|---|---|---|
GET /v2/catalog | 60 requests/min | 10 |
GET /v2/options | 120 requests/min | 20 |
POST /v2/webhooks | 10 requests/min | 2 |
When rate limited, the API returns 429 Too Many Requests with a Retry-After header.
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) |
POST /v2/webhooks | Register 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
| 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 |
Field Roles
Fields have roles that determine how they map to the payment request:
| Role | Purpose | Maps To |
|---|---|---|
account | Identifies the recipient | topup.account |
pricing | Determines payment amount | topup.amount |
none | Additional data | topup.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 two components:
- Cost — Your wholesale cost (what IIMMPACT charges you)
- 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
| Model | Example | Calculation |
|---|---|---|
percentage_discount | CB (2% off) | cost = face_value × (1 - rate/100) |
fixed_discount | TNB (RM 0.50 off) | cost = face_value - fixed_amount |
fixed_per_item | Games | cost = item.cost (varies per denomination) |
Markup Models (Dashboard Configurable)
| Model | Example | Calculation |
|---|---|---|
none | No markup | user_pays = face_value |
fixed | +RM 0.50 | user_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
- Catalog API Reference - Full catalog endpoint documentation
- Options API Reference - Options endpoint for select fields
- 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
- New
product_typevalues
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
| Event | Trigger | Payload |
|---|---|---|
catalog.sync | Any product/pricing change | Full catalog (same as GET /v2/catalog) |
options.sync | Options changed for a product | Full 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
| Setting | Description |
|---|---|
| View Cost | See your wholesale cost for each product |
| Set Markup | Configure fixed amount or percentage markup |
| Per-Product | Different markup rules for different products |
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 | Only enabled products appear in your catalog |
| Hidden Products | Disabled products are excluded from API response |
| New Products | Newly 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?
| Resource | Link |
|---|---|
| Technical Support | support@iimmpact.com |
| API Status | https://status.iimmpact.com |
| Dashboard | https://dashboard.iimmpact.com |
