https://github.com/joselay/aba-payway
TypeScript SDK for ABA PayWay — Cambodia's payment gateway. Zero dependencies, full TypeScript support, ESM/CJS.
https://github.com/joselay/aba-payway
aba aba-bank aba-payway cambodia checkout fintech khqr nodejs payment-gateway payway qr-payment sdk typescript
Last synced: 4 months ago
JSON representation
TypeScript SDK for ABA PayWay — Cambodia's payment gateway. Zero dependencies, full TypeScript support, ESM/CJS.
- Host: GitHub
- URL: https://github.com/joselay/aba-payway
- Owner: Joselay
- License: mit
- Created: 2026-03-01T06:06:41.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-03T14:43:23.000Z (4 months ago)
- Last Synced: 2026-03-04T12:28:50.975Z (4 months ago)
- Topics: aba, aba-bank, aba-payway, cambodia, checkout, fintech, khqr, nodejs, payment-gateway, payway, qr-payment, sdk, typescript
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/aba-payway
- Size: 191 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# aba-payway
[](https://www.npmjs.com/package/aba-payway)
[](https://github.com/Joselay/aba-payway/actions)
[](https://opensource.org/licenses/MIT)
[](https://www.npmjs.com/package/aba-payway)
[](https://www.npmjs.com/package/aba-payway)
Type-safe TypeScript SDK for [ABA PayWay](https://www.payway.com.kh/) — Cambodia's #1 payment gateway.
> **Unofficial community SDK.** Not affiliated with ABA Bank.
## Why aba-payway?
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 |
## Features
- **Zero runtime dependencies** — uses Node.js built-in `crypto` and native `fetch`
- **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
## Installation
```bash
# bun
bun add aba-payway
# npm
npm install aba-payway
# pnpm
pnpm add aba-payway
```
## Quick Start
```typescript
import { 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.
```
## API Reference
### `new PayWay(config)`
| 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`) |
### `payway.createTransaction(options)`
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`, and `payout` are automatically base64-encoded by the SDK.
### `payway.checkTransaction(transactionId)`
Check the status of a transaction.
```typescript
const result = await payway.checkTransaction('order-001')
console.log(result.status.code) // '00' = success
console.log(result.data?.payment_status) // 'APPROVED' | 'DECLINED' | 'PENDING' | ...
```
### `payway.listTransactions(options?)`
List transactions with optional filters. Max 3-day date range.
```typescript
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`) |
### `payway.getTransactionDetails(transactionId)`
Get detailed information about a transaction, including its operation history.
```typescript
const details = await payway.getTransactionDetails('order-001')
console.log(details.data?.payment_status) // 'APPROVED'
console.log(details.data?.transaction_operations) // [{ status, amount, ... }]
```
### `payway.closeTransaction(transactionId)`
Close (cancel) a pending transaction. The payment status becomes `CANCELLED`.
```typescript
const result = await payway.closeTransaction('order-001')
console.log(result.status.code) // '00' = success
```
### `payway.getExchangeRate()`
Fetch the latest exchange rates from ABA Bank for 12 currencies.
```typescript
const rates = await payway.getExchangeRate()
console.log(rates.exchange_rates.eur) // { sell: '...', buy: '...' }
```
### `payway.generateQR(options)`
Generate a dynamic QR code for payment via ABA KHQR, WeChat Pay, or Alipay.
```typescript
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) |
### `payway.getTransactionsByRef(merchantRef)`
Get transactions by merchant reference. Returns up to the last 50 transactions.
```typescript
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 |
## Framework Examples
### Next.js (App Router)
```typescript
// 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)
}
```
### Express
```typescript
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)
})
```
## Sandbox Test Cards
| 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 |
## Documentation
For the full ABA PayWay API documentation, see [aba-payway-docs](https://github.com/Joselay/aba-payway-docs).
## Contributing
Found a bug or have a feature request? [Open an issue](https://github.com/Joselay/aba-payway/issues) — all feedback is welcome.
Pull requests are also welcome. Please make sure tests pass before submitting:
```bash
bun run test
bun run typecheck
bun run lint
```
## License
MIT