Errors
Salam Gateway uses conventional HTTP response codes to indicate success or failure of an API request.
HTTP Status Codes
| Code | Description |
|---|---|
200 | OK - Request succeeded |
201 | Created - Resource created successfully |
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid or missing API key |
403 | Forbidden - Permission denied |
404 | Not Found - Resource doesn't exist |
409 | Conflict - Resource already exists |
422 | Unprocessable Entity - Validation failed |
429 | Too Many Requests - Rate limited |
500 | Internal Server Error - Something went wrong |
503 | Service Unavailable - Temporary server issue |
Error Response Format
All errors return a consistent JSON structure:
json
{
"error": {
"code": "invalid_request",
"message": "The amount must be at least 100 (RM 1.00)",
"param": "amount",
"type": "validation_error",
"doc_url": "https://docs.salamgateway.com/api-reference/errors#invalid_request"
}
}Error Object
| Attribute | Type | Description |
|---|---|---|
code | string | Machine-readable error code |
message | string | Human-readable error message |
param | string | Parameter that caused the error (if applicable) |
type | string | Error type category |
doc_url | string | Link to relevant documentation |
Error Codes
Authentication Errors
| Code | HTTP | Description |
|---|---|---|
invalid_api_key | 401 | API key is invalid, expired, or revoked |
missing_api_key | 401 | No API key provided in Authorization header |
test_mode_required | 403 | Operation requires test mode API key |
live_mode_required | 403 | Operation requires live mode API key |
Validation Errors
| Code | HTTP | Description |
|---|---|---|
invalid_request | 400 | Request format is invalid |
missing_parameter | 400 | Required parameter is missing |
invalid_parameter | 400 | Parameter value is invalid |
amount_too_small | 400 | Amount is below minimum (RM 1.00) |
amount_too_large | 400 | Amount exceeds maximum |
invalid_currency | 400 | Currency is not supported |
invalid_url | 400 | URL format is invalid |
Resource Errors
| Code | HTTP | Description |
|---|---|---|
resource_not_found | 404 | Requested resource doesn't exist |
resource_already_exists | 409 | Resource with same ID already exists |
resource_expired | 400 | Resource has expired |
Payment Errors
| Code | HTTP | Description |
|---|---|---|
payment_failed | 400 | Payment could not be processed |
payment_cancelled | 400 | Payment was cancelled by customer |
payment_expired | 400 | Payment link expired |
already_captured | 400 | Payment already captured |
already_refunded | 400 | Payment already refunded |
capture_amount_invalid | 400 | Capture amount exceeds authorized amount |
refund_amount_invalid | 400 | Refund amount exceeds captured amount |
Bank/Card Errors
| Code | HTTP | Description |
|---|---|---|
card_declined | 400 | Card was declined by issuer |
insufficient_funds | 400 | Insufficient funds in account |
bank_error | 400 | Error from banking provider |
fpx_unavailable | 503 | FPX service temporarily unavailable |
Rate Limit Errors
| Code | HTTP | Description |
|---|---|---|
rate_limit_exceeded | 429 | Too many requests in short time |
Server Errors
| Code | HTTP | Description |
|---|---|---|
internal_error | 500 | Unexpected server error |
service_unavailable | 503 | Service temporarily unavailable |
Handling Errors
Using the Node.js SDK
The SDK throws typed errors that you can catch:
typescript
import { Salam, ApiError, AuthError, ValidationError } from '@salamgateway/node';
const salam = new Salam({ apiKey: 'sk_live_xxx' });
try {
const payment = await salam.payments.create({
amount: 10000,
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
});
} catch (error) {
if (error instanceof AuthError) {
// Handle authentication errors
console.error('Authentication failed:', error.message);
// Redirect to login or check API key
} else if (error instanceof ValidationError) {
// Handle validation errors
console.error(`Validation error on ${error.param}:`, error.message);
// Show error to user
} else if (error instanceof ApiError) {
// Handle other API errors
console.error(`API error (${error.statusCode}):`, error.message);
// Show generic error message
} else {
// Handle unexpected errors
console.error('Unexpected error:', error);
}
}Error Types
The SDK provides specific error classes:
typescript
// Authentication errors
class AuthError extends Error {
statusCode: 401 | 403;
code: string;
}
// Validation errors
class ValidationError extends Error {
statusCode: 400 | 422;
code: string;
param?: string;
}
// Resource errors
class ResourceError extends Error {
statusCode: 404 | 409;
code: string;
}
// Rate limit errors
class RateLimitError extends Error {
statusCode: 429;
retryAfter?: number; // Seconds until retry
}
// Generic API errors
class ApiError extends Error {
statusCode: number;
code: string;
type: string;
}Example Error Responses
Invalid API Key
json
{
"error": {
"code": "invalid_api_key",
"message": "Invalid API key provided",
"type": "authentication_error",
"doc_url": "https://docs.salamgateway.com/getting-started/authentication"
}
}Missing Parameter
json
{
"error": {
"code": "missing_parameter",
"message": "The 'amount' parameter is required",
"param": "amount",
"type": "validation_error",
"doc_url": "https://docs.salamgateway.com/api-reference/payments"
}
}Amount Too Small
json
{
"error": {
"code": "amount_too_small",
"message": "The amount must be at least 100 (RM 1.00)",
"param": "amount",
"type": "validation_error",
"doc_url": "https://docs.salamgateway.com/api-reference/payments"
}
}Payment Not Found
json
{
"error": {
"code": "resource_not_found",
"message": "No payment found with ID 'pay_invalid'",
"type": "resource_error",
"doc_url": "https://docs.salamgateway.com/api-reference/payments"
}
}Card Declined
json
{
"error": {
"code": "card_declined",
"message": "Your card was declined",
"type": "payment_error",
"doc_url": "https://docs.salamgateway.com/guides/error-handling"
}
}Rate Limited
json
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please try again in 60 seconds",
"type": "rate_limit_error",
"doc_url": "https://docs.salamgateway.com/api-reference/errors#rate-limiting"
}
}Rate Limiting
API requests are rate limited to ensure service quality:
| Limit | Value |
|---|---|
| Requests per second | 10 |
| Requests per minute | 100 |
| Requests per hour | 1000 |
Rate limit headers are included in responses:
http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642252800When rate limited, retry after the time specified in Retry-After header:
http
HTTP/1.1 429 Too Many Requests
Retry-After: 60Best Practices
1. Handle Errors Gracefully
Always implement proper error handling:
typescript
async function createPayment(data) {
try {
return await salam.payments.create(data);
} catch (error) {
if (error instanceof ValidationError) {
// Show validation error to user
return { error: error.message, param: error.param };
}
// Log unexpected errors
logger.error('Payment creation failed:', error);
// Show generic error to user
return { error: 'Unable to process payment. Please try again.' };
}
}2. Implement Retry Logic
Retry failed requests with exponential backoff:
typescript
async function retryRequest(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error instanceof RateLimitError) {
// Wait before retrying
await sleep(error.retryAfter * 1000);
} else if (i === maxRetries - 1) {
// Last attempt failed
throw error;
} else {
// Exponential backoff
await sleep(Math.pow(2, i) * 1000);
}
}
}
}
// Usage
const payment = await retryRequest(() =>
salam.payments.create(data)
);3. Log Errors
Log errors for debugging and monitoring:
typescript
try {
await salam.payments.create(data);
} catch (error) {
logger.error('Payment error', {
code: error.code,
message: error.message,
statusCode: error.statusCode,
requestId: error.requestId, // If available
});
}4. Show User-Friendly Messages
Don't expose technical errors to users:
typescript
function getUserMessage(error: ApiError): string {
switch (error.code) {
case 'card_declined':
return 'Your payment was declined. Please try a different card.';
case 'insufficient_funds':
return 'Insufficient funds. Please use a different payment method.';
case 'fpx_unavailable':
return 'Online banking is temporarily unavailable. Please try again later.';
default:
return 'Unable to process payment. Please try again.';
}
}5. Monitor Error Rates
Track error rates in your application:
- Set up alerts for high error rates
- Monitor specific error codes
- Track payment success/failure rates
- Review logs regularly
Need Help?
If you encounter persistent errors, contact support at support@salamgateway.com with the error details and request ID.