@transaksikita/node
v1.0.1
Published
Official Node.js SDK for TransaksiKita Payment Gateway — Create QRIS payments, check status, cancel, and list transactions with zero dependencies.
Maintainers
Readme
Features
- Zero Dependencies — Hanya menggunakan built-in Node.js
http/https - TypeScript Support — Full type definitions included
- Auto Retry — Exponential backoff untuk network errors dan server errors
- Error Handling — Custom error class dengan helper methods
- Callback Verification — Verifikasi callback payload langsung dari SDK
- Payment Polling — Built-in
waitForPayment()untuk polling status - Idempotency — Cegah duplikasi pembayaran dengan idempotency key
- Sandbox & Production — Mode otomatis dari prefix API key
Table of Contents
- Installation
- Quick Start
- Configuration
- API Reference
- Error Handling
- Examples
- Headers & Authentication
- Environment Variables
- FAQ
- Support
- License
Installation
npm install @transaksikita/nodeyarn add @transaksikita/nodepnpm add @transaksikita/nodeRequirements: Node.js >= 14.0.0
Quick Start
const { TransaksiKita } = require('@transaksikita/node');
// 1. Inisialisasi SDK
const tk = new TransaksiKita({
projectId: 'YOUR_PROJECT_ID',
publicKey: 'tk_sandbox_xxxxxxxxxxxx',
secretKey: 'sk_sandbox_xxxxxxxxxxxx',
});
// 2. Buat pembayaran
const payment = await tk.createPayment({
amount: 50000,
customerName: 'Budi Santoso',
description: 'Pembelian Paket Premium',
referenceId: 'ORDER-001',
expiredMinutes: 60,
});
// 3. Redirect customer ke checkout
console.log(payment.checkoutFullUrl);
// → https://transaksikita.com/pay/PAY-xxxxx
// 4. Cek status pembayaran
const status = await tk.checkStatus(payment.paymentId);
console.log(status.status); // 'pending' | 'paid' | 'expired' | 'cancelled'Configuration
const tk = new TransaksiKita({
// WAJIB
projectId: 'PROJECT_ID', // Project ID dari dashboard
publicKey: 'tk_sandbox_xxx', // Public Key dari dashboard
secretKey: 'sk_sandbox_xxx', // Secret Key dari dashboard
// OPSIONAL
baseUrl: 'https://transaksikita.com', // Default base URL
timeout: 30000, // Request timeout dalam ms (default: 30000)
maxRetries: 2, // Auto-retry untuk network/server error (0-3)
});| Param | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| projectId | string | ✅ | — | Project ID dari dashboard TransaksiKita |
| publicKey | string | ✅ | — | Public Key (prefix tk_sandbox_ atau tk_production_) |
| secretKey | string | ✅ | — | Secret Key (prefix sk_sandbox_ atau sk_production_) |
| baseUrl | string | ❌ | https://transaksikita.com | Base URL API |
| timeout | number | ❌ | 30000 | Request timeout dalam milliseconds |
| maxRetries | number | ❌ | 0 | Jumlah retry (0-3), dengan exponential backoff |
Mode Otomatis: SDK otomatis mendeteksi mode (sandbox/production) dari prefix API key Anda. Tidak perlu konfigurasi manual.
API Reference
ping()
Test koneksi API dan verifikasi credentials.
const info = await tk.ping();Returns: PingData
| Field | Type | Description |
|-------|------|-------------|
| projectId | string | Project ID |
| projectName | string | Nama project |
| mode | string | 'sandbox' atau 'production' |
| timestamp | string | Waktu server (ISO 8601) |
Example:
const info = await tk.ping();
console.log(info.projectName); // "Toko Saya"
console.log(info.mode); // "sandbox"createPayment(params)
Buat pembayaran baru. Customer akan diarahkan ke halaman checkout TransaksiKita.
const payment = await tk.createPayment({
amount: 100000,
customerName: 'Budi Santoso',
description: 'Order #12345',
referenceId: 'ORD-12345',
expiredMinutes: 60,
paymentMethod: 'QRIS',
idempotencyKey: 'ORD-12345',
sandbox: false,
});Parameters:
| Param | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| amount | number | ✅ | — | Nominal pembayaran dalam Rupiah (min. 500) |
| customerName | string | ❌ | — | Nama customer |
| description | string | ❌ | — | Deskripsi pembayaran |
| referenceId | string | ❌ | — | ID referensi unik dari sistem Anda |
| expiredMinutes | number | ❌ | 60 | Waktu expired: 5 - 1440 menit (24 jam) |
| paymentMethod | string | ❌ | — | 'QRIS' atau kosong (customer pilih di checkout) |
| idempotencyKey | string | ❌ | — | Mencegah duplikasi pembayaran |
| sandbox | boolean | ❌ | false | Force sandbox mode |
Returns: PaymentData
| Field | Type | Description |
|-------|------|-------------|
| paymentId | string | ID pembayaran unik |
| projectId | string | Project ID |
| mode | string | 'sandbox' atau 'production' |
| status | string | Status: 'pending' |
| amount | number | Nominal asli |
| feeAmount | number | Biaya QRIS |
| totalAmount | number | Total yang harus dibayar (amount + fee + unique code) |
| expiredMinutes | number | Waktu expired dalam menit |
| referenceId | string\|null | ID referensi Anda |
| createdAt | string | Waktu dibuat (ISO 8601) |
| expiresAt | number | Timestamp expired (ms) |
| checkoutUrl | string | Path checkout (relative) |
| checkoutFullUrl | string | Full URL checkout — redirect customer ke sini |
| qrisPayload | string\|null | QRIS payload untuk generate QR code sendiri |
checkStatus(paymentId)
Cek status pembayaran secara real-time.
const status = await tk.checkStatus('PAY-xxxxx');Returns: PaymentStatusData
| Field | Type | Description |
|-------|------|-------------|
| paymentId | string | ID pembayaran |
| status | string | 'pending' | 'paid' | 'expired' | 'cancelled' |
| amount | number | Nominal asli |
| feeAmount | number | Biaya QRIS |
| totalAmount | number | Total amount |
| paidAmount | number | Jumlah yang dibayar (jika sudah paid) |
| paidAt | string\|null | Waktu pembayaran (ISO 8601) |
| remainingMs | number | Sisa waktu dalam milliseconds |
| customerName | string | Nama customer |
| description | string | Deskripsi |
| referenceId | string\|null | ID referensi Anda |
| checkoutFullUrl | string | Full checkout URL |
| qrisPayload | string\|null | QRIS payload (hanya jika pending) |
Example:
const status = await tk.checkStatus('PAY-xxxxx');
switch (status.status) {
case 'paid':
console.log('✅ Pembayaran berhasil!');
console.log('Dibayar pada:', status.paidAt);
console.log('Jumlah:', TransaksiKita.formatRupiah(status.paidAmount));
break;
case 'pending':
console.log('⏳ Menunggu pembayaran...');
console.log('Sisa waktu:', Math.floor(status.remainingMs / 60000), 'menit');
break;
case 'expired':
console.log('⏰ Pembayaran expired');
break;
case 'cancelled':
console.log('❌ Pembayaran dibatalkan');
break;
}cancelPayment(paymentId)
Batalkan pembayaran. Hanya bisa untuk status pending.
const result = await tk.cancelPayment('PAY-xxxxx');
console.log(result.status); // 'cancelled'
console.log(result.cancelledAt); // '2026-04-24T12:00:00.000Z'Returns: CancelPaymentData
| Field | Type | Description |
|-------|------|-------------|
| paymentId | string | ID pembayaran |
| status | string | 'cancelled' |
| cancelledAt | string | Waktu pembatalan (ISO 8601) |
| amount | number | Nominal asli |
| totalAmount | number | Total amount |
| referenceId | string\|null | ID referensi |
listPayments(params?)
Daftar semua pembayaran dengan pagination dan filter.
const { data, pagination } = await tk.listPayments({
page: 1,
limit: 20,
status: 'paid',
});Parameters:
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| page | number | 1 | Halaman |
| limit | number | 20 | Jumlah per halaman (1-100) |
| status | string | — | Filter: 'pending', 'paid', 'expired', 'cancelled' |
Returns: { data: PaymentListItem[], pagination: Pagination }
const { data, pagination } = await tk.listPayments({ limit: 5, status: 'paid' });
console.log(`Total: ${pagination.total} payments`);
console.log(`Halaman: ${pagination.page}/${pagination.totalPages}`);
data.forEach((p) => {
console.log(`${p.paymentId} | ${TransaksiKita.formatRupiah(p.amount)} | ${p.status}`);
});verifyCallback(payload)
Verifikasi callback payload dengan re-check ke API TransaksiKita. Selalu gunakan ini di callback endpoint!
const isValid = await tk.verifyCallback(req.body);Returns: boolean — true jika payment ID, status, dan amount cocok.
waitForPayment(paymentId, intervalMs?, maxAttempts?)
Polling status sampai berubah dari pending. Berguna untuk CLI tools atau background jobs.
// Polling setiap 5 detik, max 60x (5 menit)
const result = await tk.waitForPayment('PAY-xxxxx', 5000, 60);| Param | Type | Default | Description |
|-------|------|---------|-------------|
| paymentId | string | — | ID pembayaran |
| intervalMs | number | 5000 | Interval polling dalam ms |
| maxAttempts | number | 60 | Jumlah maksimum polling |
Static Helpers
// Format angka ke Rupiah
TransaksiKita.formatRupiah(50000); // "Rp 50.000"
TransaksiKita.formatRupiah(1500000); // "Rp 1.500.000"
// Cek apakah payment masih bisa dibayar
const status = await tk.checkStatus('PAY-xxx');
TransaksiKita.isPaymentActive(status); // true/falseError Handling
SDK menggunakan custom TransaksiKitaError class dengan helper methods:
const { TransaksiKita, TransaksiKitaError } = require('@transaksikita/node');
try {
await tk.createPayment({ amount: 100 });
} catch (err) {
if (err instanceof TransaksiKitaError) {
console.log(err.message); // Pesan error
console.log(err.statusCode); // HTTP status code (0 = network/timeout)
console.log(err.detail); // Detail tambahan dari API
console.log(err.response); // Raw API response
// Helper methods
err.isAuthError(); // 401/403 — API key salah
err.isValidationError(); // 400 — Parameter tidak valid
err.isNotFound(); // 404 — Payment tidak ditemukan
err.isRateLimited(); // 429 — Terlalu banyak request
err.isConflict(); // 409 — Idempotency conflict
err.isRetryable(); // Network error, timeout, atau 5xx
}
}Error codes:
| Code | Penyebab | Solusi |
|------|----------|--------|
| 400 | Parameter tidak valid | Cek amount (min 500), expiredMinutes (5-1440) |
| 401 | API key tidak valid | Cek publicKey dan secretKey |
| 403 | Project ditolak/tidak punya akses | Hubungi admin |
| 404 | Payment/project tidak ditemukan | Cek paymentId atau projectId |
| 409 | Idempotency conflict | Request sedang diproses, tunggu |
| 429 | Rate limit | Maksimum 60 req/menit, tunggu 1 menit |
| 0 | Network error / timeout | Cek koneksi, gunakan maxRetries |
Auto Retry
const tk = new TransaksiKita({
// ...credentials
maxRetries: 3, // Retry 3x untuk network/server error
timeout: 15000, // 15 detik per request
});
// Retry delay: 1s → 2s → 4s (exponential backoff)
// TIDAK retry untuk: 400, 401, 403, 404, 409Examples
Express.js Integration
const express = require('express');
const { TransaksiKita, TransaksiKitaError } = require('@transaksikita/node');
const app = express();
app.use(express.json());
const tk = new TransaksiKita({
projectId: process.env.TK_PROJECT_ID,
publicKey: process.env.TK_PUBLIC_KEY,
secretKey: process.env.TK_SECRET_KEY,
});
// Buat pembayaran
app.post('/checkout', async (req, res) => {
try {
const payment = await tk.createPayment({
amount: req.body.amount,
customerName: req.body.name,
description: `Order dari ${req.body.name}`,
referenceId: `ORD-${Date.now()}`,
expiredMinutes: 60,
});
res.json({
checkoutUrl: payment.checkoutFullUrl,
paymentId: payment.paymentId,
});
} catch (err) {
if (err instanceof TransaksiKitaError) {
return res.status(err.statusCode || 500).json({ error: err.message });
}
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(3000);📁 Lihat contoh lengkap: examples/express.js
Callback Handler
// Endpoint untuk menerima callback dari TransaksiKita
app.post('/callback/transaksikita', async (req, res) => {
// PENTING: Selalu verifikasi callback!
const isValid = await tk.verifyCallback(req.body);
if (!isValid) {
return res.status(400).json({ error: 'Invalid callback' });
}
const { paymentId, status, referenceId, amount } = req.body;
if (status === 'paid') {
// Update order di database Anda
await db.orders.update(
{ status: 'paid', paidAt: new Date() },
{ where: { orderId: referenceId } }
);
// Kirim email konfirmasi
await sendEmail(customer.email, 'Pembayaran Berhasil!');
}
// WAJIB: respond 200
res.json({ received: true });
});Polling Payment
// Menunggu pembayaran selesai (untuk CLI/background job)
const payment = await tk.createPayment({ amount: 50000 });
console.log('Scan QR:', payment.checkoutFullUrl);
// Polling setiap 3 detik, max 100x
const result = await tk.waitForPayment(payment.paymentId, 3000, 100);
if (result.status === 'paid') {
console.log('Pembayaran berhasil!');
}📁 Lihat contoh lengkap: examples/polling.js
Idempotency
Cegah pembayaran duplikat menggunakan idempotency key:
const orderId = 'ORDER-12345';
// Request pertama — buat pembayaran baru
const pay1 = await tk.createPayment({
amount: 50000,
idempotencyKey: orderId,
});
// Request kedua dengan key sama — TIDAK membuat pembayaran baru
// Mengembalikan data pembayaran yang sama
const pay2 = await tk.createPayment({
amount: 50000,
idempotencyKey: orderId,
});
console.log(pay1.paymentId === pay2.paymentId); // true📁 Lihat contoh lengkap: examples/error-handling.js
TypeScript
import TransaksiKita, {
TransaksiKitaError,
CreatePaymentParams,
PaymentData,
PaymentStatusData,
} from '@transaksikita/node';
const tk = new TransaksiKita({
projectId: process.env.TK_PROJECT_ID!,
publicKey: process.env.TK_PUBLIC_KEY!,
secretKey: process.env.TK_SECRET_KEY!,
});
const params: CreatePaymentParams = {
amount: 100000,
customerName: 'Budi',
};
const payment: PaymentData = await tk.createPayment(params);
const status: PaymentStatusData = await tk.checkStatus(payment.paymentId);📁 Lihat contoh lengkap: examples/typescript.ts
Headers & Authentication
SDK otomatis mengirim headers berikut ke API TransaksiKita:
| Header | Value | Description |
|--------|-------|-------------|
| Authorization | Bearer {secretKey} | Secret Key sebagai Bearer token |
| X-Public-Key | {publicKey} | Public Key |
| X-Project-Id | {projectId} | Project ID |
| Content-Type | application/json | JSON body |
| User-Agent | TransaksiKita-Node/1.0.0 | SDK identifier |
| X-Idempotency-Key | {key} | (opsional) Idempotency key |
| X-Sandbox | 1 | (opsional) Force sandbox mode |
Environment Variables
Rekomendasi: simpan credentials di environment variables, jangan hardcode di source code.
# .env
TK_PROJECT_ID=your-project-id-here
TK_PUBLIC_KEY=tk_production_xxxxxxxxxxxx
TK_SECRET_KEY=sk_production_xxxxxxxxxxxxconst tk = new TransaksiKita({
projectId: process.env.TK_PROJECT_ID,
publicKey: process.env.TK_PUBLIC_KEY,
secretKey: process.env.TK_SECRET_KEY,
});FAQ
Q: Apakah SDK ini perlu dependency tambahan?
A: Tidak. SDK ini zero dependencies — hanya menggunakan built-in Node.js http dan https.
Q: Bagaimana cara mendapatkan API key? A: Daftar di transaksikita.com, buat project, dan API key akan digenerate otomatis.
Q: Apa bedanya sandbox dan production?
A: Sandbox untuk testing (pembayaran simulasi), production untuk transaksi nyata. Mode otomatis dari prefix API key (tk_sandbox_ vs tk_production_).
Q: Berapa rate limit API?
A: Maksimum 60 request per menit per IP. SDK akan throw TransaksiKitaError dengan statusCode: 429 jika melebihi limit.
Q: Apakah callback aman?
A: Selalu gunakan tk.verifyCallback() untuk memverifikasi callback. Method ini akan re-check ke API TransaksiKita untuk memastikan data valid.
Q: Pembayaran bisa expired?
A: Ya. Set expiredMinutes saat createPayment() (5-1440 menit). Setelah expired, payment otomatis berubah status.
Support
- Documentation: transaksikita.com
- Issues: GitHub Issues
- Email: [email protected]
