Skip to content

Browser SDK

The official JavaScript library for browser-side Salam Gateway integrations.

Installation

bash
npm install @salamgateway/js
bash
yarn add @salamgateway/js
bash
pnpm add @salamgateway/js

Or 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

OptionTypeDefaultDescription
sandboxbooleanfalseUse sandbox environment
localestring'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>

Support

Released under the MIT License.