Quick Start
Accept your first payment in under 5 minutes.
Prerequisites
- A Salam Gateway account (Sign up)
- Your API keys from the dashboard
Step 1: Install the SDK
npm install @salamgateway/nodeyarn add @salamgateway/nodepnpm add @salamgateway/nodeStep 2: Create a Payment
import Salam from '@salamgateway/node';
const salam = new Salam({
apiKey: 'sk_test_your_api_key',
sandbox: true, // Use sandbox for testing
});
// Create a payment
const payment = await salam.payments.create({
amount: 10000, // RM 100.00 in cents
description: 'Premium subscription',
success_url: 'https://yoursite.com/success',
cancel_url: 'https://yoursite.com/cancel',
});
// Redirect customer to checkout
console.log(payment.redirect_url);
// https://sandbox-checkout.salamgateway.com/pay/pay_xxxStep 3: Handle Webhooks
import express from 'express';
const app = express();
app.post('/webhooks/salam',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.headers['salam-signature'];
try {
const event = salam.webhooks.constructEvent(req.body, sig);
if (event.type === 'payment.captured') {
const payment = event.data;
// Fulfill the order
console.log('Payment successful:', payment.id);
}
res.json({ received: true });
} catch (err) {
res.status(400).send(`Webhook Error: ${err.message}`);
}
}
);Step 4: Test the Integration
Use these test credentials in sandbox mode:
| Bank | Account |
|---|---|
| Maybank | Any 12-digit number |
| CIMB | Any 10-digit number |
TIP
All payments in sandbox mode will succeed automatically.
Complete Example
import express from 'express';
import Salam from '@salamgateway/node';
const app = express();
const salam = new Salam({
apiKey: process.env.SALAM_API_KEY,
sandbox: true,
});
// Create payment endpoint
app.post('/create-payment', async (req, res) => {
try {
const payment = await salam.payments.create({
amount: req.body.amount,
description: req.body.description,
success_url: `${req.body.base_url}/success`,
cancel_url: `${req.body.base_url}/cancel`,
});
res.json({ redirect_url: payment.redirect_url });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Webhook endpoint
app.post('/webhooks/salam',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['salam-signature'];
try {
const event = salam.webhooks.constructEvent(req.body, signature);
switch (event.type) {
case 'payment.captured':
// Payment successful
console.log('Payment captured:', event.data.id);
break;
case 'payment.failed':
// Payment failed
console.log('Payment failed:', event.data.id);
break;
}
res.json({ received: true });
} catch (error) {
res.status(400).send(`Webhook Error: ${error.message}`);
}
}
);
app.listen(3000);Next Steps
- Set up webhooks for production
- Go live checklist before launching
- Handle errors gracefully
Get started with Salam Payments in under 5 minutes. This guide will walk you through creating your first payment.
1. Get Your API Keys
Sign up at dashboard.salam.com and get your API keys from the Developers section.
You'll have two sets of keys:
- Test keys - Start with
sk_test_andpk_test_for development - Live keys - Start with
sk_live_andpk_live_for production
Keep your secret key safe
Never expose your secret key in client-side code or commit it to version control. Use environment variables to store your keys securely.
2. Install the SDK
Choose your preferred package manager:
npm install @salam/salam-nodeyarn add @salam/salam-nodepnpm add @salam/salam-nodeFor browser-side integration:
<script src="https://js.salam.com/v1/salam.js"></script>3. Create Your First Payment
Server-side (Node.js)
const Salam = require('@salam/salam-node');
const salam = new Salam('sk_test_xxxxx');
// Create a payment
const payment = await salam.payments.create({
amount: 5000, // RM 50.00 (amount in cents)
currency: 'MYR',
payment_method_data: {
type: 'card',
card: {
number: '4242424242424242',
exp_month: 12,
exp_year: 2025,
cvc: '123',
},
},
description: 'Test payment',
metadata: {
order_id: '12345',
},
});
console.log(payment.id); // pay_xxxxx
console.log(payment.status); // succeededClient-side (Browser)
Create a payment form with secure card input:
<!DOCTYPE html>
<html>
<head>
<title>Salam Payment</title>
<script src="https://js.salam.com/v1/salam.js"></script>
<style>
#card-element {
border: 1px solid #ccc;
padding: 10px;
border-radius: 4px;
}
.error {
color: #f93e3e;
margin-top: 8px;
}
</style>
</head>
<body>
<form id="payment-form">
<div id="card-element"></div>
<div id="card-errors" class="error"></div>
<button type="submit">Pay RM 50.00</button>
</form>
<script>
const salam = Salam('pk_test_xxxxx');
const elements = salam.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
// Handle real-time validation errors
cardElement.on('change', (event) => {
const displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Handle form submission
document.getElementById('payment-form').addEventListener('submit', async (e) => {
e.preventDefault();
const { paymentMethod, error } = await salam.createPaymentMethod({
type: 'card',
card: cardElement,
});
if (error) {
console.error(error.message);
return;
}
// Send paymentMethod.id to your server
const response = await fetch('/create-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
payment_method: paymentMethod.id,
amount: 5000,
}),
});
const result = await response.json();
if (result.status === 'succeeded') {
alert('Payment successful!');
} else if (result.status === 'requires_action') {
// Handle 3D Secure
const { error: confirmError } = await salam.confirmPayment(
result.client_secret
);
if (confirmError) {
console.error(confirmError);
} else {
alert('Payment successful!');
}
}
});
</script>
</body>
</html>Server endpoint for browser payments
const express = require('express');
const app = express();
const Salam = require('@salam/salam-node');
const salam = new Salam(process.env.SALAM_SECRET_KEY);
app.use(express.json());
app.post('/create-payment', async (req, res) => {
try {
const { payment_method, amount } = req.body;
const payment = await salam.payments.create({
amount,
currency: 'MYR',
payment_method,
description: 'Order payment',
});
res.json({
status: payment.status,
client_secret: payment.client_secret,
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});4. Handle Webhooks
Set up webhooks to receive real-time payment notifications:
const express = require('express');
const app = express();
// Important: Use raw body for webhook verification
app.post('/webhook',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.headers['x-salam-signature'];
const webhookSecret = 'whsec_xxxxx';
try {
const event = salam.webhooks.constructEvent(
req.body,
sig,
webhookSecret
);
switch (event.type) {
case 'payment.succeeded':
const payment = event.data.object;
console.log(`Payment ${payment.id} succeeded!`);
// Fulfill the order
fulfillOrder(payment);
break;
case 'payment.failed':
console.log(`Payment ${event.data.object.id} failed`);
// Handle failed payment
break;
case 'refund.created':
console.log(`Refund ${event.data.object.id} created`);
// Handle refund
break;
}
res.json({ received: true });
} catch (err) {
console.error('Webhook signature verification failed:', err.message);
res.status(400).send(`Webhook Error: ${err.message}`);
}
}
);
function fulfillOrder(payment) {
// Your order fulfillment logic
console.log('Fulfilling order for payment:', payment.id);
}Webhook Secret
Get your webhook signing secret from Dashboard → Developers → Webhooks. Each endpoint has a unique secret starting with whsec_.
5. FPX Payments (Malaysian Banks)
To accept FPX payments:
// Server-side
const payment = await salam.payments.create({
amount: 10000, // RM 100.00
currency: 'MYR',
payment_method_data: {
type: 'fpx',
fpx: {
bank_code: 'MBBEMYKL', // Maybank
},
},
return_url: 'https://yoursite.com/payment/complete',
});
// Redirect customer to payment.next_action.redirect_to_url
res.redirect(payment.next_action.redirect_to_url);Supported FPX banks:
- Maybank (MBBEMYKL)
- CIMB Bank (CIBBMYKL)
- Public Bank (PBBEMYKL)
- Hong Leong Bank (HLBBMYKL)
- RHB Bank (RHBBMYKL)
- And more...
Next Steps
Now that you've created your first payment, learn more about:
- Authentication - API keys and security
- Accept a Payment - Complete payment flow guide
- Handle Webhooks - Production webhook setup
- Test Mode - Test cards and testing guide
- API Reference - Full API documentation
Common Issues
Payment fails with "card_declined"
This is normal in test mode. Use test card 4242 4242 4242 4242 for successful payments, or see Test Mode for other test cards.
Webhook signature verification fails
Make sure you're using the raw request body (Buffer or string), not a parsed JSON object. See Webhook Signatures.
CORS errors in browser
Make sure you're using your publishable key (pk_test_ or pk_live_) in client-side code, not your secret key.