Skip to content

Errors

Salam Gateway uses conventional HTTP response codes to indicate success or failure of an API request.

HTTP Status Codes

CodeDescription
200OK - Request succeeded
201Created - Resource created successfully
400Bad Request - Invalid parameters
401Unauthorized - Invalid or missing API key
403Forbidden - Permission denied
404Not Found - Resource doesn't exist
409Conflict - Resource already exists
422Unprocessable Entity - Validation failed
429Too Many Requests - Rate limited
500Internal Server Error - Something went wrong
503Service 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

AttributeTypeDescription
codestringMachine-readable error code
messagestringHuman-readable error message
paramstringParameter that caused the error (if applicable)
typestringError type category
doc_urlstringLink to relevant documentation

Error Codes

Authentication Errors

CodeHTTPDescription
invalid_api_key401API key is invalid, expired, or revoked
missing_api_key401No API key provided in Authorization header
test_mode_required403Operation requires test mode API key
live_mode_required403Operation requires live mode API key

Validation Errors

CodeHTTPDescription
invalid_request400Request format is invalid
missing_parameter400Required parameter is missing
invalid_parameter400Parameter value is invalid
amount_too_small400Amount is below minimum (RM 1.00)
amount_too_large400Amount exceeds maximum
invalid_currency400Currency is not supported
invalid_url400URL format is invalid

Resource Errors

CodeHTTPDescription
resource_not_found404Requested resource doesn't exist
resource_already_exists409Resource with same ID already exists
resource_expired400Resource has expired

Payment Errors

CodeHTTPDescription
payment_failed400Payment could not be processed
payment_cancelled400Payment was cancelled by customer
payment_expired400Payment link expired
already_captured400Payment already captured
already_refunded400Payment already refunded
capture_amount_invalid400Capture amount exceeds authorized amount
refund_amount_invalid400Refund amount exceeds captured amount

Bank/Card Errors

CodeHTTPDescription
card_declined400Card was declined by issuer
insufficient_funds400Insufficient funds in account
bank_error400Error from banking provider
fpx_unavailable503FPX service temporarily unavailable

Rate Limit Errors

CodeHTTPDescription
rate_limit_exceeded429Too many requests in short time

Server Errors

CodeHTTPDescription
internal_error500Unexpected server error
service_unavailable503Service 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:

LimitValue
Requests per second10
Requests per minute100
Requests per hour1000

Rate limit headers are included in responses:

http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642252800

When rate limited, retry after the time specified in Retry-After header:

http
HTTP/1.1 429 Too Many Requests
Retry-After: 60

Best 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.

Released under the MIT License.