Skip to content

Kore Payment SDK Integration Guide

Overview

The Kore Payment SDK is a JavaScript library that enables frontend applications to integrate with the Kore Payment Platform. It provides a simple, secure, and developer-friendly interface for processing payments through various payment gateways.

Key Features

  • Unified Payment Flow - One integration path: the SDK handles redirect or embedded automatically based on backend response
  • Payment Session Creation - Create sessions with createEmbeddedSession; backend decides redirect vs embedded
  • Embedded Payment Forms - Payment forms embedded in your page when the gateway supports it
  • Automatic Gateway Detection - SDK detects gateway and either redirects or initializes the correct form
  • Multi-Gateway Support - Checkout.com, Adyen, and QiCard support
  • Redirect Handling - Handle payment redirects with signature verification
  • Status Polling - Poll payment status in real-time
  • Idempotency Support - Built-in idempotency key management
  • Error Handling - Comprehensive error handling with retry logic
  • TypeScript Support - Full TypeScript definitions included
  • Browser Compatibility - Support for modern browsers (ES6+)

Supported Environments

  • Production: https://api.kora.com
  • Sandbox: https://api-sandbox.kora.com (for testing)

Installation

Download the SDK (zip) from the Download page on this documentation site. Unzip and include the script in your project.

Script tag (browser):

html
<script src="path/to/kore-sdk.js"></script>

ES module (bundler):

html
<script type="module">
  import Kore from './path/to/kore-sdk.esm.js';
</script>

Quick Start

Use one flow for all gateways. The backend decides whether the customer is redirected or sees an embedded form; your code stays the same.

javascript
import Kore from './path/to/kore-sdk.esm.js';

const kore = new Kore({
  apiKey: 'pk_test_xxxxxxxxxxxxx',
  environment: 'sandbox'
});

// 1. Create payment session (same for redirect or embedded)
const session = await kore.createEmbeddedSession({
  order_id: 'order_12345',
  amount: 10000,
  currency: 'USD',
  capture_mode: 'auto',
  payer: {
    email: '[email protected]',
    name: 'John Doe',
    phone: '+1234567890'
  },
  billing: {
    address_line_1: '123 Main St',
    city: 'New York',
    state: 'NY',
    postal_code: '10001',
    country: 'US'
  },
  return_url: 'https://yourstore.com/success',
  cancel_url: 'https://yourstore.com/cancel'
});

// 2. Initialize payment — SDK redirects or shows embedded form automatically
await kore.initializePayment({
  session: session,
  container: '#payment-form-container',
  onSuccess: (result) => {
    console.log('Payment successful!', result);
    showSuccessMessage();
  },
  onError: (error) => {
    console.error('Payment failed:', error);
    showErrorMessage(error.message);
  }
});

Add a container for embedded flow (ignored when the SDK redirects):

html
<div id="payment-form-container"></div>

Handling Return From Redirect

When the gateway uses redirect, the customer returns to your return_url. On that page, verify the redirect and show the result:

javascript
// On your return URL page (e.g., /success)
const urlParams = new URLSearchParams(window.location.search);

// Verify redirect (API secret should come from server-side in production)
const result = await kore.handleRedirectReturn(urlParams, apiSecret);

if (result.success) {
  const { payment_id, order_id, status } = result.data;
  console.log(`Payment ${payment_id} for order ${order_id} is ${status}`);
  showSuccessMessage();
} else {
  const { code, message } = result.error;
  console.error(`Payment failed: ${code} - ${message}`);
  showErrorMessage(message);
}

Configuration

SDK Initialization Options

javascript
const kore = new Kore({
  // Required
  apiKey: 'pk_test_xxxxxxxxxxxxx',
  
  // Optional
  baseUrl: 'https://api.kora.com',        // Custom API base URL
  environment: 'sandbox',                  // 'sandbox' | 'live' (default: 'live')
  timeout: 30000,                          // Request timeout in ms (default: 30000)
  retryAttempts: 3,                        // Number of retry attempts (default: 3)
  retryDelay: 1000,                        // Delay between retries in ms (default: 1000)
  
  // Hooks
  onError: (error) => {                    // Global error handler
    console.error('SDK Error:', error);
  },
  onRequest: (config) => {                 // Request interceptor
    console.log('Request:', config);
  },
  onResponse: (response) => {              // Response interceptor
    console.log('Response:', response);
  },
  
  // Logging
  debug: false,                            // Enable debug logging (development only; do not use in production)
  logger: (message) => console.log(message) // Custom logger function
});

Environment Variables

For security, store your API keys in environment variables:

javascript
// .env file (never commit this)
REACT_APP_KORA_API_KEY=pk_test_xxxxxxxxxxxxx
REACT_APP_KORA_ENV=sandbox

// In your code
const kore = new Kore({
  apiKey: process.env.REACT_APP_KORA_API_KEY,
  environment: process.env.REACT_APP_KORA_ENV
});

API Reference

Core Methods

createSession(sessionData, options)

Creates a new payment session.

Parameters:

typescript
sessionData: {
  order_id: string,              // Required: Unique order identifier
  amount: number,                // Required: Amount in minor units (e.g., 10000 = $100.00)
  currency: string,              // Required: ISO-4217 currency code (e.g., 'USD')
  capture_mode?: 'auto' | 'manual', // Optional: Default 'auto'
  payer: {                       // Required
    email: string,
    name: string,
    phone?: string
  },
  billing: {                     // Required
    address_line_1: string,
    address_line_2?: string,
    city: string,
    state?: string,
    postal_code: string,
    country: string              // ISO-3166-1 alpha-2 (e.g., 'US')
  },
  shipping?: {                   // Optional
    address_line_1: string,
    address_line_2?: string,
    city: string,
    state?: string,
    postal_code: string,
    country: string,
    name?: string,
    phone?: string
  },
  return_url: string,            // Required: URL to redirect after payment
  cancel_url: string,            // Required: URL to redirect on cancellation
  metadata?: object              // Optional: Additional metadata
}

options: {
  idempotencyKey?: string,       // Optional: Custom idempotency key
  timeout?: number               // Optional: Request timeout in ms
}

Returns:

typescript
{
  session_id: string,
  payment_id: string,
  redirect_url: string,
  expires_at: string             // ISO 8601 timestamp
}

Example:

javascript
const session = await kore.createSession({
  order_id: 'order_12345',
  amount: 10000,
  currency: 'USD',
  payer: {
    email: '[email protected]',
    name: 'John Doe'
  },
  billing: {
    address_line_1: '123 Main St',
    city: 'New York',
    postal_code: '10001',
    country: 'US'
  },
  return_url: 'https://yourstore.com/success',
  cancel_url: 'https://yourstore.com/cancel'
}, {
  idempotencyKey: Kore.generateIdempotencyKey()
});

getSessionStatus(sessionId)

Gets the current status of a payment session.

Parameters:

typescript
sessionId: string  // Session ID from createSession

Returns:

typescript
{
  session_id: string,
  status: 'pending' | 'requires_action' | 'redirected' | 'completed' | 'failed',
  payment_id: string | null,
  order_id: string,
  amount: number,
  currency: string,
  created_at: string,
  expires_at: string
}

Example:

javascript
const status = await kore.getSessionStatus('session_12345');
console.log(`Session status: ${status.status}`);

getTransaction(paymentId)

Gets detailed transaction information.

Parameters:

typescript
paymentId: string | number  // Payment ID

Returns:

typescript
{
  payment_id: string,
  order_id: string,
  amount: number,
  currency: string,
  status: 'pending' | 'authorized' | 'captured' | 'failed' | 'refunded' | 'partial_refunded' | 'canceled',
  gateway: {
    id: number,
    code: string,
    name: string
  } | null,
  gateway_payment_id: string | null,
  authorized_at: string | null,
  captured_at: string | null,
  failed_at: string | null,
  failure_reason: string | null,
  created_at: string,
  updated_at: string
}

Example:

javascript
const transaction = await kore.getTransaction('payment_12345');
console.log(`Transaction status: ${transaction.status}`);

handleRedirectReturn(urlParams, apiSecret)

Handles redirect return from payment gateway with signature verification.

Parameters:

typescript
urlParams: URLSearchParams | Record<string, string>  // URL search parameters
apiSecret: string                                    // Merchant API secret (server-side recommended)

Returns:

typescript
{
  success: boolean,
  data?: {
    payment_id: string,
    order_id: string,
    status: 'captured' | 'authorized' | 'failed' | 'canceled' | 'pending',
    gateway?: string
  },
  error?: {
    code: string,
    message: string,
    payment_id?: string,
    order_id?: string,
    gateway?: string
  }
}

Example:

javascript
const urlParams = new URLSearchParams(window.location.search);
const result = await kore.handleRedirectReturn(urlParams, apiSecret);

if (result.success) {
  // Handle success
} else {
  // Handle error
  console.error(result.error.code, result.error.message);
}

redirectToPayment(redirectUrl, options)

Redirects the browser to the payment gateway.

Parameters:

typescript
redirectUrl: string  // URL from createSession response
options: {
  target?: '_self' | '_blank'  // Window target (default: '_self')
}

Example:

javascript
kore.redirectToPayment(session.redirect_url);
// Or open in new window
kore.redirectToPayment(session.redirect_url, { target: '_blank' });

pollPaymentStatus(sessionId, options)

Polls payment status until completion or failure.

Parameters:

typescript
sessionId: string
options: {
  interval?: number,                    // Polling interval in ms (default: 2000)
  maxAttempts?: number,                // Maximum polling attempts (default: 30)
  onStatusChange?: (status) => void    // Callback on status change
}

Returns:

typescript
Promise<SessionStatus>  // Final session status

Example:

javascript
const finalStatus = await kore.pollPaymentStatus('session_12345', {
  interval: 2000,
  maxAttempts: 30,
  onStatusChange: (status) => {
    console.log(`Status changed to: ${status.status}`);
  }
});

Utility Methods

Kore.generateIdempotencyKey()

Generates a UUID v4 string for use as an idempotency key.

Example:

javascript
const idempotencyKey = Kore.generateIdempotencyKey();

Kore.formatAmount(amount, currency)

Formats amount in minor units to display format.

Example:

javascript
const formatted = Kore.formatAmount(10000, 'USD');  // Returns: '$100.00'

Kore.validateCurrency(currency)

Validates ISO-4217 currency code.

Example:

javascript
Kore.validateCurrency('USD');  // Returns: true
Kore.validateCurrency('INVALID');  // Returns: false

Kore.validateEmail(email)

Validates email format.

Example:

javascript
Kore.validateEmail('[email protected]');  // Returns: true
Kore.validateEmail('invalid');  // Returns: false

Error Codes

Access error code constants via Kore.ErrorCodes:

javascript
// SDK Errors
Kore.ErrorCodes.AUTHENTICATION_ERROR
Kore.ErrorCodes.VALIDATION_ERROR
Kore.ErrorCodes.PAYMENT_ERROR
Kore.ErrorCodes.NETWORK_ERROR
Kore.ErrorCodes.RATE_LIMIT_ERROR
Kore.ErrorCodes.NOT_FOUND_ERROR
Kore.ErrorCodes.SERVER_ERROR

// Redirect Errors
Kore.ErrorCodes.SESSION_NOT_FOUND
Kore.ErrorCodes.PAYMENT_NOT_FOUND
Kore.ErrorCodes.GATEWAY_NOT_AVAILABLE
Kore.ErrorCodes.GATEWAY_CREDENTIALS_ERROR
Kore.ErrorCodes.GATEWAY_ADAPTER_ERROR
Kore.ErrorCodes.GATEWAY_SESSION_CREATION_FAILED
Kore.ErrorCodes.GATEWAY_VERIFICATION_FAILED
Kore.ErrorCodes.GATEWAY_TIMEOUT
Kore.ErrorCodes.NO_ACTIVE_API_KEY
Kore.ErrorCodes.RESOURCE_NOT_FOUND
Kore.ErrorCodes.BAD_REQUEST
Kore.ErrorCodes.FORBIDDEN
Kore.ErrorCodes.INTERNAL_ERROR
Kore.ErrorCodes.UNKNOWN_ERROR

Payment Flow

Use a single integration path for all gateways. You always call createEmbeddedSession and then initializePayment. The backend decides whether the gateway uses redirect or embedded; the SDK behaves accordingly.

What happens:

  • Redirect: If the backend returns gateway_config.mode === 'redirect' and a redirectUrl, the SDK redirects the customer to the gateway payment page. You handle the return on your return_url with handleRedirectReturn.
  • Embedded: If the backend returns an embedded gateway (Checkout.com, Adyen, or QiCard), the SDK loads the right form and mounts it in your container. Completion is reported via onSuccess / onError.
1. User fills payment form on your website
2. Frontend calls createEmbeddedSession()
3. Backend returns session (redirect URL or gateway_config for embedded)
4. Frontend calls initializePayment({ session, container, onSuccess, onError })
5. SDK either redirects the user or renders the payment form in the container
6. If redirect: user completes payment on gateway page, returns to return_url; use handleRedirectReturn()
7. If embedded: user completes payment in your page; onSuccess/onError are called

Complete example (unified):

javascript
// Step 1: Create payment session (same for redirect or embedded)
const session = await kore.createEmbeddedSession({
  order_id: `order_${Date.now()}`,
  amount: 10000,
  currency: 'USD',
  capture_mode: 'auto',
  payer: {
    email: '[email protected]',
    name: 'John Doe',
    phone: '+1234567890'
  },
  billing: {
    address_line_1: '123 Main St',
    address_line_2: 'Apt 4B',
    city: 'New York',
    state: 'NY',
    postal_code: '10001',
    country: 'US'
  },
  return_url: 'https://yourstore.com/success',
  cancel_url: 'https://yourstore.com/cancel',
  processing_channel_id: 'pc_xxxxx'  // Optional: Checkout.com only
});

// Step 2: Initialize payment — SDK redirects or shows embedded form
await kore.initializePayment({
  session: session,
  container: '#payment-form-container',
  onSuccess: (result) => {
    console.log('Payment successful!', result);
    updateOrderStatus(result.session?.order_id, 'paid');
    showSuccessMessage();
  },
  onError: (error) => {
    console.error('Payment failed:', error);
    handlePaymentError(error);
    showErrorMessage(error.message);
  }
});
html
<div id="payment-form-container"></div>

Benefits:

  • One integration for all gateways
  • No need to choose redirect vs embedded in your code
  • Automatic gateway detection and form loading for embedded
  • Automatic redirect when the backend returns a redirect URL

Legacy: Redirect-Only API

If you only need redirect and use the legacy sessions API, you can call createSession (V1) and then redirectToPayment:

javascript
const session = await kore.createSession({
  order_id: `order_${Date.now()}`,
  amount: 10000,
  currency: 'USD',
  payer: { email: '[email protected]', name: 'John Doe' },
  billing: { address_line_1: '123 Main St', city: 'New York', postal_code: '10001', country: 'US' },
  return_url: 'https://yourstore.com/success',
  cancel_url: 'https://yourstore.com/cancel'
});
kore.redirectToPayment(session.redirect_url);

On your return URL page, use handleRedirectReturn() as described in Handling Return From Redirect. For new integrations, prefer the unified flow with createEmbeddedSession + initializePayment.


Error Handling

Error Classes

The SDK provides specific error classes for different error types:

javascript
import {
  KoraError,
  KoreAuthenticationError,
  KoreValidationError,
  KorePaymentError,
  KoreNetworkError,
  KoreRateLimitError,
  KoreNotFoundError,
  KoreServerError
} from 'kora-payment-sdk';

try {
  await kore.createEmbeddedSession(sessionData);
} catch (error) {
  if (error instanceof KoreAuthenticationError) {
    // Handle authentication error
    console.error('Invalid API key');
  } else if (error instanceof KoreValidationError) {
    // Handle validation error
    console.error('Invalid request:', error.details);
  } else if (error instanceof KoreNetworkError) {
    // Handle network error
    console.error('Network issue, please retry');
  } else {
    // Handle other errors
    console.error('Unexpected error:', error);
  }
}

Redirect Error Handling

When handling redirect returns, check the error code:

javascript
const result = await kore.handleRedirectReturn(urlParams, apiSecret);

if (!result.success) {
  const { code, message } = result.error;
  
  // Handle specific error codes
  switch (code) {
    case Kore.ErrorCodes.GATEWAY_SESSION_CREATION_FAILED:
    case Kore.ErrorCodes.GATEWAY_TIMEOUT:
      // Retryable errors - show retry button
      showRetryButton();
      break;
      
    case Kore.ErrorCodes.GATEWAY_CREDENTIALS_ERROR:
    case Kore.ErrorCodes.NO_ACTIVE_API_KEY:
      // Configuration errors - contact support
      showContactSupport();
      break;
      
    case Kore.ErrorCodes.SESSION_NOT_FOUND:
      // Session expired - redirect to create new session
      redirectToCreateSession();
      break;
      
    default:
      // Generic error handling
      showErrorMessage(message);
  }
}

Error Code Reference

SDK Error Codes

CodeDescriptionAction
AUTHENTICATION_ERRORInvalid or missing API keyCheck API key configuration
VALIDATION_ERRORInvalid request parametersReview request data
PAYMENT_ERRORPayment processing errorCheck payment details
NETWORK_ERRORNetwork/connection errorRetry request
RATE_LIMIT_ERRORRate limit exceededWait and retry
NOT_FOUND_ERRORResource not foundCheck resource ID
SERVER_ERRORServer errorContact support

Redirect Error Codes

CodeDescriptionAction
SESSION_NOT_FOUNDPayment session not found or expiredCreate new session
PAYMENT_NOT_FOUNDPayment record not foundCheck payment ID
GATEWAY_NOT_AVAILABLEGateway is not activeContact support
GATEWAY_CREDENTIALS_ERRORGateway credentials invalidContact support
GATEWAY_ADAPTER_ERRORGateway adapter failedContact support
GATEWAY_SESSION_CREATION_FAILEDFailed to create gateway sessionRetry payment
GATEWAY_VERIFICATION_FAILEDFailed to verify paymentContact support
GATEWAY_TIMEOUTGateway request timed outRetry payment
NO_ACTIVE_API_KEYNo active API keyContact support
RESOURCE_NOT_FOUNDResource not foundCheck resource ID
BAD_REQUESTInvalid requestReview request data
FORBIDDENAccess deniedCheck permissions
INTERNAL_ERRORServer errorContact support
UNKNOWN_ERRORUnknown errorContact support

Examples

Unified Payment Flow (React)

jsx
import { useState } from 'react';
import Kore from './path/to/kore-sdk.esm.js';

function EmbeddedPayment() {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const kore = new Kore({ 
    apiKey: process.env.REACT_APP_KORA_API_KEY,
    environment: 'sandbox'
  });

  const handlePayment = async () => {
    setLoading(true);
    setError(null);

    try {
      // Step 1: Create embedded payment session
      const session = await kore.createEmbeddedSession({
        order_id: `order_${Date.now()}`,
        amount: 10000,
        currency: 'USD',
        capture_mode: 'auto',
        payer: {
          email: '[email protected]',
          name: 'John Doe'
        },
        billing: {
          address_line_1: '123 Main St',
          city: 'New York',
          postal_code: '10001',
          country: 'US'
        },
        return_url: window.location.origin + '/success',
        cancel_url: window.location.origin + '/cancel'
      });

      // Step 2: Initialize payment form
      await kore.initializePayment({
        session: session,
        container: '#payment-container',
        onSuccess: (result) => {
          console.log('Payment successful!', result);
          setLoading(false);
          // Handle success
        },
        onError: (err) => {
          setError(err.message);
          setLoading(false);
        }
      });
    } catch (err) {
      setError(err.message);
      setLoading(false);
    }
  };

  return (
    <div>
      <button onClick={handlePayment} disabled={loading}>
        {loading ? 'Processing...' : 'Pay Now'}
      </button>
      {error && <div className="error">{error}</div>}
      <div id="payment-container"></div>
    </div>
  );
}

Handling Return From Redirect (React)

jsx
import { useState, useEffect } from 'react';
import { useSearchParams } from 'react-router-dom';
import Kore from './path/to/kore-sdk.esm.js';

function PaymentForm() {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const kore = new Kore({ 
    apiKey: process.env.REACT_APP_KORA_API_KEY 
  });

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    setError(null);

    try {
      const session = await kore.createSession({
        order_id: `order_${Date.now()}`,
        amount: 10000,
        currency: 'USD',
        payer: {
          email: e.target.email.value,
          name: e.target.name.value
        },
        billing: {
          address_line_1: e.target.address.value,
          city: e.target.city.value,
          postal_code: e.target.zip.value,
          country: e.target.country.value
        },
        return_url: window.location.origin + '/success',
        cancel_url: window.location.origin + '/cancel'
      });

      kore.redirectToPayment(session.redirect_url);
    } catch (err) {
      setError(err.message);
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
      {error && <div className="error">{error}</div>}
      <button type="submit" disabled={loading}>
        {loading ? 'Processing...' : 'Pay Now'}
      </button>
    </form>
  );
}

// Payment Return Handler Component
function PaymentReturn() {
  const [searchParams] = useSearchParams();
  const [result, setResult] = useState(null);
  const [loading, setLoading] = useState(true);
  const kore = new Kore({ 
    apiKey: process.env.REACT_APP_KORA_API_KEY 
  });

  useEffect(() => {
    const handleReturn = async () => {
      // Get API secret from server (recommended)
      const apiSecret = await fetch('/api/get-secret').then(r => r.text());
      
      try {
        const result = await kore.handleRedirectReturn(searchParams, apiSecret);
        setResult(result);
      } catch (err) {
        setResult({
          success: false,
          error: {
            code: 'SIGNATURE_VERIFICATION_FAILED',
            message: 'Failed to verify redirect signature'
          }
        });
      } finally {
        setLoading(false);
      }
    };

    handleReturn();
  }, [searchParams]);

  if (loading) return <div>Processing payment...</div>;

  if (result?.success) {
    return (
      <div className="success">
        <h2>Payment Successful!</h2>
        <p>Payment ID: {result.data.payment_id}</p>
        <p>Order ID: {result.data.order_id}</p>
      </div>
    );
  }

  return (
    <div className="error">
      <h2>Payment Failed</h2>
      <p>{result?.error?.message}</p>
    </div>
  );
}

Vue.js Integration

vue
<template>
  <div>
    <form @submit.prevent="handleSubmit">
      <!-- Form fields -->
      <button type="submit" :disabled="loading">
        {{ loading ? 'Processing...' : 'Pay Now' }}
      </button>
    </form>
  </div>
</template>

<script>
import { ref } from 'vue';
import Kore from './path/to/kore-sdk.esm.js';

export default {
  setup() {
    const loading = ref(false);
    const error = ref(null);
    const kore = new Kore({
      apiKey: import.meta.env.VITE_KORA_API_KEY
    });

    const handleSubmit = async () => {
      loading.value = true;
      error.value = null;

      try {
        const session = await kore.createSession({
          order_id: `order_${Date.now()}`,
          amount: 10000,
          currency: 'USD',
          payer: {
            email: '[email protected]',
            name: 'John Doe'
          },
          billing: {
            address_line_1: '123 Main St',
            city: 'New York',
            postal_code: '10001',
            country: 'US'
          },
          return_url: window.location.origin + '/success',
          cancel_url: window.location.origin + '/cancel'
        });

        kore.redirectToPayment(session.redirect_url);
      } catch (err) {
        error.value = err.message;
        loading.value = false;
      }
    };

    return { loading, error, handleSubmit };
  }
};
</script>

Vanilla JavaScript

javascript
// Initialize SDK
const kore = new Kore({
  apiKey: 'pk_test_xxxxxxxxxxxxx',
  environment: 'sandbox'
});

// Handle form submission
document.getElementById('paymentForm').addEventListener('submit', async (e) => {
  e.preventDefault();
  
  try {
    const session = await kore.createSession({
      order_id: document.getElementById('orderId').value,
      amount: parseInt(document.getElementById('amount').value),
      currency: document.getElementById('currency').value,
      payer: {
        email: document.getElementById('email').value,
        name: document.getElementById('name').value
      },
      billing: {
        address_line_1: document.getElementById('address').value,
        city: document.getElementById('city').value,
        postal_code: document.getElementById('zip').value,
        country: document.getElementById('country').value
      },
      return_url: window.location.origin + '/success',
      cancel_url: window.location.origin + '/cancel'
    });

    kore.redirectToPayment(session.redirect_url);
  } catch (error) {
    alert('Error: ' + error.message);
  }
});

// Handle return from payment gateway
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('status')) {
  // Get API secret from server
  const apiSecret = await fetch('/api/get-secret').then(r => r.text());
  
  const result = await kore.handleRedirectReturn(urlParams, apiSecret);
  
  if (result.success) {
    document.getElementById('result').innerHTML = 
      `Payment successful! Payment ID: ${result.data.payment_id}`;
  } else {
    document.getElementById('result').innerHTML = 
      `Payment failed: ${result.error.message}`;
  }
}

Security Best Practices

1. API Key Management

❌ Never do this:

javascript
// DON'T: Hardcode API keys in frontend code
const kore = new Kore({
  apiKey: 'pk_live_secret_key_12345'  // Exposed in client-side code!
});

✅ Do this:

javascript
// DO: Use environment variables
const kore = new Kore({
  apiKey: process.env.REACT_APP_KORA_API_KEY  // From .env file
});

2. API Secret Handling

❌ Never do this:

javascript
// DON'T: Store API secret in frontend
const apiSecret = 'sk_live_secret_12345';  // Never expose secrets!

✅ Do this:

javascript
// DO: Retrieve API secret from your backend server
const apiSecret = await fetch('/api/get-secret', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${userToken}` }
}).then(r => r.text());

// Or verify signature server-side
const result = await fetch('/api/verify-payment', {
  method: 'POST',
  body: JSON.stringify({ urlParams: Object.fromEntries(urlParams) })
}).then(r => r.json());

3. Signature Verification

Always verify redirect signatures:

javascript
// Frontend: Get redirect parameters
const urlParams = new URLSearchParams(window.location.search);

// Option 1: Verify client-side (less secure, requires API secret)
const result = await kore.handleRedirectReturn(urlParams, apiSecret);

// Option 2: Verify server-side (recommended)
const result = await fetch('/api/verify-payment', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    payment_id: urlParams.get('payment_id'),
    order_id: urlParams.get('order_id'),
    status: urlParams.get('status'),
    signature: urlParams.get('signature')
  })
}).then(r => r.json());

4. HTTPS Only

Always use HTTPS in production:

javascript
// Check for HTTPS
if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost') {
  console.error('SDK requires HTTPS in production');
}

5. Input Validation

Validate all user inputs:

javascript
// Validate email
if (!Kore.validateEmail(formData.email)) {
  throw new Error('Invalid email address');
}

// Validate currency
if (!Kore.validateCurrency(formData.currency)) {
  throw new Error('Invalid currency code');
}

// Validate amount
if (formData.amount <= 0 || !Number.isInteger(formData.amount)) {
  throw new Error('Invalid amount');
}

6. Error Message Handling

Don't expose sensitive information:

javascript
try {
  await kore.createEmbeddedSession(sessionData);
} catch (error) {
  // ❌ DON'T: Expose internal error details
  // console.error(error.details);
  
  // ✅ DO: Show user-friendly messages
  if (error instanceof KoreAuthenticationError) {
    showError('Authentication failed. Please contact support.');
  } else {
    showError('Payment processing failed. Please try again.');
  }
}

Troubleshooting

Common Issues

1. "API key is required" Error

Problem: SDK initialization fails with API key error.

Solution:

  • Ensure API key is provided in configuration
  • Check that API key starts with pk_test_ or pk_live_
  • Verify environment variables are loaded correctly
javascript
// Debug API key
console.log('API Key:', process.env.REACT_APP_KORA_API_KEY?.substring(0, 10) + '...');

2. Signature Verification Fails

Problem: handleRedirectReturn returns SIGNATURE_VERIFICATION_FAILED.

Solution:

  • Ensure API secret is correct (not API key)
  • Verify signature is included in URL parameters
  • Check that all required parameters are present
  • Verify signature verification is done server-side when possible
javascript
// Debug redirect parameters
console.log('Redirect params:', Object.fromEntries(urlParams));

3. Network Errors

Problem: Requests fail with network errors.

Solution:

  • Check internet connection
  • Verify API base URL is correct
  • Check CORS settings if making requests from browser
  • Increase timeout if needed
javascript
const kore = new Kore({
  apiKey: 'pk_test_xxx',
  timeout: 60000  // Increase timeout to 60 seconds
});

4. Session Expired

Problem: SESSION_NOT_FOUND error when handling redirect.

Solution:

  • Sessions expire after a certain time
  • Create a new session if expired
  • Store session ID and check expiration time
javascript
// Check session expiration
const session = await kore.createEmbeddedSession(sessionData);
const expiresAt = new Date(session.expires_at);

if (new Date() > expiresAt) {
  // Session expired, create new one
  const newSession = await kore.createEmbeddedSession(sessionData);
}

5. CORS Issues

Problem: CORS errors when making API requests.

Solution:

  • Ensure your domain is whitelisted in Kore dashboard
  • Use proper CORS headers on your backend
  • Consider using a backend proxy for API calls

Debug Mode

Enable debug mode to see detailed logs:

javascript
const kore = new Kore({
  apiKey: 'pk_test_xxx',
  debug: true,
  logger: (message) => {
    console.log('[Kore SDK]', message);
  }
});

Getting Help

If you encounter issues:

  1. Check Error Codes: Use Kore.ErrorCodes to identify specific errors
  2. Enable Debug Mode: Set debug: true to see detailed logs
  3. Review Documentation: Check this guide and API reference
  4. Contact Support: Reach out to Kore support with:
    • Error code and message
    • Request/response details (with sensitive data redacted)
    • Steps to reproduce

FAQ

Q: Can I use the SDK in Node.js?

A: The SDK is designed for browser environments. For Node.js, use the backend API directly or create a server-side wrapper.

Q: How do I handle webhooks?

A: Webhooks should be handled on your backend server. The SDK focuses on frontend payment flows.

Q: Can I customize the payment UI?

A: The SDK redirects to gateway-hosted payment pages. UI customization depends on the gateway provider.

Q: How do I test payments?

A: Use the sandbox environment with test API keys. Test cards are provided in the Kore dashboard.

Q: What currencies are supported?

A: Support depends on your account configuration. Check with Kora support for available currencies.

Q: How do I handle refunds?

A: Refunds are handled through the backend API, not the frontend SDK. Contact your backend team or use the Kore API directly.

Q: Is the SDK PCI compliant?

A: The SDK doesn't handle card data directly. Card data is processed by gateway-hosted pages, which are PCI compliant.

Q: Can I use multiple payment gateways?

A: Yes, Kore handles gateway routing automatically based on your configuration.


Additional Resources


Changelog

Version 1.0.0

  • Initial release
  • Payment session creation
  • Redirect handling with signature verification
  • Error code system
  • TypeScript support

Last Updated: SDK Version: 1.0.0