Instant Provisioning on Sign-Up
We integrated Nomba's Virtual Account API so that every student gets a personal bank account numbers linked directly to their TicketPay wallet during onboarding. No manuals deposits required.
// Virtual Account Generation Flow
const result = await axios.post(`${NOMBA_BASE_URL}/v1/virtual-accounts`, {
accountRef: `TP-${uuidv4()}`,
accountName: studentFullName,
bankCode: "100033", // Nomba Default
...
});
HMAC-SHA256 Webhook Cryptographic Validation
We engineered signature verification to validate requests sent to /api/wallets/webhook/nomba using Nomba's custom colon-delimited parameters rather than raw body strings, protected by crypto.timingSafeEqual.
// Signature calculation
const hashingPayload = `${eventType}:${requestId}:${userId}:${walletId}:${transactionId}:${transactionType}:${transactionTime}:${transactionResponseCode}:${timestamp}`;
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
const expectedSignature = hmac.update(hashingPayload).digest('base64');
const isValid = crypto.timingSafeEqual(Buffer.from(sig, 'base64'), Buffer.from(expectedSignature, 'base64'));
Redis-backed Token Rotation Strategy
Nomba tokens expire every 30 minutes. To prevent API rate limits and token expirations, we implemented a dual-key cache in Redis. The active token expires in 25 minutes, triggering background renewal using the refresh_token grant before the absolute expiration.
// Redis Cache & Expiry Check
const cachedToken = await redis.get("nomba:access_token");
if (!cachedToken) {
const expiredToken = await redis.get("nomba:expired_access_token");
const refresh = await redis.get("nomba:refresh_token");
// Call Nomba /v1/auth/token/refresh using refresh_token...
}