@gpmpay/sdk
Version:
Official Node.js SDK for GPM Pay — VietQR codes, transaction webhooks, and payment reconciliation.
109 lines (106 loc) • 4.05 kB
text/typescript
import { B as BankAccount, a as Bank } from './bank-SVz37Xt1.cjs';
interface VietQrInput {
/** NAPAS BIN of the beneficiary bank (`bank.bin`). */
bankBin: string;
accountNumber: string;
/** Omit for a static QR the payer fills in themselves. */
amount?: number | string;
/** Truncated to 25 chars, matching the server. */
description?: string;
serviceCode?: 'QRIBFTTA' | 'QRIBFTTC';
}
interface VietQrImageInput extends VietQrInput {
template?: 'compact' | 'compact2' | 'qr_only' | 'print';
accountName?: string;
}
/**
* Build an EMVCo/VietQR payload string.
*
* @remarks
* This is the main entry point when you handle reconciliation yourself — the
* common case. Put your own order code in `description`; it becomes the
* transfer content, and you match it against `event.payload.content` when the
* webhook arrives.
*
* ```ts
* const payload = buildVietQrPayload({
* bankBin: '970422', // account.bank.bin
* accountNumber: '1234567890',
* amount: 50_000,
* description: 'DH123', // your own code — keep it <= 25 chars
* });
* ```
*
* Also fine for a static account QR: omit `amount` and the payer fills it in.
*
* `description` is what the payer ends up transferring, so it carries your
* reconciliation code. VietQR truncates it to 25 characters and banks may
* prepend their own prefix — keep the code short and at the front. For the
* common case, {@link buildPaymentInstructions} wraps this up from a bank
* account object.
*
* Byte-for-byte port of `apps/backend/src/modules/vietqr/vietqr.util.ts`.
*/
declare function buildVietQrPayload(input: VietQrInput): string;
/**
* Build an `img.vietqr.io` image URL.
*
* The server always emits the `compact` template; pass `template` to pick a
* different one for your own checkout page.
*/
declare function buildVietQrImageUrl(input: VietQrImageInput): string;
interface PaymentRequest {
/**
* The destination account, as returned by
* `client.bankAccounts.retrieve(id)`. Must carry its `bank` relation — the
* NAPAS BIN lives there.
*/
bankAccount: BankAccount & {
bank?: Bank;
};
/** VND. A number, or the string form the API returns for `Decimal`. */
amount: number | string;
/**
* The transfer content you will look for later. Put **your own** order
* reference in here — GPM Pay mints nothing and matches nothing. Truncated
* to 25 chars inside the QR, so keep the code short and near the front.
*/
transferContent: string;
serviceCode?: 'QRIBFTTA' | 'QRIBFTTC';
template?: VietQrImageInput['template'];
}
interface PaymentInstructions {
/** EMVCo payload. Render this as the QR. */
qrPayload: string;
qrImageUrl: string;
amount: number;
/** What the payer MUST put in the transfer content. */
transferContent: string;
bankName: string | undefined;
bankBin: string | undefined;
accountNumber: string;
accountName: string;
}
/**
* Everything a checkout page needs, built entirely client-side.
*
* @remarks
* There is no server-side order to read this from — GPM Pay has no
* order/QR-minting endpoint. You choose the reference code, you render the QR,
* and you reconcile it yourself when the transaction webhook arrives by looking
* for that code in `payload.content`.
*
* @throws {GpmPayConfigError} when `bankAccount.bank.bin` is missing — without
* the BIN there is no valid VietQR payload to build.
*
* @example
* const account = await client.bankAccounts.retrieve(bankAccountId);
* const ref = `SHOP${orderId}`;
* const instructions = buildPaymentInstructions({
* bankAccount: account,
* amount: 250_000,
* transferContent: ref,
* });
*/
declare function buildPaymentInstructions(request: PaymentRequest): PaymentInstructions;
export { type PaymentInstructions as P, type VietQrImageInput as V, type PaymentRequest as a, type VietQrInput as b, buildPaymentInstructions as c, buildVietQrImageUrl as d, buildVietQrPayload as e };