Skip to content

Authentication Guide

Understanding authentication in Payme API.

Overview

Payme uses two different authentication methods:

  1. Merchant API: Basic Authentication with Base64 encoding
  2. Subscribe API: X-Auth header with merchant ID and password

Merchant API Authentication

How It Works

The Merchant API uses HTTP Basic Authentication:

Authorization: Basic base64(Paycom:SECRET_KEY)

Manual Implementation

typescript
const merchantId = 'your_merchant_id';
const secretKey = 'your_secret_key';

// Create auth string
const authString = `Paycom:${secretKey}`;

// Encode to Base64
const authHeader = `Basic ${Buffer.from(authString).toString('base64')}`;

// Use in request
const response = await fetch('https://checkout.paycom.uz/api', {
  method: 'POST',
  headers: {
    'Authorization': authHeader,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'CheckPerformTransaction',
    params: {
      amount: 500000,
      account: { order_id: 'ORD-123' }
    }
  })
});

Using PaymeMerchant

The library handles authentication automatically:

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

const payme = new PaymeMerchant({
  merchantId: 'your_merchant_id',
  secretKey: 'your_secret_key'
});

// Authentication is handled automatically
await payme.checkPerformTransaction({
  amount: 500000,
  account: { order_id: 'ORD-123' }
});

Subscribe API Authentication

How It Works

The Subscribe API uses X-Auth header with different formats for client and server modes:

Client Mode (card tokenization):

X-Auth: MERCHANT_ID

Server Mode (card management and receipts):

X-Auth: MERCHANT_ID:PASSWORD

Manual Implementation

typescript
const merchantId = 'your_merchant_id';
const password = 'your_password';

// Client mode (card tokenization)
const clientAuthHeader = merchantId;

// Server mode (card management and receipts)
const serverAuthHeader = `${merchantId}:${password}`;

// Use in request
const response = await fetch('https://checkout.paycom.uz/api', {
  method: 'POST',
  headers: {
    'X-Auth': serverAuthHeader,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'cards.check',
    params: {
      token: 'card_token_here'
    }
  })
});

Using PaymeSubscribe

The library handles authentication automatically:

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

// Client mode (only merchant ID needed)
const subscribeClient = new PaymeSubscribe({
  merchantId: 'your_merchant_id'
}, 'client');

// Server mode (merchant ID and password needed)
const subscribeServer = new PaymeSubscribe({
  merchantId: 'your_merchant_id',
  password: 'your_password'
}, 'server');

// Authentication is handled automatically
await subscribeClient.cardsCreate({
  card: { number: '8600069195406311', expire: '0399' },
  save: true
});

await subscribeServer.cardsCheck({
  token: 'card_token_here'
});

Auth Helper Functions

The library provides standalone auth functions for advanced use cases:

createBasicAuth

Creates Basic auth header for Merchant API:

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

const header = createBasicAuth('my_secret_key');
// Returns: "Basic UGF5Y29tOm15U2VjcmV0S2V5"

createXAuth

Creates X-Auth header for Subscribe API:

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

// Client mode
const clientHeader = createXAuth('merchant_id', undefined, 'client');
// Returns: "merchant_id"

// Server mode
const serverHeader = createXAuth('merchant_id', 'password', 'server');
// Returns: "merchant_id:password"

Deprecated: AuthManager Class

Deprecation Notice

The AuthManager class is deprecated and will be removed in version 0.5.0. Please use the named auth functions instead.

Migration:

typescript
// ❌ Old (deprecated)
import { AuthManager } from '@joyida/payme';
AuthManager.createBasicAuth('secret');

// ✅ New (recommended)
import { createBasicAuth } from '@joyida/payme';
createBasicAuth('secret');

Getting Credentials

Merchant ID and Secret Key

  1. Log in to Payme Business
  2. Go to SettingsAPI
  3. Find your Merchant ID
  4. Generate or view your Secret Key

Subscribe API Password

  1. Log in to Payme Business
  2. Go to SettingsSubscribe API
  3. Generate or view your Password

Security Best Practices

✅ Do's

  1. Store credentials securely

    typescript
    // Use environment variables
    const payme = new PaymeMerchant({
      merchantId: process.env.PAYME_MERCHANT_ID!,
      secretKey: process.env.PAYME_SECRET_KEY!
    });
  2. Use different credentials for test and production

    typescript
    const isDevelopment = process.env.NODE_ENV === 'development';
    
    const payme = new PaymeMerchant({
      merchantId: isDevelopment 
        ? process.env.PAYME_MERCHANT_ID_TEST!
        : process.env.PAYME_MERCHANT_ID!,
      secretKey: isDevelopment
        ? process.env.PAYME_SECRET_KEY_TEST!
        : process.env.PAYME_SECRET_KEY!
    });
  3. Rotate credentials regularly

    • Change secret keys every 3-6 months
    • Update immediately if compromised
  4. Use HTTPS only

    typescript
    const payme = new PaymeMerchant({
      merchantId: 'your_merchant_id',
      secretKey: 'your_secret_key',
      baseURL: 'https://checkout.paycom.uz/api' // ✅ HTTPS
    });
  5. Restrict access to credentials

    • Use environment variables
    • Don't commit to version control
    • Use secret management services

❌ Don'ts

  1. Never hardcode credentials

    typescript
    // ❌ BAD
    const payme = new PaymeMerchant({
      merchantId: '5e730e8e0b852a417aa49ceb',
      secretKey: 'my_secret_key_123'
    });
    
    // ✅ GOOD
    const payme = new PaymeMerchant({
      merchantId: process.env.PAYME_MERCHANT_ID!,
      secretKey: process.env.PAYME_SECRET_KEY!
    });
  2. Never commit credentials to Git

    bash
    # .gitignore
    .env
    .env.local
    .env.production
  3. Never expose credentials in client-side code

    typescript
    // ❌ BAD - Never use Merchant API in browser
    const payme = new PaymeMerchant({
      merchantId: 'your_merchant_id',
      secretKey: 'your_secret_key' // ❌ Exposed to users!
    });
    
    // ✅ GOOD - Use Subscribe API client mode in browser
    const subscribe = new PaymeSubscribe({
      merchantId: 'your_merchant_id' // ✅ Safe to expose
    }, 'client');
  4. Never log credentials

    typescript
    // ❌ BAD
    console.log('Secret key:', process.env.PAYME_SECRET_KEY);
    
    // ✅ GOOD
    console.log('Payme client initialized');
  5. Never share credentials

    • Don't send via email or chat
    • Don't share between environments
    • Don't reuse across projects

Environment Variables

.env File

bash
# Development
PAYME_MERCHANT_ID_TEST=test_merchant_id
PAYME_SECRET_KEY_TEST=test_secret_key
PAYME_PASSWORD_TEST=test_password

# Production
PAYME_MERCHANT_ID=prod_merchant_id
PAYME_SECRET_KEY=prod_secret_key
PAYME_PASSWORD=prod_password

# Environment
NODE_ENV=development

Loading Environment Variables

typescript
// Bun loads .env when you run with: bun --env-file=.env run src/index.ts
const payme = new PaymeMerchant({
  secretKey: process.env.PAYME_SECRET_KEY!
});

Authentication Errors

Invalid Credentials

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

try {
  await payme.checkPerformTransaction(params);
} catch (error) {
  if (error instanceof PaymeError && error.code === -32504) {
    console.error('Invalid credentials');
    // Check merchantId and secretKey
  }
}

Missing Password (Subscribe API)

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

try {
  // ❌ Missing password for server mode
  const subscribe = new PaymeSubscribe({
    merchantId: 'your_merchant_id'
  }, 'server');
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Password required for server mode');
  }
}

Testing Authentication

Test Credentials

typescript
async function testAuthentication() {
  try {
    const payme = new PaymeMerchant({
      merchantId: process.env.PAYME_MERCHANT_ID!,
      secretKey: process.env.PAYME_SECRET_KEY!
    });
    
    // Try a simple request
    await payme.checkPerformTransaction({
      amount: 100,
      account: { test: 'test' }
    });
    
    console.log('✅ Authentication successful');
  } catch (error) {
    if (error instanceof PaymeError && error.code === -32504) {
      console.error('❌ Authentication failed: Invalid credentials');
    } else {
      console.error('❌ Authentication test failed:', error.message);
    }
  }
}

testAuthentication();

Next Steps

Released under MIT License.