Browser SDK
The official JavaScript library for browser-side Salam Gateway integrations.
Installation
bash
npm install @salamgateway/jsbash
yarn add @salamgateway/jsbash
pnpm add @salamgateway/jsOr use via CDN:
html
<script src="https://cdn.salamgateway.com/js/v1/salam.js"></script>Setup
javascript
import SalamJS from '@salamgateway/js';
const salam = new SalamJS('pk_test_xxx', {
sandbox: true,
});WARNING
Use publishable key (pk_) not secret key (sk_) in browser code.
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
sandbox | boolean | false | Use sandbox environment |
locale | string | 'en' | UI language (en, ms) |
Create Payment
javascript
const payment = await salam.payments.create({
amount: 10000,
description: 'Order #1234',
success_url: window.location.origin + '/success',
cancel_url: window.location.origin + '/cancel',
});
// Redirect to checkout
window.location.href = payment.redirect_url;React Integration
Payment Button
tsx
import { useState } from 'react';
import SalamJS from '@salamgateway/js';
const salam = new SalamJS(process.env.NEXT_PUBLIC_SALAM_KEY);
export default function CheckoutButton() {
const [loading, setLoading] = useState(false);
const handleCheckout = async () => {
setLoading(true);
try {
const payment = await salam.payments.create({
amount: 10000,
description: 'Order #1234',
success_url: window.location.origin + '/checkout/success',
cancel_url: window.location.origin + '/checkout/cancel',
metadata: {
order_id: '1234',
},
});
window.location.href = payment.redirect_url;
} catch (error) {
alert('Payment failed: ' + error.message);
setLoading(false);
}
};
return (
<button onClick={handleCheckout} disabled={loading}>
{loading ? 'Processing...' : 'Pay Now'}
</button>
);
}Payment Hook
tsx
import { useState } from 'react';
import SalamJS from '@salamgateway/js';
export function usePayment() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const createPayment = async (amount: number, description: string) => {
setLoading(true);
setError(null);
try {
const salam = new SalamJS(process.env.NEXT_PUBLIC_SALAM_KEY!);
const payment = await salam.payments.create({
amount,
description,
success_url: window.location.origin + '/success',
cancel_url: window.location.origin + '/cancel',
});
return payment;
} catch (err: any) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
};
return { createPayment, loading, error };
}
// Usage
function CheckoutPage() {
const { createPayment, loading, error } = usePayment();
const handleCheckout = async () => {
try {
const payment = await createPayment(10000, 'Order #1234');
window.location.href = payment.redirect_url;
} catch (error) {
console.error('Checkout failed:', error);
}
};
return (
<button onClick={handleCheckout} disabled={loading}>
Checkout
</button>
);
}Vue Integration
Composition API
vue
<script setup>
import { ref } from 'vue';
import SalamJS from '@salamgateway/js';
const loading = ref(false);
const salam = new SalamJS(import.meta.env.VITE_SALAM_KEY);
async function checkout() {
loading.value = true;
try {
const payment = await salam.payments.create({
amount: 10000,
description: 'Order #1234',
success_url: window.location.origin + '/success',
cancel_url: window.location.origin + '/cancel',
});
window.location.href = payment.redirect_url;
} catch (error) {
alert('Payment failed: ' + error.message);
loading.value = false;
}
}
</script>
<template>
<button @click="checkout" :disabled="loading">
{{ loading ? 'Processing...' : 'Pay Now' }}
</button>
</template>Options API
vue
<script>
import SalamJS from '@salamgateway/js';
export default {
data() {
return {
loading: false,
salam: new SalamJS(process.env.VUE_APP_SALAM_KEY),
};
},
methods: {
async checkout() {
this.loading = true;
try {
const payment = await this.salam.payments.create({
amount: 10000,
description: 'Order #1234',
success_url: window.location.origin + '/success',
cancel_url: window.location.origin + '/cancel',
});
window.location.href = payment.redirect_url;
} catch (error) {
alert('Payment failed: ' + error.message);
this.loading = false;
}
},
},
};
</script>
<template>
<button @click="checkout" :disabled="loading">
{{ loading ? 'Processing...' : 'Pay Now' }}
</button>
</template>Vanilla JavaScript
html
<!DOCTYPE html>
<html>
<head>
<title>Checkout</title>
<script src="https://cdn.salamgateway.com/js/v1/salam.js"></script>
</head>
<body>
<button id="checkout-btn">Pay RM 100.00</button>
<script>
const salam = new SalamJS('pk_test_xxx', { sandbox: true });
document.getElementById('checkout-btn').addEventListener('click', async () => {
try {
const payment = await salam.payments.create({
amount: 10000,
description: 'Order #1234',
success_url: window.location.origin + '/success.html',
cancel_url: window.location.origin + '/cancel.html',
});
window.location.href = payment.redirect_url;
} catch (error) {
alert('Payment failed: ' + error.message);
}
});
</script>
</body>
</html>Error Handling
javascript
import { ApiError } from '@salamgateway/js';
try {
const payment = await salam.payments.create(data);
} catch (error) {
if (error instanceof ApiError) {
switch (error.code) {
case 'invalid_api_key':
console.error('Invalid API key');
break;
case 'amount_too_small':
console.error('Amount too small');
break;
default:
console.error('Payment error:', error.message);
}
}
}TypeScript Support
typescript
import SalamJS, { Payment, PaymentCreateParams } from '@salamgateway/js';
const salam = new SalamJS('pk_test_xxx');
const params: PaymentCreateParams = {
amount: 10000,
description: 'Order #1234',
success_url: '/success',
cancel_url: '/cancel',
};
const payment: Payment = await salam.payments.create(params);Success Page
Verify payment status on success page:
javascript
// success.html or success page component
const urlParams = new URLSearchParams(window.location.search);
const paymentId = urlParams.get('payment_id');
if (paymentId) {
// Verify with your backend
fetch(`/api/payments/${paymentId}/verify`)
.then(res => res.json())
.then(data => {
if (data.status === 'captured') {
showSuccessMessage();
} else {
showErrorMessage();
}
});
}Best Practices
1. Use Environment Variables
javascript
// React/Next.js
const salam = new SalamJS(process.env.NEXT_PUBLIC_SALAM_KEY);
// Vue/Vite
const salam = new SalamJS(import.meta.env.VITE_SALAM_KEY);2. Handle Errors Gracefully
javascript
async function checkout() {
try {
const payment = await salam.payments.create(data);
window.location.href = payment.redirect_url;
} catch (error) {
// Show user-friendly message
showToast('Unable to process payment. Please try again.');
// Log for debugging
console.error('Checkout failed:', error);
}
}3. Show Loading States
javascript
button.disabled = true;
button.textContent = 'Processing...';
try {
const payment = await salam.payments.create(data);
window.location.href = payment.redirect_url;
} catch (error) {
button.disabled = false;
button.textContent = 'Pay Now';
showError(error.message);
}4. Validate Before Payment
javascript
function validateCheckout() {
if (amount < 100) {
alert('Minimum amount is RM 1.00');
return false;
}
if (!email) {
alert('Email is required');
return false;
}
return true;
}
if (validateCheckout()) {
const payment = await salam.payments.create(data);
}CDN Usage
html
<script src="https://cdn.salamgateway.com/js/v1/salam.js"></script>
<script>
// SalamJS is available globally
const salam = new SalamJS('pk_test_xxx');
async function checkout() {
const payment = await salam.payments.create({
amount: 10000,
success_url: '/success',
cancel_url: '/cancel',
});
window.location.href = payment.redirect_url;
}
</script>