Type-safe TypeScript SDK for ABA PayWay — Cambodia's #1 payment gateway.
Unofficial community SDK. Not affiliated with ABA Bank.
ABA PayWay's official SDK is a raw REST API with no official Node.js/TypeScript client. That means you're left dealing with manual HMAC hashing, snake_case field ordering, base64 encoding, and zero type safety. This SDK handles all of that for you.
aba-payway |
Rolling your own | |
|---|---|---|
| Type safety | Full TypeScript with strict types | None — guess the field names |
| Hash computation | Automatic, correct field ordering | Manual HMAC-SHA512, easy to get wrong |
| Base64 encoding | Automatic for items, URLs, payout | Do it yourself, hope you didn't miss one |
| Dependencies | Zero — only Node.js built-ins | Probably axios + crypto-js + glue code |
| API coverage | 15+ methods | Build each one from scratch |
| Runtime support | Node.js, Bun, Deno, Cloudflare Workers | Whatever you tested |
- Zero runtime dependencies — uses Node.js built-in
cryptoand nativefetch - Full TypeScript support with strict types and autocomplete
- Dual ESM + CJS output — works everywhere
- 15+ API methods — checkout, QR payments, refunds, pre-auth, payouts, and more
- Runs anywhere — Node.js, Bun, Deno, Next.js, Express, Hono, Cloudflare Workers
- Tested against ABA's sandbox — not just unit tests, real API integration tests
# bun
bun add aba-payway
# npm
npm install aba-payway
# pnpm
pnpm add aba-paywayimport { PayWay } from 'aba-payway'
const payway = new PayWay({
merchantId: 'your_merchant_id',
apiKey: 'your_api_key',
})
// Generate checkout params (synchronous — no API call)
const params = payway.createTransaction({
transactionId: 'order-001',
amount: 10.00,
items: 'Product A',
returnUrl: 'https://yoursite.com/callback',
})
// Send `params` to your frontend, populate ABA's hidden form,
// and call AbaPayway.checkout() to open the payment dialog.
// See examples/ for more snippets and framework integrations.| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
merchantId |
string |
Yes | — | Your ABA PayWay merchant ID |
apiKey |
string |
Yes | — | Your ABA PayWay API key |
environment |
'sandbox' | 'production' |
No | 'sandbox' |
Target environment |
baseUrl |
string |
No | — | Override the base URL directly (takes priority over environment) |
Generate checkout parameters for a payment. Synchronous — computes the HMAC hash and returns form params without making any API calls.
Returns CheckoutParams — snake_case form parameters to submit via ABA's checkout JS SDK.
| Parameter | Type | Required | Description |
|---|---|---|---|
transactionId |
string |
Yes | Unique transaction ID (max 20 chars) |
amount |
number |
Yes | Purchase amount |
currency |
'USD' | 'KHR' |
No | Default: 'USD' |
paymentOption |
PaymentOption |
No | cards, abapay_khqr, abapay_khqr_deeplink, alipay, wechat, google_pay |
firstName |
string |
No | Buyer's first name |
lastName |
string |
No | Buyer's last name |
email |
string |
No | Buyer's email |
phone |
string |
No | Buyer's phone |
items |
string | ItemEntry[] |
No | Item description — string or { name, quantity, price }[] |
returnUrl |
string |
No | Callback URL for payment completion |
cancelUrl |
string |
No | Redirect URL when user closes payment |
continueSuccessUrl |
string |
No | Redirect URL after success |
type |
'purchase' | 'pre-auth' |
No | Default: 'purchase' |
shipping |
number |
No | Shipping fee |
viewType |
string |
No | 'hosted_view' or 'popup' |
lifetime |
number |
No | Payment lifetime in minutes (3–43200) |
skipSuccessPage |
number |
No | 0 (don't skip) or 1 (skip) |
payout |
string |
No | Payout details (JSON string) |
returnDeeplink |
string |
No | Mobile app deeplink |
googlePayToken |
string |
No | Required if paymentOption is 'google_pay' |
items,returnUrl,returnDeeplink, andpayoutare automatically base64-encoded by the SDK.
Check the status of a transaction.
const result = await payway.checkTransaction('order-001')
console.log(result.status.code) // '00' = success
console.log(result.data?.payment_status) // 'APPROVED' | 'DECLINED' | 'PENDING' | ...List transactions with optional filters. Max 3-day date range.
const list = await payway.listTransactions({
fromDate: '2026-03-01 00:00:00',
toDate: '2026-03-03 23:59:59',
status: 'APPROVED',
page: 1,
pagination: 20,
})| Parameter | Type | Description |
|---|---|---|
fromDate |
string |
Start date: 'YYYY-MM-DD HH:mm:ss' |
toDate |
string |
End date: 'YYYY-MM-DD HH:mm:ss' |
fromAmount |
number |
Minimum amount filter |
toAmount |
number |
Maximum amount filter |
status |
string |
Comma-separated: APPROVED, DECLINED, PENDING, PRE-AUTH, CANCELLED, REFUNDED |
page |
number |
Page number (default: 1) |
pagination |
number |
Records per page (default: 40, max: 1000) |
Get detailed information about a transaction, including its operation history.
const details = await payway.getTransactionDetails('order-001')
console.log(details.data?.payment_status) // 'APPROVED'
console.log(details.data?.transaction_operations) // [{ status, amount, ... }]Close (cancel) a pending transaction. The payment status becomes CANCELLED.
const result = await payway.closeTransaction('order-001')
console.log(result.status.code) // '00' = successFetch the latest exchange rates from ABA Bank for 12 currencies.
const rates = await payway.getExchangeRate()
console.log(rates.exchange_rates.eur) // { sell: '...', buy: '...' }Generate a dynamic QR code for payment via ABA KHQR, WeChat Pay, or Alipay.
const qr = await payway.generateQR({
transactionId: 'qr-001',
amount: 10.00,
paymentOption: 'abapay_khqr',
qrImageTemplate: 'template1',
lifetime: 30,
})
console.log(qr.qrString) // QR content string
console.log(qr.abapay_deeplink) // ABA Mobile deep link| Parameter | Type | Required | Description |
|---|---|---|---|
transactionId |
string |
Yes | Unique transaction ID (max 20 chars) |
amount |
number |
Yes | Payment amount (min: 100 KHR or 0.01 USD) |
paymentOption |
QRPaymentOption |
Yes | abapay_khqr, wechat (USD only), alipay (USD only) |
qrImageTemplate |
string |
Yes | QR image template name |
currency |
'USD' | 'KHR' |
No | Default: 'USD' |
lifetime |
number |
No | Lifetime in minutes (3–43200) |
firstName |
string |
No | Payer's first name |
lastName |
string |
No | Payer's last name |
email |
string |
No | Payer's email |
phone |
string |
No | Payer's phone |
purchaseType |
'purchase' | 'pre-auth' |
No | Default: 'purchase' |
items |
string |
No | Item description (auto base64-encoded) |
callbackUrl |
string |
No | Payment callback URL (auto base64-encoded) |
returnDeeplink |
string |
No | Mobile deeplink (auto base64-encoded) |
payout |
string |
No | Payout JSON string (auto base64-encoded) |
Get transactions by merchant reference. Returns up to the last 50 transactions.
const txns = await payway.getTransactionsByRef('REF-001')
for (const txn of txns.data) {
console.log(txn.transaction_id, txn.payment_status)
}
## Error Handling
```typescript
import { PayWay, PayWayAPIError, PayWayConfigError } from 'aba-payway'| Error Class | When Thrown |
|---|---|
PayWayConfigError |
Missing or invalid constructor config |
PayWayAPIError |
ABA API returns non-2xx response (has statusCode and responseBody properties) |
PayWayError |
Base error class |
PayWayHashError |
Hash generation failure |
// app/api/pay/route.ts
import { PayWay } from 'aba-payway'
const payway = new PayWay({
merchantId: process.env.PAYWAY_MERCHANT_ID!,
apiKey: process.env.PAYWAY_API_KEY!,
environment: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox',
})
export async function POST(request: Request) {
const { orderId, amount } = await request.json()
const params = payway.createTransaction({
transactionId: orderId,
amount,
items: 'Order payment',
returnUrl: `${process.env.NEXT_PUBLIC_URL}/api/pay/callback`,
})
return Response.json(params)
}import express from 'express'
import { PayWay } from 'aba-payway'
const app = express()
app.use(express.json())
const payway = new PayWay({
merchantId: process.env.PAYWAY_MERCHANT_ID!,
apiKey: process.env.PAYWAY_API_KEY!,
})
app.post('/pay', (req, res) => {
const params = payway.createTransaction({
transactionId: req.body.orderId,
amount: req.body.amount,
items: 'Order payment',
returnUrl: 'https://yoursite.com/callback',
})
res.json(params)
})| Card | Number | Expiry | CVV | Result |
|---|---|---|---|---|
| Mastercard | 5156 8399 3770 6777 |
01/30 |
993 |
Approved |
| Visa | 4286 0900 0000 0206 |
04/30 |
777 |
Approved |
| Mastercard | 5156 8302 7256 1029 |
04/30 |
777 |
Declined |
| Visa | 4156 8399 3770 6777 |
01/30 |
993 |
Declined |
For the full ABA PayWay API documentation, see aba-payway-docs.
Found a bug or have a feature request? Open an issue — all feedback is welcome.
Pull requests are also welcome. Please make sure tests pass before submitting:
bun run test
bun run typecheck
bun run lintMIT