kapital-bank-sdk
v1.4.0
Published
TypeScript SDK for Kapital Bank payment services
Maintainers
Readme
Kapital Bank SDK
TypeScript SDK for Kapital Bank Payment Gateway API.
Installation
npm install kapital-bank-sdkFeatures
- Environment-based configuration with
KapitalBank.fromEnv() - Default order settings from config or environment variables
createHostedPayment()— one-call HPP session (orderId,password,paymentUrl,order)- Google Pay via
GN3D/GSMS—createGooglePayOrder(),setGooglePayToken(),payWithGooglePay() restoreOrder()— resume an unfinished HPP order inPreparingstatus- Order status helpers (
isPreparing,isFullyPaid, and more) - Low-level
request()escape hatch for undocumented API endpoints - EventEmitter support (
payment:paid,payment:declined, and more) - Debug request logging via
KAPITALBANK_LOG_ENABLED - Hosted Payment Page (HPP) with
getPaymentUrl() - Payment monitoring (
waitForPayment,waitForStatus,watchOrder) - Create Order & Get Order Details
- Execute, Refund, and Reverse Transactions
- Set Source / Destination Token
- Recurring Payment Support
- Card Transfer Helper (OCT)
- PreAuthorization & Clearing Helpers
- Typed Error Handling (
KapitalBankError,WatchOrderTimeoutError) - Full TypeScript Support
- ESM & CommonJS Support
- Webhook Handler with signature verification
- Notification Services (Telegram, Discord)
- Automatic Retry with Exponential Backoff
- Health Check & API Monitoring
- Metrics & Performance Tracking
Quick Start
Create an order, open the payment page, wait until the customer pays.
Option A — Environment Variables
Copy the template and edit your credentials:
cp .env.example .env # Linux/macOS
copy .env.example .env # WindowsKAPITALBANK_MODE=test
KAPITALBANK_USERNAME=TerminalSys/kapital
KAPITALBANK_PASSWORD=kapital123
KAPITALBANK_ORDER_TYPE=Order_SMS
KAPITALBANK_GOOGLE_PAY_ORDER_TYPE=GSMS
KAPITALBANK_CURRENCY=AZN
KAPITALBANK_LANGUAGE=az
KAPITALBANK_REDIRECT_URL=https://your-site.com/callback
KAPITALBANK_LOG_ENABLED=trueExamples load .env automatically via examples/client.ts.
import { KapitalBank } from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();
const session = await kb.createHostedPayment({
amount: "1",
description: "Payment",
});
console.log(session.paymentUrl);
const result = await kb.waitForPayment(session.orderId, {
password: session.password,
});When env defaults are set, createOrder() and createHostedPayment() apply typeRid, currency, language, and hppRedirectUrl automatically.
Option B — Constructor Config
import { KapitalBank, getPaymentUrl } from "kapital-bank-sdk";
const kb = new KapitalBank({
username: "TerminalSys/kapital",
password: "kapital123",
environment: "test",
defaults: {
currency: "AZN",
language: "az",
hppRedirectUrl: "https://your-site.com/callback",
},
});
const order = await kb.createOrder({
typeRid: "Order_SMS",
amount: "1",
description: "Payment",
initiationEnvKind: "Browser",
hppCofCapturePurposes: ["Cit"],
});
const paymentUrl = getPaymentUrl(order);
console.log(paymentUrl);
const result = await kb.waitForPayment(order.id, {
password: order.password,
});
console.log(result.status);Important: Each
createOrder()call creates a new order. Redirect the customer to the URL from the same order you are monitoring.
Google Pay
Kapital Bank Google Pay uses dedicated order types on the same POST /order endpoint:
| Type | Description | Auth method |
| ------ | ----------------------------- | ---------------------- |
| GSMS | Google Pay purchase (default) | PAN_ONLY cards |
| GN3D | Google Pay with 3D Secure | CRYPTOGRAM_3DS cards |
Your curator may configure different typeRid mappings per terminal. Contact Kapital Bank to enable Google Pay on your merchant login.
Payment Flow
Google Pay uses a token-based server-side flow (not HPP):
Google Pay Button (Frontend)
↓
createGooglePayOrder() (Backend)
↓
Customer pays via Google Pay API
↓
Receive payment token JSON
↓
encodeGooglePayToken() - Convert to HEX
↓
setGooglePayToken() - Set token on order
↓
executeTransaction() - Process payment
↓
waitForPayment() - Monitor status (optional)Quick Start (One-Call)
The simplest way to process Google Pay:
import {
KapitalBank,
encodeGooglePayToken,
GOOGLE_PAY_GATEWAY,
} from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();
const gatewayConfig = {
gateway: GOOGLE_PAY_GATEWAY.gateway,
gatewayMerchantId: GOOGLE_PAY_GATEWAY.testGatewayMerchantId,
};
const googlePayBlock = encodeGooglePayToken(googlePayTokenJson);
const result = await kb.payWithGooglePay({
amount: "10",
description: "Google Pay Test",
googlePayBlock,
});
console.log("Order ID:", result.orderId);
console.log("Approval Code:", result.transaction.approvalCode);Advanced Flow (Step-by-Step)
For more control over the payment process:
import {
KapitalBank,
encodeGooglePayToken,
} from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();
const order = await kb.createGooglePayOrder({
amount: "10",
description: "Google Pay Test",
typeRid: "GSMS",
});
console.log("Order ID:", order.id);
const googlePayBlock = encodeGooglePayToken(googlePayTokenJson);
await kb.setGooglePayToken(order.id, order.password, {
googlePayBlock,
});
const transaction = await kb.executeTransaction(order.id, {
phase: "Single",
});
console.log("Transaction:", transaction);
const result = await kb.waitForPayment(order.id, {
password: order.password,
});
console.log("Final status:", result.status);Order Creation Only
If you need just the order (e.g., for custom token handling):
import { KapitalBank } from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();
const order = await kb.createGooglePayOrder({
amount: "10",
description: "Google Pay Test",
});
console.log("Order ID:", order.id);
console.log("Password:", order.password);Environment Configuration
KAPITALBANK_GOOGLE_PAY_ORDER_TYPE=GSMS
KAPITALBANK_CURRENCY=AZN
KAPITALBANK_LANGUAGE=az
KAPITALBANK_REDIRECT_URL=https://your-site.com/callbackOr via constructor:
const kb = new KapitalBank({
username: process.env.KAPITALBANK_USERNAME!,
password: process.env.KAPITALBANK_PASSWORD!,
environment: "test",
defaults: {
googlePayOrderType: "GSMS",
currency: "AZN",
language: "az",
hppRedirectUrl: "https://your-site.com/callback",
},
});Restore Order
Kapital Bank does not expose a separate "restore" HTTP endpoint. An unfinished HPP order in Preparing status can be resumed by rebuilding the payment URL from stored orderId and password.
restoreOrder() validates the status and returns a ready-to-redirect session:
import { KapitalBank, isPreparing } from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();
const details = await kb.getOrder(orderId, {
password,
});
if (isPreparing(details)) {
const session = await kb.restoreOrder(orderId, password);
console.log(session.paymentUrl);
}Only orders with status Preparing can be restored. Other statuses throw KapitalBankError with code InvalidOrderState.
Order Status Helpers
Tree-shakable utilities for common status checks:
import {
isPreparing,
isFullyPaid,
isDeclined,
isExpired,
isRefunded,
isReversed,
} from "kapital-bank-sdk";
if (isFullyPaid(order)) {}Custom API Requests
Use request() when you need an endpoint not yet wrapped by the SDK. Authentication and base URL are reused automatically:
const response = await kb.request<{ order: OrderDetails }>(
"GET",
`/order/${orderId}`,
undefined,
{ params: { password } },
);Hosted Payment Page (HPP)
createHostedPayment()
The simplest way to start an HPP flow:
const session = await kb.createHostedPayment({
amount: "10",
description: "Order",
});
console.log(session.order.status);See Quick Start for the full flow. Additional options:
const result = await kb.waitForStatus(order.id, "FullyPaid", {
password: order.password,
interval: 5000,
timeout: 300000,
});
const result = await kb.watchOrder(order.id, {
password: order.password,
});getPaymentUrl()
The API returns a base hppUrl. Build the full redirect URL with:
import { getPaymentUrl } from "kapital-bank-sdk";
const url = getPaymentUrl(order);Configuration
Environment Variables
| Variable | Required | Description |
| ----------------------------------- | -------- | -------------------------------------------- |
| KAPITALBANK_USERNAME | Yes | API username |
| KAPITALBANK_PASSWORD | Yes | API password |
| KAPITALBANK_MODE | No | test or production (default: test) |
| KAPITALBANK_TIMEOUT | No | HTTP timeout in milliseconds |
| KAPITALBANK_ORDER_TYPE | No | Default order type (e.g. Order_SMS) |
| KAPITALBANK_GOOGLE_PAY_ORDER_TYPE | No | Default Google Pay type: GSMS or GN3D |
| KAPITALBANK_CURRENCY | No | Default order currency (AZN, USD, EUR) |
| KAPITALBANK_LANGUAGE | No | Default order language (az, en, ru) |
| KAPITALBANK_REDIRECT_URL | No | Default hppRedirectUrl for HPP orders |
| KAPITALBANK_LOG_ENABLED | No | Log HTTP requests (true / false) |
import { KapitalBank } from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();You can also parse env vars manually:
import { KapitalBank, parseEnvConfig } from "kapital-bank-sdk";
const kb = new KapitalBank(parseEnvConfig());Constructor Defaults
const kb = new KapitalBank({
username: process.env.KAPITALBANK_USERNAME!,
password: process.env.KAPITALBANK_PASSWORD!,
environment: "test",
defaults: {
currency: "AZN",
language: "az",
hppRedirectUrl: "https://your-site.com/callback",
},
});Explicit createOrder() values always override configured defaults.
Debug Logging
When KAPITALBANK_LOG_ENABLED=true or logEnabled: true:
[KapitalBank]
POST /order
[KapitalBank]
GET /order/233266Events
KapitalBank extends Node.js EventEmitter with typed payment events:
kb.on("payment:paid", (order) => {
console.log("Paid:", order.id);
});
kb.on("payment:declined", (order) => {
console.log("Declined:", order.id);
});
kb.on("payment:status", (order) => {
console.log("Status:", order.status);
});
const session = await kb.createHostedPayment({
amount: "1",
description: "Bot payment",
});
await kb.waitForPayment(session.orderId, {
password: session.password,
});| Event | When |
| ------------------ | ----------------------------------------------------------- |
| order:created | After createOrder() |
| payment:created | After createHostedPayment() |
| payment:status | On each poll during monitoring |
| payment:paid | Order reaches FullyPaid |
| payment:declined | Order reaches Declined |
| payment:expired | Order reaches Expired |
| payment:refunded | Order reaches Refunded |
| payment:reversed | Order reaches Reversed |
Ideal for Telegram bots, Discord bots, n8n workflows, and WebSocket bridges.
Create Order
const order = await kb.createOrder({
amount: "1",
description: "SDK Test Order",
});
console.log(order.id);
console.log(getPaymentUrl(order));You can still pass typeRid, currency, language, and hppRedirectUrl per order when needed.
Get Order Details
const details = await kb.getOrder(order.id);
const details = await kb.getOrder(order.id, {
password: order.password,
tranDetailLevel: 2,
tokenDetailLevel: 2,
orderDetailLevel: 2,
});Payment Monitoring
await kb.waitForPayment(order.id, {
password: order.password,
interval: 5000,
timeout: 300000,
});
await kb.waitForStatus(order.id, "FullyPaid", {
password: order.password,
});
await kb.watchOrder(order.id, {
password: order.password,
});| Method | Description |
| ------------------------------------- | ------------------------------------------------ |
| waitForPayment(id, options?) | Poll until FullyPaid, Declined, or Expired |
| waitForStatus(id, status, options?) | Poll until the order reaches a specific status |
| watchOrder(id, options?) | Poll until a terminal status is reached |
WatchOrderOptions:
| Option | Default | Description |
| -------------- | ----------------- | ------------------------------------------ |
| password | — | Order password (recommended for HPP flows) |
| interval | 5000 | Poll interval in ms |
| timeout | 300000 | Max wait time in ms |
| stopStatuses | terminal statuses | Statuses that stop polling |
Throws WatchOrderTimeoutError when timeout is exceeded.
Execute Transaction
await kb.executeTransaction(order.id, {
phase: "Single",
});Refund Transaction
await kb.refund(order.id, {
phase: "Single",
amount: "1.00",
type: "Refund",
});Reverse Transaction
await kb.reverse(order.id, {
phase: "Single",
voidKind: "Full",
});Set Source Token
await kb.setSourceToken(order.id, order.password, {
initiationEnvKind: "Server",
storedId: 5125,
});Set Destination Token
await kb.setDestinationToken(order.id, order.password, {
pan: "4169741330151778",
});Recurring Payment
const order = await kb.createOrder({
typeRid: "Order_REC",
amount: "1",
currency: "AZN",
language: "az",
description: "Recurring Payment",
});
await kb.setSourceToken(order.id, order.password, {
initiationEnvKind: "Server",
storedId: 5125,
});
await kb.executeTransaction(order.id, {
phase: "Single",
conditions: {
cofUsage: "Recurring",
},
});PreAuthorization
await kb.preAuthorize(order.id, "1.00");Clearing
await kb.clear(order.id, "1.00");Card Transfer (OCT)
const result = await kb.transferToCard({
amount: "1",
pan: "4169741330151778",
});
console.log(result);Example response:
{
orderId: 232774,
destinationTokenId: 144495,
approvalCode: "007696",
pmoResultCode: "1"
}The SDK automatically:
- Creates an OCT order
- Creates a destination token
- Executes the credit transaction
Error Handling
import { KapitalBankError, WatchOrderTimeoutError } from "kapital-bank-sdk";
try {
await kb.waitForPayment(order.id, {
password: order.password,
timeout: 120000,
});
} catch (error) {
if (error instanceof WatchOrderTimeoutError) {
console.log("Payment not completed in time");
}
if (error instanceof KapitalBankError) {
if (error.isDeclined()) {
console.log("Transaction declined");
}
}
}KapitalBankError provides helper methods for common API error codes:
| Method | Error Code |
| ----------------------- | ------------------- |
| isDeclined() | PmoDecline |
| isInvalidToken() | InvalidToken |
| isInvalidOrderState() | InvalidOrderState |
| isOrderNotFound() | OrderNotFound |
| isSystemError() | SystemError |
Supported Order Types
type OrderType =
| "Order_SMS"
| "Order_DMS"
| "Order_REC"
| "DMSN3D"
| "OCT"
| "GN3D"
| "GSMS";| Type | Description | | --------- | -------------------------- | | Order_SMS | Standard Purchase (HPP) | | Order_DMS | PreAuthorization | | Order_REC | Recurring Payment | | DMSN3D | Recurring PreAuthorization | | OCT | Account-to-Card | | GN3D | Google Pay 3D Secure | | GSMS | Google Pay Purchase |
Environment
Test
environment: "test";Base URL:
https://txpgtst.kapitalbank.az/apiTest credentials:
| Field | Value |
| -------- | --------------------- |
| Username | TerminalSys/kapital |
| Password | kapital123 |
Test Cards
| PAN | Exp Date | CVV | Notes | | ---------------- | -------- | --- | ------------------------------ | | 5239151747183468 | 11/27 | 602 | Use for HPP browser payments | | 4169741330151778 | 06/25 | 119 | Expired — OCT/server-side only |
The
06/25card may show "expired card" on HPP. Use5239151747183468for hosted payment page testing.
Production
environment: "production";Base URL:
https://e-commerce.kapitalbank.az/apiExamples
Clone the repo and run examples with tsx:
npm install| Script | Command | Description |
| -------------------- | ---------------------------- | ---------------------------------------- |
| From env | npm run from-env | Create order using environment variables |
| Hosted payment | npm run hosted-payment | createHostedPayment() demo |
| Restore order | npm run restore-order | Resume a preparing HPP order |
| Google Pay order | npm run google-pay-order | Create a Google Pay order |
| Google Pay native | npm run google-pay-native | Token-based Google Pay flow |
| Google Pay full flow | npm run google-pay-full-flow | End-to-end Google Pay with monitoring |
| Payment events | npm run payment-events | EventEmitter + wait for payment |
| HPP payment URL | npm run hpp-payment | Create order and print payment URL |
| HPP wait for payment | npm run hpp-wait | Create order, print URL, poll until paid |
| Create order | npm run example | Basic order creation |
| Wait for payment | npm run wait-for-payment | Poll order status |
| Watch order | npm run watch-order | Poll until terminal status |
| Get order | npm run get-order | Fetch order details |
| Transfer to card | npm run transfer | OCT card transfer |
| Recurring | npm run recurring | Recurring payment flow |
| Preauthorize | npm run preauthorize | PreAuthorization flow |
| Clear | npm run clear | Clearing flow |
| Reverse | npm run reverse | Reverse transaction |
| Error handling | npm run error-test | Error handling demo |
| Webhook handler | npm run webhook | Webhook handling example |
| Telegram | npm run telegram | Telegram notifications example |
| Discord | npm run discord | Discord notifications example |
| Retry system | npm run retry | Retry with backoff example |
| Health check | npm run health | Health check example |
| Monitoring | npm run monitoring | Metrics and monitoring example |
Production Guides
Webhook Handler
Handle webhooks from Kapital Bank to receive real-time payment updates:
import { KapitalBank } from "kapital-bank-sdk";
const kb = new KapitalBank({
username: process.env.KAPITALBANK_USERNAME!,
password: process.env.KAPITALBANK_PASSWORD!,
environment: "production",
webhook: {
secret: process.env.WEBHOOK_SECRET!,
allowedIps: ["195.20.100.1", "195.20.100.2"],
},
});
const isValid = kb.verifyWebhookSignature(
rawBody,
signature,
webhookSecret
);
if (isValid.valid) {
const payload = kb.parseWebhookPayload(rawBody);
await kb.handleWebhook(payload, {
onPaymentPaid: async (order) => {},
onPaymentDeclined: async (order) => {},
});
}Security Features:
- HMAC-SHA256 signature verification with timing-safe comparison
- IP filtering (denies by default if not configured)
- Password-based order verification (recommended over orderId)
- JSON parsing with error handling
Notification Services
Send automatic notifications to Telegram or Discord when payment events occur:
import { KapitalBank } from "kapital-bank-sdk";
const kb = new KapitalBank({
username: process.env.KAPITALBANK_USERNAME!,
password: process.env.KAPITALBANK_PASSWORD!,
environment: "production",
telegram: {
botToken: process.env.TELEGRAM_BOT_TOKEN!,
chatId: process.env.TELEGRAM_CHAT_ID!,
customMessages: {
paid: "Payment {orderId} for {amount} {currency} has been paid!",
declined: "Payment {orderId} for {amount} {currency} was declined.",
},
enabledEvents: {
paid: true,
declined: true,
expired: false,
refunded: false,
reversed: false,
},
},
discord: {
webhookUrl: process.env.DISCORD_WEBHOOK_URL!,
customMessages: {
paid: "Payment {orderId} for {amount} {currency} has been paid!",
},
},
});
const session = await kb.createHostedPayment({
amount: "100",
description: "Order",
});
await kb.waitForPayment(session.orderId, {
password: session.password,
});Or use environment variables:
KAPITALBANK_TELEGRAM_BOT_TOKEN=your-bot-token
KAPITALBANK_TELEGRAM_CHAT_ID=your-chat-id
KAPITALBANK_TELEGRAM_MESSAGE_PAID=Payment {orderId} for {amount} {currency} has been paid!
KAPITALBANK_TELEGRAM_ENABLE_PAID=true
KAPITALBANK_TELEGRAM_ENABLE_DECLINED=true
KAPITALBANK_TELEGRAM_ENABLE_EXPIRED=falseThen simply:
import { KapitalBank } from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();Security Note: By default, only terminal payment events (paid, declined, expired) send notifications. Non-terminal events (refunded, reversed) are disabled to prevent notification spam.
Retry System
Configure automatic retry with exponential backoff for failed requests:
import { KapitalBank } from "kapital-bank-sdk";
const kb = new KapitalBank({
username: process.env.KAPITALBANK_USERNAME!,
password: process.env.KAPITALBANK_PASSWORD!,
environment: "production",
retry: {
maxAttempts: 3,
initialDelay: 1000,
maxDelay: 30000,
backoffMultiplier: 2,
retryableErrors: ["ECONNRESET", "ETIMEDOUT"],
onRetry: (attempt, error) => {
console.log(`Retry ${attempt}:`, error.message);
},
},
});Health Check
Monitor API health and availability:
import { KapitalBank } from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();
const health = await kb.healthCheck();
console.log("Healthy:", health.healthy);
console.log("Latency:", health.latency, "ms");
const health = await kb.healthCheckWithTimeout(5000);
setInterval(async () => {
const health = await kb.healthCheck();
if (!health.healthy) {}
}, 30000);Monitoring
Track API performance and metrics:
import { KapitalBank } from "kapital-bank-sdk";
const kb = KapitalBank.fromEnv();
const metrics = kb.getMonitoringMetrics();
console.log("Total requests:", metrics.totalRequests);
console.log("Success rate:", metrics.successRate, "%");
console.log("Average latency:", metrics.averageLatency, "ms");
kb.clearMonitoringMetrics();Environment Variables
Add these to your production environment:
# Kapital Bank API
KAPITALBANK_MODE=production
KAPITALBANK_USERNAME=your-username
KAPITALBANK_PASSWORD=your-password
# Webhook
KAPITALBANK_WEBHOOK_SECRET=your-webhook-secret
KAPITALBANK_WEBHOOK_PATH=/webhook
KAPITALBANK_WEBHOOK_ALLOWED_IPS=195.20.100.1,195.20.100.2
# Telegram
KAPITALBANK_TELEGRAM_BOT_TOKEN=your-bot-token
KAPITALBANK_TELEGRAM_CHAT_ID=your-chat-id
KAPITALBANK_TELEGRAM_PARSE_MODE=Markdown
KAPITALBANK_TELEGRAM_MESSAGE_PAID=Payment {orderId} for {amount} {currency} has been paid!
KAPITALBANK_TELEGRAM_MESSAGE_DECLINED=Payment {orderId} for {amount} {currency} was declined.
KAPITALBANK_TELEGRAM_ENABLE_PAID=true
KAPITALBANK_TELEGRAM_ENABLE_DECLINED=true
KAPITALBANK_TELEGRAM_ENABLE_EXPIRED=true
# Discord
KAPITALBANK_DISCORD_WEBHOOK_URL=your-webhook-url
KAPITALBANK_DISCORD_USERNAME=Kapital Bank Bot
KAPITALBANK_DISCORD_MESSAGE_PAID=Payment {orderId} for {amount} {currency} has been paid!
KAPITALBANK_DISCORD_ENABLE_PAID=true
KAPITALBANK_DISCORD_ENABLE_DECLINED=true
# Retry
KAPITALBANK_RETRY_MAX_ATTEMPTS=3
KAPITALBANK_RETRY_INITIAL_DELAY=1000
KAPITALBANK_RETRY_MAX_DELAY=30000
KAPITALBANK_RETRY_BACKOFF_MULTIPLIER=2
KAPITALBANK_RETRY_RETRYABLE_ERRORS=ECONNRESET,ETIMEDOUTSecurity Notes:
- Always use environment variables for sensitive credentials
- Webhook IP filtering denies by default - configure allowed IPs explicitly
- Retry is limited to max 10 attempts to prevent API abuse
- Notification event toggles prevent spam - disable non-terminal events by default
Best Practices
- Use environment variables for sensitive credentials
- Enable retry in production to handle transient failures
- Set up health checks to monitor API availability
- Configure notifications to stay informed about payment events
- Monitor metrics to track performance and identify issues
- Use webhooks for real-time payment updates instead of polling
- Test in sandbox before deploying to production
- Keep SDK updated to receive security patches and new features
Roadmap
- Apple Pay Support
- Extended Test Coverage
- Transaction Response Enhancements
- SMS Notification Support
Links
GitHub: https://github.com/Umud-Quliyev/kapital-bank-sdk
NPM: https://www.npmjs.com/package/kapital-bank-sdk
License
MIT
Author
Umud Guliyev
