Skip to content

Error Codes Usage Examples

Complete guide on using Payme error code constants.

Overview

The library provides comprehensive error code constants for all Payme API errors. This makes error handling more readable and maintainable.

Importing Error Codes

typescript
import { 
  PAYME_ERROR_CODES,
  ERROR_MESSAGES,
  getErrorMessage,
  PaymeError
} from '@joyida/payme';

Using Error Codes

Basic Error Handling

typescript
import { PaymeMerchant, PaymeError, PAYME_ERROR_CODES } from '@joyida/payme';

const payme = new PaymeMerchant({
  merchantId: process.env.PAYME_MERCHANT_ID!,
  secretKey: process.env.PAYME_SECRET_KEY!
});

try {
  await payme.createTransaction(params);
} catch (error) {
  if (error instanceof PaymeError) {
    switch (error.code) {
      case PAYME_ERROR_CODES.FORBIDDEN:
        console.error('Invalid credentials');
        break;
        
      case PAYME_ERROR_CODES.INVALID_AMOUNT:
        console.error('Invalid payment amount');
        break;
        
      case PAYME_ERROR_CODES.TRANSACTION_NOT_FOUND:
        console.error('Transaction not found');
        break;
        
      case PAYME_ERROR_CODES.ACCOUNT_NOT_FOUND:
        console.error('Order not found');
        break;
        
      case PAYME_ERROR_CODES.ORDER_ALREADY_PAID:
        console.error('Order already paid');
        break;
        
      case PAYME_ERROR_CODES.CANNOT_CANCEL:
        console.error('Cannot cancel - order fulfilled');
        break;
        
      default:
        console.error(`Payme error: ${error.message}`);
    }
  }
}

Using Merchant API Error Codes

typescript
import { PaymeMerchant, PaymeError, PAYME_ERROR_CODES } from '@joyida/payme';

const payme = new PaymeMerchant({
  merchantId: process.env.PAYME_MERCHANT_ID!,
  secretKey: process.env.PAYME_SECRET_KEY!
});

try {
  await payme.performTransaction({ id: paymeId });
} catch (error) {
  if (error instanceof PaymeError) {
    switch (error.code) {
      case PAYME_ERROR_CODES.TRANSACTION_NOT_FOUND:
        console.error('Transaction not found');
        break;
        
      case PAYME_ERROR_CODES.INVALID_STATE:
        console.error('Invalid transaction state');
        break;
        
      case PAYME_ERROR_CODES.CANNOT_PERFORM:
        console.error('Cannot perform transaction');
        break;
        
      case PAYME_ERROR_CODES.ALREADY_DONE:
        console.error('Transaction already completed');
        break;
        
      default:
        console.error(`Error: ${error.message}`);
    }
  }
}

Using Subscribe API Error Codes

typescript
import { PaymeSubscribe, PaymeError, PAYME_ERROR_CODES } from '@joyida/payme';

const subscribe = new PaymeSubscribe({
  merchantId: process.env.PAYME_MERCHANT_ID!,
  password: process.env.PAYME_PASSWORD!
}, 'server');

try {
  await subscribe.receiptsPay({
    id: receiptId,
    token: cardToken
  });
} catch (error) {
  if (error instanceof PaymeError) {
    switch (error.code) {
      case PAYME_ERROR_CODES.CARD_NOT_FOUND:
        console.error('Card not found');
        break;
        
      case PAYME_ERROR_CODES.CARD_EXPIRED:
        console.error('Card has expired');
        break;
        
      case PAYME_ERROR_CODES.CARD_BLOCKED:
        console.error('Card is blocked');
        break;
        
      case PAYME_ERROR_CODES.INSUFFICIENT_FUNDS:
        console.error('Insufficient funds');
        break;
        
      case PAYME_ERROR_CODES.CARD_VERIFICATION_FAILED:
        console.error('Card verification failed');
        break;
        
      case PAYME_ERROR_CODES.RECEIPT_NOT_FOUND:
        console.error('Receipt not found');
        break;
        
      case PAYME_ERROR_CODES.RECEIPT_ALREADY_PAID:
        console.error('Receipt already paid');
        break;
        
      default:
        console.error(`Error: ${error.message}`);
    }
  }
}

Getting Error Messages

Using ERROR_MESSAGES

typescript
import { ERROR_MESSAGES, PAYME_ERROR_CODES } from '@joyida/payme';

const errorCode = PAYME_ERROR_CODES.INVALID_AMOUNT;
const message = ERROR_MESSAGES[errorCode];

console.log(message); // "Invalid amount"

Using getErrorMessage Helper

typescript
import { getErrorMessage, PAYME_ERROR_CODES } from '@joyida/payme';

const message1 = getErrorMessage(PAYME_ERROR_CODES.FORBIDDEN);
console.log(message1); // "Forbidden - Invalid credentials"

const message2 = getErrorMessage(PAYME_ERROR_CODES.CARD_EXPIRED);
console.log(message2); // "Card has expired"

const message3 = getErrorMessage(-99999);
console.log(message3); // "Unknown error (code: -99999)"

Complete Error Handling Example

typescript
import {
  PaymeMerchant,
  PaymeError,
  PAYME_ERROR_CODES,
  getErrorMessage
} from '@joyida/payme';

const payme = new PaymeMerchant({
  merchantId: process.env.PAYME_MERCHANT_ID!,
  secretKey: process.env.PAYME_SECRET_KEY!
});

async function processPayment(orderId: string, amount: number) {
  try {
    const paymeId = generatePaymeId();
    
    const created = await payme.createTransaction({
      id: paymeId,
      time: Date.now(),
      amount,
      account: { order_id: orderId }
    });
    
    const performed = await payme.performTransaction({
      id: paymeId
    });
    
    return {
      success: true,
      transactionId: performed.transaction
    };
    
  } catch (error) {
    if (error instanceof PaymeError) {
      // Log error with code and message
      console.error({
        code: error.code,
        message: error.message,
        description: getErrorMessage(error.code)
      });
      
      // Handle specific errors
      switch (error.code) {
        case PAYME_ERROR_CODES.FORBIDDEN:
          throw new Error('Payment system configuration error');
          
        case PAYME_ERROR_CODES.INVALID_AMOUNT:
          throw new Error('Invalid payment amount');
          
        case PAYME_ERROR_CODES.ACCOUNT_NOT_FOUND:
          throw new Error('Order not found');
          
        case PAYME_ERROR_CODES.ORDER_ALREADY_PAID:
          throw new Error('Order already paid');
          
        case PAYME_ERROR_CODES.ORDER_CANCELLED:
          throw new Error('Order is cancelled');
          
        case PAYME_ERROR_CODES.ORDER_EXPIRED:
          throw new Error('Order has expired');
          
        case PAYME_ERROR_CODES.TRANSACTION_NOT_FOUND:
          throw new Error('Transaction not found');
          
        case PAYME_ERROR_CODES.CANNOT_PERFORM:
          throw new Error('Cannot complete payment');
          
        case PAYME_ERROR_CODES.TRANSPORT_ERROR:
          throw new Error('Payment system temporarily unavailable');
          
        default:
          throw new Error(`Payment error: ${error.message}`);
      }
    }
    throw error;
  }
}

Error Code Categories

JSON-RPC Protocol Errors

typescript
import { PAYME_ERROR_CODES } from '@joyida/payme';

// Protocol errors
PAYME_ERROR_CODES.PARSE_ERROR          // -32700
PAYME_ERROR_CODES.INVALID_REQUEST      // -32600
PAYME_ERROR_CODES.METHOD_NOT_FOUND     // -32601
PAYME_ERROR_CODES.INVALID_PARAMS       // -32602
PAYME_ERROR_CODES.INTERNAL_ERROR       // -32603
PAYME_ERROR_CODES.TRANSPORT_ERROR      // -32400
PAYME_ERROR_CODES.METHOD_NOT_POST      // -32300
PAYME_ERROR_CODES.FORBIDDEN            // -32504

Transaction Errors

typescript
// Transaction errors
PAYME_ERROR_CODES.INVALID_AMOUNT           // -31001
PAYME_ERROR_CODES.INVALID_ACCOUNT          // -31002
PAYME_ERROR_CODES.TRANSACTION_NOT_FOUND    // -31003
PAYME_ERROR_CODES.INVALID_STATE            // -31004
PAYME_ERROR_CODES.TRANSACTION_CANCELLED    // -31005
PAYME_ERROR_CODES.TRANSACTION_EXISTS       // -31006
PAYME_ERROR_CODES.CANNOT_CANCEL            // -31007
PAYME_ERROR_CODES.CANNOT_PERFORM           // -31008

Account Errors

typescript
// Account errors (range: -31050 to -31099)
PAYME_ERROR_CODES.ACCOUNT_NOT_FOUND        // -31050
PAYME_ERROR_CODES.ACCOUNT_BLOCKED          // -31051
PAYME_ERROR_CODES.ACCOUNT_INACTIVE         // -31052
PAYME_ERROR_CODES.INSUFFICIENT_PRIVILEGES  // -31053
PAYME_ERROR_CODES.ACCOUNT_LIMIT_EXCEEDED   // -31054
PAYME_ERROR_CODES.ORDER_ALREADY_PAID       // -31055
PAYME_ERROR_CODES.ORDER_CANCELLED          // -31056
PAYME_ERROR_CODES.ORDER_NOT_AVAILABLE      // -31057
PAYME_ERROR_CODES.INVALID_ORDER_AMOUNT     // -31058
PAYME_ERROR_CODES.ORDER_EXPIRED            // -31059
PAYME_ERROR_CODES.ALREADY_DONE             // -31060
PAYME_ERROR_CODES.PENDING_TRANSACTION      // -31099

Card Errors

typescript
// Card errors (range: -31300 to -31310)
PAYME_ERROR_CODES.CARD_NOT_FOUND           // -31300
PAYME_ERROR_CODES.CARD_EXPIRED             // -31301
PAYME_ERROR_CODES.CARD_BLOCKED             // -31302
PAYME_ERROR_CODES.INSUFFICIENT_FUNDS       // -31303
PAYME_ERROR_CODES.CARD_VERIFICATION_FAILED // -31304
PAYME_ERROR_CODES.INVALID_CARD_NUMBER      // -31305
PAYME_ERROR_CODES.INVALID_CARD_EXPIRY      // -31306
PAYME_ERROR_CODES.CARD_NOT_SUPPORTED       // -31307
PAYME_ERROR_CODES.CARD_LIMIT_EXCEEDED      // -31308
PAYME_ERROR_CODES.TOO_MANY_ATTEMPTS        // -31309
PAYME_ERROR_CODES.CARD_ALREADY_EXISTS      // -31310

Receipt Errors

typescript
// Receipt errors (range: -31400 to -31405)
PAYME_ERROR_CODES.RECEIPT_NOT_FOUND        // -31400
PAYME_ERROR_CODES.RECEIPT_ALREADY_PAID     // -31401
PAYME_ERROR_CODES.RECEIPT_CANCELLED        // -31402
PAYME_ERROR_CODES.INVALID_RECEIPT_STATE    // -31403
PAYME_ERROR_CODES.RECEIPT_EXPIRED          // -31404
PAYME_ERROR_CODES.INVALID_RECEIPT_AMOUNT   // -31405

Fiscal Errors

typescript
// Fiscal errors
PAYME_ERROR_CODES.FISCAL_CHECK_NOT_FOUND   // -32001
PAYME_ERROR_CODES.FISCAL_MODULE_ERROR      // -32002
PAYME_ERROR_CODES.FISCAL_DATA_INVALID      // -32003

Error Logging

Structured Error Logging

typescript
import { PaymeError, PAYME_ERROR_CODES, getErrorMessage } from '@joyida/payme';

function logPaymeError(error: PaymeError, context: Record<string, unknown>) {
  const logEntry = {
    timestamp: new Date().toISOString(),
    errorCode: error.code,
    errorMessage: error.message,
    errorDescription: getErrorMessage(error.code),
    context,
    isRetryable: isRetryableError(error.code)
  };
  
  console.error(JSON.stringify(logEntry));
}

function isRetryableError(code: number): boolean {
  // Network and temporary errors are retryable
  return [
    PAYME_ERROR_CODES.TRANSPORT_ERROR,
    PAYME_ERROR_CODES.INTERNAL_ERROR
  ].includes(code);
}

// Usage
try {
  await payme.createTransaction(params);
} catch (error) {
  if (error instanceof PaymeError) {
    logPaymeError(error, {
      operation: 'createTransaction',
      orderId: params.account.order_id,
      amount: params.amount
    });
  }
}

Best Practices

✅ Do's

  1. Use constants instead of magic numbers

    typescript
    // ✅ GOOD
    if (error.code === PAYME_ERROR_CODES.FORBIDDEN) {
      console.error('Invalid credentials');
    }
    
    // ❌ BAD
    if (error.code === -32504) {
      console.error('Invalid credentials');
    }
  2. Use getErrorMessage for user-friendly messages

    typescript
    // ✅ GOOD
    const message = getErrorMessage(error.code);
    showErrorToUser(message);
  3. Handle specific errors

    typescript
    // ✅ GOOD
    switch (error.code) {
      case PAYME_ERROR_CODES.CARD_EXPIRED:
        return 'Please update your card';
      case PAYME_ERROR_CODES.INSUFFICIENT_FUNDS:
        return 'Insufficient funds';
    }
  4. Log error codes for debugging

    typescript
    // ✅ GOOD
    console.error({
      code: error.code,
      message: getErrorMessage(error.code),
      context: { orderId, amount }
    });

❌ Don'ts

  1. Don't use magic numbers
  2. Don't ignore error codes
  3. Don't show technical errors to users
  4. Don't retry on non-retryable errors

Next Steps

Released under MIT License.