Appearance
Bill Presentment SDK Quickstart
This guide gets you from zero to a working bill selection flow as fast as possible.
Prerequisites
- B2B API credentials — Existing
X-Api-Key+ HMAC secret (same credentials used for other B2B API key endpoints) - A backend server — Session creation is server-to-server only (secrets must never be in client code)
- A frontend app — Web (any framework) or React Native
DANGER
Never put API keys or HMAC secrets in frontend bundles, mobile apps, or source control.
Step 1: Create a Session (Backend)
When a user wants to view bills, your backend creates a session with POST /v2/sdk/sessions using API Key + HMAC headers.
bash
API_KEY="your_api_key"
HMAC_SECRET_BASE64="your_hmac_secret_base64"
TIMESTAMP=$(date +%s)
NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]')
BODY='{"ic_number":"901234567890"}'
BODY_HASH=$(printf "%s" "$BODY" | openssl dgst -sha256 -binary | base64)
CANONICAL="v1:${TIMESTAMP}:${NONCE}:POST::${BODY_HASH}"
SIGNATURE=$(printf "%s" "$CANONICAL" | openssl dgst -sha256 -mac HMAC \
-macopt "hexkey:$(printf "%s" "$HMAC_SECRET_BASE64" | base64 -d | xxd -p -c 256)" \
-binary | base64)
curl -X POST https://api.iimmpact.com/v2/sdk/sessions \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${API_KEY}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "X-Nonce: ${NONCE}" \
-H "X-Signature: v1=${SIGNATURE}" \
-d "$BODY"Response:
json
{
"session_token": "bp_sess_7nF1oQ4n6vR2xZ9a",
"expires_at": "2026-03-11T10:15:00Z"
}Pass session_token to your frontend. See POST /v2/sdk/sessions for full request/response details.
INFO
session_token is the only SDK token. There is no bootstrap-token exchange step.
Step 2: Install the SDK (Frontend)
bash
npm install @iimmpact-sdn-bhd/billpresentment-sdkbash
npm install @iimmpact-sdn-bhd/billpresentment-sdk-react-native react-native-webviewStep 3: Open the SDK
Use the session_token returned by your backend.
typescript
import { BillPresentmentSDK } from "@iimmpact-sdn-bhd/billpresentment-sdk";
const sdk = new BillPresentmentSDK({
sessionToken: sessionTokenFromBackend,
displayMode: "modal", // "modal" | "fullscreen" | "inline"
});
const result = await sdk.open();tsx
import { BillPresentment } from "@iimmpact-sdn-bhd/billpresentment-sdk-react-native";
<BillPresentment
sessionToken={sessionTokenFromBackend}
visible={showBills}
displayMode="fullscreen"
onResult={(result) => handleResult(result)}
onClose={() => setShowBills(false)}
/>Internally, the SDK opens bills.iimmpact.com/#token=..., the hosted app reads and clears the fragment, then uses Authorization: Bearer {session_token} for API calls.
Step 4: Handle the Result
When the user confirms bill selection, the SDK returns a structured result object:
typescript
if (result.status === "success") {
console.log(result.user); // { fullName, icNumber }
console.log(result.selectedBills); // Array of { billerCode, billerName, ref1, ref2, amount }
console.log(result.totalAmount); // Sum of selected bill amounts
navigateToPayment({
user: result.user,
bills: result.selectedBills,
total: result.totalAmount,
});
}
if (result.status === "cancelled") {
// The SDK resolves with: { status: "cancelled" }
}
if (result.status === "error") {
console.error("SDK error:", result.error);
}Result structure:
typescript
interface User {
fullName: string;
icNumber: string;
}
interface SelectedBill {
billerCode: string;
billerName: string;
ref1: string;
ref2: string;
amount: number;
}
type BillSelectionResult =
| { status: "success"; user: User; selectedBills: SelectedBill[]; totalAmount: number }
| { status: "cancelled" }
| { status: "error"; error: string };Example result:
json
{
"user": { "fullName": "AHMAD BIN ALI", "icNumber": "901234567890" },
"status": "success",
"totalAmount": 156.80,
"selectedBills": [
{
"billerCode": "5454",
"billerName": "Tenaga Nasional Berhad",
"ref1": "220108271001",
"ref2": "IIMMPACT",
"amount": 143.50
},
{
"billerCode": "8888",
"billerName": "Telekom Malaysia",
"ref1": "TM12345678",
"ref2": "IIMMPACT",
"amount": 13.30
}
]
}Complete Example (Web)
typescript
import { BillPresentmentSDK } from "@iimmpact-sdn-bhd/billpresentment-sdk";
async function showBills(sessionToken: string) {
const sdk = new BillPresentmentSDK({
sessionToken,
displayMode: "modal",
});
const result = await sdk.open();
if (result.status === "success") {
sessionStorage.setItem("user", JSON.stringify(result.user));
sessionStorage.setItem("selectedBills", JSON.stringify(result.selectedBills));
sessionStorage.setItem("totalAmount", String(result.totalAmount));
window.location.href = "/pay";
return;
}
if (result.status === "cancelled") {
return;
}
console.error("Failed to collect bill selection:", result.error);
}
showBills(sessionTokenFromBackend);Backend Example (Node.js)
typescript
import { createHash, createHmac, randomUUID } from "node:crypto";
const API_BASE_URL = "https://api.iimmpact.com";
type CreateSessionInput = {
ic_number: string;
};
function sha256Base64(value: string): string {
return createHash("sha256").update(value).digest("base64");
}
export async function createSdkSession(input: CreateSessionInput) {
const apiKey = process.env.IIMMPACT_API_KEY;
const hmacSecretBase64 = process.env.IIMMPACT_HMAC_SECRET_BASE64;
if (!apiKey || !hmacSecretBase64) {
throw new Error("Missing IIMMPACT API credentials");
}
const method = "POST";
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = randomUUID().toLowerCase();
const query = "";
const body = JSON.stringify(input);
const bodyHash = sha256Base64(body);
const canonical = `v1:${timestamp}:${nonce}:${method}:${query}:${bodyHash}`;
const hmacKey = Buffer.from(hmacSecretBase64, "base64");
const signature = createHmac("sha256", hmacKey).update(canonical).digest("base64");
const response = await fetch(`${API_BASE_URL}/v2/sdk/sessions`, {
method,
headers: {
"Content-Type": "application/json",
"X-Api-Key": apiKey,
"X-Timestamp": timestamp,
"X-Nonce": nonce,
"X-Signature": `v1=${signature}`,
},
body,
});
if (!response.ok) {
throw new Error(`Session creation failed (${response.status})`);
}
return (await response.json()) as {
session_token: string;
expires_at: string;
};
}Next Steps
- Authentication — Full auth flow, token lifecycle, and bill set validation
- Web SDK — Full configuration options and display modes
- React Native SDK — Component props and platform-specific handling
