@zencemarketing/storepay-sdk
v0.1.0-alpha.1
Published
StorePay React SDK to open StorePay payment gateway UI in an iframe modal
Downloads
187
Readme
@zencemarketing/storepay-sdk
StorePay React SDK - A simple React SDK to open StorePay payment gateway UI in an iframe modal.
Installation
npm install @zencemarketing/storepay-sdkQuick Start
import React, { useEffect, useState } from 'react';
import { StorePayProvider, useStorePay, StorePayButton } from '@zencemarketing/storepay-sdk';
function App() {
return (
<StorePayProvider>
<PaymentComponent />
</StorePayProvider>
);
}
function PaymentComponent() {
const { init, openPayment, isInitialized } = useStorePay();
const [accessToken, setAccessToken] = useState<string | null>(null);
// Your API configuration
const tokenUrl = 'YOUR_TOKEN_URL';
const clientId = 'YOUR_CLIENT_ID';
const clientSecret = 'YOUR_CLIENT_SECRET';
const paymentGatewayUrl = 'YOUR_PAYMENT_GATEWAY_URL';
const apiBaseUrl = 'YOUR_API_BASE_URL';
useEffect(() => {
// Initialize SDK
try {
init({
paymentGatewayUrl: paymentGatewayUrl
});
console.log('SDK initialized successfully');
} catch (error) {
console.error('SDK initialization failed:', error);
}
}, [init]);
// Format bill date time helper
const formatBillDateTime = () => {
const now = new Date();
const day = now.getDate().toString().padStart(2, '0');
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const month = monthNames[now.getMonth()];
const year = now.getFullYear();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
return `${day}-${month}-${year} ${hours}:${minutes}:${seconds}`;
};
// Get access token
const getAccessToken = async () => {
try {
const data = `Client_Id=${encodeURIComponent(clientId)}&Client_Secret=${encodeURIComponent(clientSecret)}&Grant_Type=client_credentials&Scope=api.storepay.com`;
const response = await fetch(`${tokenUrl}/connect/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
body: data
});
if (!response.ok) {
throw new Error(`Token request failed: ${response.status} ${response.statusText}`);
}
const responseData = await response.json();
return responseData.access_token;
} catch (error) {
console.error('Failed to get access token:', error);
throw error;
}
};
// Generate payment iframe URL (complete flow)
const generatePaymentIframeUrl = async (paymentData: any) => {
try {
// Step 1: Get access token (use cached or fetch new)
let token = accessToken;
if (!token) {
token = await getAccessToken();
setAccessToken(token || null);
}
// Step 2: Call GeneratePaymentLink API
const response = await fetch(`${apiBaseUrl}/api/GeneratePaymentLink`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(paymentData)
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(`Payment failed: ${errorData.message || response.statusText}`);
}
const responseData = await response.json();
// Check for error in response
if (responseData.returnCode !== "0" && responseData.returnCode !== 0) {
throw new Error(responseData.returnMessage || "Payment link generation failed");
}
// Extract tokenId from response
const tokenId = responseData.tokenId;
if (!tokenId) {
throw new Error("Token ID not received from API");
}
// Get programCode from paymentData
const programCode = paymentData.programCode;
if (!programCode) {
throw new Error("Program code is required in payment data");
}
// Step 3: Encrypt the URL parameters using AESEncrypt API
const textToEncrypt = `programcode=${programCode}&tokenId=${tokenId}&language=en`;
const encryptResponse = await fetch(`${apiBaseUrl}/api/AESEncrypt`, {
method: 'POST',
headers: {
'accept': 'text/plain',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ text: textToEncrypt })
});
if (!encryptResponse.ok) {
throw new Error(`Encryption failed: ${encryptResponse.statusText}`);
}
// Get encrypted text from JSON response
const encryptResponseData = await encryptResponse.json();
const encryptedText = encryptResponseData.encryptedText;
if (!encryptedText) {
throw new Error("Encrypted text not received from API");
}
// Step 4: Build the iframe URL
const iframeUrl = `${paymentGatewayUrl}/ol/?${encryptedText}`;
return iframeUrl;
} catch (error) {
// If token expired, try once more with new token
if (error instanceof Error && error.message.includes('401')) {
const newToken = await getAccessToken();
setAccessToken(newToken || null);
throw new Error("Token expired. Please try again.");
}
throw error;
}
};
// Handle payment
const handlePayment = async () => {
try {
// Prepare payment data
const paymentData = {
programCode: 'YOUR_PROGRAM_CODE',
storeCode: 'YOUR_STORE_CODE',
billDateTime: formatBillDateTime(),
terminalId: 'YOUR_TERMINAL_ID',
merchantTxnID: `TXN_${Date.now()}`,
name: "Customer Name",
email: null,
mobile: '1234567890',
customerId: 'YOUR_CUSTOMER_ID',
amount: 100,
mode: '1',
linkRequired: true
};
// Generate iframe URL (all API calls happen here)
const iframeUrl = await generatePaymentIframeUrl(paymentData);
// Open payment using SDK
openPayment(iframeUrl, {
onSuccess: (data) => {
console.log('Payment Success:', data);
alert(`Payment Successful!\nTransaction ID: ${data.merchantTxnId}\nMessage: ${data.message}`);
},
onFailure: (data) => {
console.log('Payment Failed:', data);
alert(`Payment Failed!\nBill ID: ${data.billId || 'N/A'}`);
},
onCancel: (data) => {
console.log('Payment Cancelled:', data);
alert(`Payment Cancelled: ${data.message}`);
},
onError: (data) => {
console.log('Payment Error:', data);
alert(`Payment Error: ${data.message}`);
},
onTimeout: (data) => {
console.log('Payment Timeout:', data);
alert(`Payment Timed Out!\nMessage: ${data.message}`);
}
});
} catch (error) {
console.error('Payment failed:', error);
alert(error instanceof Error ? error.message : 'Payment failed');
}
};
return (
<button onClick={handlePayment} disabled={!isInitialized}>
Pay with StorePay
</button>
);
}Using StorePayButton Component
import { StorePayButton } from '@zencemarketing/storepay-sdk';
function PaymentButton() {
const [iframeUrl, setIframeUrl] = useState<string | null>(null);
const generatePaymentUrl = async () => {
// Generate iframe URL using your API calls
const url = await generatePaymentIframeUrl(paymentData);
setIframeUrl(url);
};
return (
<>
<button onClick={generatePaymentUrl}>Generate Payment URL</button>
{iframeUrl && (
<StorePayButton
iframeUrl={iframeUrl}
callbacks={{
onSuccess: (data) => console.log('Success:', data),
onFailure: (data) => console.log('Failed:', data),
onCancel: (data) => console.log('Cancelled:', data),
onError: (data) => console.log('Error:', data),
onTimeout: (data) => console.log('Timeout:', data)
}}
>
Pay with StorePay
</StorePayButton>
)}
</>
);
}Features
- ✅ Simple iframe modal integration
- ✅ Payment status callbacks (success, failure, cancel, error, timeout)
- ✅ No API calls in SDK - full control in your application
- ✅ TypeScript support
- ✅ React 16.8+ compatible
- ✅ Token caching support
- ✅ Error handling
API Reference
init(config: StorePayInitConfig)
Initialize the SDK with payment gateway URL.
init({
paymentGatewayUrl: 'YOUR_PAYMENT_GATEWAY_URL'
});openPayment(iframeUrl: string, callbacks?: StorePayPaymentCallbacks)
Open payment modal with the generated iframe URL.
openPayment(iframeUrl, {
onSuccess: (data) => { /* ... */ },
onFailure: (data) => { /* ... */ },
onCancel: (data) => { /* ... */ },
onError: (data) => { /* ... */ },
onTimeout: (data) => { /* ... */ }
});closeCheckout()
Close the payment modal programmatically.
isInitialized
Boolean indicating if SDK is initialized.
Payment Flow
- Get Access Token - Call your token API endpoint
- Generate Payment Link - Call GeneratePaymentLink API with payment data
- Encrypt URL - Call AESEncrypt API to encrypt payment parameters
- Build Iframe URL - Combine payment gateway URL with encrypted text
- Open Payment - Use SDK's
openPayment()to open the modal
Documentation
See README-SDK.md for complete documentation and API reference.
Version
Current Version: 0.1.0-alpha.1 (Pre-release)
This is a pre-release version. Official release coming soon.
License
MIT
Author
ZenceMarketing
