payment-development
Payment Development Guide
This skill provides guidance for developers working with the @rytass/payments base package, including creating new payment adapters.
Overview
The @rytass/payments package defines the core interfaces and types that all payment adapters must implement. It follows the adapter pattern to provide a unified API across different Taiwan payment providers.
Architecture
@rytass/payments (Base Package)
│
├── PaymentGateway<OCM, O> # Gateway interface
├── Order<OCM> # Order entity interface
├── BindCardPaymentGateway<...> # Card binding interface (optional)
├── Enums & Types # Shared types
└── Event System # EventEmitter-based callbacks
@rytass/payments-adapter-* # Provider implementations
│
├── [Provider]Payment # Implements PaymentGateway
├── [Provider]Order # Implements Order
└── [Provider]BindCard # Implements card binding (optional)
Installation
npm install @rytass/payments
Core Interfaces
PaymentItem
Item included in an order:
interface PaymentItem {
name: string;
unitPrice: number;
quantity: number;
}
PaymentGateway
The main interface that all adapters must implement:
interface PaymentGateway<
OCM extends OrderCommitMessage = OrderCommitMessage,
O extends Order<OCM> = Order<OCM>,
> {
emitter: EventEmitter;
prepare<N extends OCM>(input: InputFromOrderCommitMessage<N>): Promise<Order<N>>;
query<OO extends O>(id: string, options?: unknown): Promise<OO>;
}
PrepareOrderInput
Base input interface for orders:
interface PrepareOrderInput<I extends PaymentItem = PaymentItem> {
items: I[];
}
Order
The order entity interface:
interface Order<OCM extends OrderCommitMessage> extends PrepareOrderInput {
state: OrderState;
createdAt: Date | null;
committedAt: Date | null;
additionalInfo?: AdditionalInfo<OCM>;
asyncInfo?: AsyncOrderInformation<OCM>;
failedMessage: OrderFailMessage | null;
id: string;
items: PaymentItem[];
committable: boolean;
infoRetrieved<T extends OCM>(asyncInformation: AsyncOrderInformation<T>): void;
fail(code: string, message: string): void;
commit<T extends OCM>(message: T, additionalInfo?: AdditionalInfo<T>): void;
refund(amount?: number, options?: unknown): Promise<void>;
}
InputFromOrderCommitMessage
Input type for creating orders via prepare():
interface InputFromOrderCommitMessage<OCM extends OrderCommitMessage> extends PrepareOrderInput {
id?: string;
shopName?: string;
clientBackUrl?: string;
cardType?: CardType;
}
BindCardRequest
Card binding request interface:
interface BindCardRequest {
cardId: string | undefined;
memberId: string;
}
CheckoutWithBoundCardOptions
Options for checkout with bound card:
interface CheckoutWithBoundCardOptions {
cardId: string; // 綁定的卡片 ID
memberId: string; // 綁定會員 ID
items: PaymentItem[];
orderId?: string; // 可選的訂單 ID,若未提供則自動生成
}
BindCardPaymentGateway (Optional)
For adapters supporting card binding:
interface BindCardPaymentGateway<
CM extends OrderCommitMessage = OrderCommitMessage,
R extends BindCardRequest = BindCardRequest,
O extends Order<CM> = Order<CM>,
> {
prepareBindCard(memberId: string): Promise<R>;
checkoutWithBoundCard(options: CheckoutWithBoundCardOptions): Promise<O>;
}
Quick Reference
Order Lifecycle
INITED
↓ prepare()
PRE_COMMIT (Created - form/URL ready)
↓ User completes payment
ASYNC_INFO_RETRIEVED (for ATM/CVS - virtual account/code ready)
↓ User pays at bank/CVS
COMMITTED (Payment successful)
↓ OR
FAILED (Payment failed)
↓ (optional)
REFUNDED (Refund processed)
Channel Enum (支付通道)
import { Channel } from '@rytass/payments';
enum Channel {
CREDIT_CARD = 'CREDIT_CARD', // 信用卡
WEB_ATM = 'WEB_ATM', // 網路 ATM
VIRTUAL_ACCOUNT = 'VIRTUAL_ACCOUNT', // 虛擬帳號
CVS_KIOSK = 'CVS_KIOSK', // 超商代碼繳費
CVS_BARCODE = 'CVS_BARCODE', // 超商條碼繳費
APPLE_PAY = 'APPLE_PAY', // Apple Pay
LINE_PAY = 'LINE_PAY', // LINE Pay
}
Payment Channels
| Channel | Description | Commit Type |
|---|---|---|
CREDIT_CARD |
Credit/Debit Card | Sync |
VIRTUAL_ACCOUNT |
ATM Virtual Account | Async |
WEB_ATM |
Online ATM | Async |
CVS_KIOSK |
Convenience Store Code | Async |
CVS_BARCODE |
Convenience Store Barcode | Async |
APPLE_PAY |
Apple Pay | Sync |
LINE_PAY |
LINE Pay | Sync |
OrderState Enum
enum OrderState {
INITED = 'INITED',
PRE_COMMIT = 'PRE_COMMIT', // Created
ASYNC_INFO_RETRIEVED = 'ASYNC_INFO_RETRIEVED', // Async Payment Information Retrieved (ATM/CVS/Barcode...)
COMMITTED = 'COMMITTED', // Fulfilled
FAILED = 'FAILED',
REFUNDED = 'REFUNDED',
}
| State | Description |
|---|---|
INITED |
Order initialized |
PRE_COMMIT |
Order created, awaiting payment |
ASYNC_INFO_RETRIEVED |
Async payment info ready (ATM/CVS) |
COMMITTED |
Payment successful |
FAILED |
Payment failed |
REFUNDED |
Order refunded |
OrderFailMessage
interface OrderFailMessage {
code: string;
message: string;
}
Card Types
import { CardType } from '@rytass/payments';
enum CardType {
VMJ = 'VMJ', // Visa, MasterCard, JCB
AE = 'AE', // American Express
}
CVS (便利商店)
import { CVS } from '@rytass/payments';
enum CVS {
FAMILY_MART = 'FAMILY_MART', // 全家
HILIFE = 'HILIFE', // 萊爾富
OK_MART = 'OK_MART', // OK 超商
SEVEN_ELEVEN = 'SEVEN_ELEVEN', // 7-11
}
CreditCardECI (3D 驗證結果)
import { CreditCardECI } from '@rytass/payments';
enum CreditCardECI {
MASTER_3D = '2', // MasterCard 3D 驗證成功
MASTER_3D_PART = '1', // MasterCard 部分驗證
MASTER_3D_FAILED = '0', // MasterCard 驗證失敗
VISA_AE_JCB_3D = '5', // Visa/AE/JCB 3D 驗證成功
VISA_AE_JCB_3D_PART = '6', // Visa/AE/JCB 部分驗證
VISA_AE_JCB_3D_FAILED = '7', // Visa/AE/JCB 驗證失敗
}
PaymentPeriod (定期定額)
import { PaymentPeriod, PaymentPeriodType } from '@rytass/payments';
enum PaymentPeriodType {
DAY = 'DAY', // 每日
MONTH = 'MONTH', // 每月
YEAR = 'YEAR', // 每年
}
interface PaymentPeriod {
amountPerPeriod: number; // 每期金額
type: PaymentPeriodType; // 週期類型
frequency?: number; // 頻率(可選)
times: number; // 扣款次數
}
Payment Events
enum PaymentEvents {
SERVER_LISTENED = 'LISTENED',
ORDER_INFO_RETRIEVED = 'INFO_RETRIEVED',
ORDER_PRE_COMMIT = 'PRE_COMMIT',
ORDER_COMMITTED = 'COMMITTED',
ORDER_FAILED = 'FAILED',
CARD_BOUND = 'CARD_BOUND',
CARD_BINDING_FAILED = 'CARD_BINDING_FAILED',
}
| Event | When Triggered |
|---|---|
SERVER_LISTENED |
Built-in server started |
ORDER_PRE_COMMIT |
Order created (form/URL ready) |
ORDER_INFO_RETRIEVED |
Async payment info ready |
ORDER_COMMITTED |
Payment successful |
ORDER_FAILED |
Payment failed |
CARD_BOUND |
Card bound successfully |
CARD_BINDING_FAILED |
Card binding failed |
Event Usage
import { PaymentEvents } from '@rytass/payments';
payment.emitter.on(PaymentEvents.ORDER_COMMITTED, (order) => {
console.log('Payment successful:', order.id);
});
payment.emitter.on(PaymentEvents.ORDER_FAILED, (order) => {
console.error('Payment failed:', order.failedMessage);
});
OrderCommitMessage Types
Base commit message and channel-specific types:
// Base commit message
interface OrderCommitMessage {
id: string;
totalPrice: number;
committedAt: Date | null;
}
// Credit Card
interface OrderCreditCardCommitMessage extends OrderCommitMessage {
type?: Channel.CREDIT_CARD;
id: string;
totalPrice: number;
committedAt: Date;
cardType?: CardType;
}
// Virtual Account (ATM)
interface OrderVirtualAccountCommitMessage extends OrderCommitMessage {
type?: Channel.VIRTUAL_ACCOUNT;
id: string;
totalPrice: number;
committedAt: Date | null;
}
// CVS Kiosk
interface OrderCVSCommitMessage extends OrderCommitMessage {
type?: Channel.CVS_KIOSK;
id: string;
totalPrice: number;
committedAt: Date | null;
}
// CVS Barcode
interface OrderBarcodeCommitMessage extends OrderCommitMessage {
type?: Channel.CVS_BARCODE;
id: string;
totalPrice: number;
committedAt: Date | null;
}
// Apple Pay
interface OrderApplePayCommitMessage extends OrderCommitMessage {
type?: Channel.APPLE_PAY;
id: string;
totalPrice: number;
committedAt: Date | null;
}
// LINE Pay
interface OrderLinePayCommitMessage extends OrderCommitMessage {
type?: Channel.LINE_PAY;
id: string;
totalPrice: number;
committedAt: Date | null;
}
// WebATM
interface OrderWebATMCommitMessage extends OrderCommitMessage {
type?: Channel.WEB_ATM;
id: string;
totalPrice: number;
committedAt: Date | null;
}
AsyncOrderInformation Type
Conditional type for async payment info based on commit message type:
type AsyncOrderInformation<OCM extends OrderCommitMessage> =
OCM extends OrderVirtualAccountCommitMessage
? VirtualAccountInfo
: OCM extends OrderCVSCommitMessage
? CVSInfo
: OCM extends OrderBarcodeCommitMessage
? BarcodeInfo
: never;
AdditionalInfo Type
Conditional type for additional payment info based on commit message type:
type AdditionalInfo<OCM extends OrderCommitMessage> =
OCM extends OrderCreditCardCommitMessage
? CreditCardAuthInfo
: OCM extends OrderVirtualAccountCommitMessage
? VirtualAccountPaymentInfo
: OCM extends OrderWebATMCommitMessage
? WebATMPaymentInfo
: OCM extends OrderCVSCommitMessage
? CVSPaymentInfo
: OCM extends OrderBarcodeCommitMessage
? BarcodeInfo
: OCM extends OrderApplePayCommitMessage
? undefined
: never;
Info Types
For async payment channels:
// Virtual Account (ATM)
interface VirtualAccountInfo {
channel: Channel.VIRTUAL_ACCOUNT;
bankCode: string;
account: string;
expiredAt: Date;
}
// CVS Kiosk
interface CVSInfo {
channel: Channel.CVS_KIOSK;
paymentCode: string;
expiredAt: Date;
}
// CVS Barcode
interface BarcodeInfo {
channel: Channel.CVS_BARCODE;
barcodes: [string, string, string];
expiredAt: Date;
}
For credit card authorization:
interface CreditCardAuthInfo {
channel: Channel.CREDIT_CARD;
processDate: Date;
authCode: string; // 信用卡授權碼 (6 碼)
amount: number;
eci: CreditCardECI; // 3D 驗證結果
card4Number: string; // 卡號末 4 碼
card6Number: string; // 卡號前 6 碼
gwsr?: string; // 閘道序號(可選)
xid?: string; // 交易 ID(可選)
aetId?: string; // AE 交易 ID(可選)
}
For WebATM payment:
interface WebATMPaymentInfo {
channel: Channel.WEB_ATM;
buyerAccountNumber: string; // 付款人帳號
buyerBankCode: string; // 付款人銀行代碼
}
For Virtual Account payment (付款後):
interface VirtualAccountPaymentInfo {
channel: Channel.VIRTUAL_ACCOUNT;
buyerAccountNumber: string; // 付款人帳號
buyerBankCode: string; // 付款人銀行代碼
}
For CVS payment:
interface CVSPaymentInfo {
channel: Channel.CVS_KIOSK;
cvsPayFrom: CVS; // 付款超商
}
Detailed Documentation
For complete interface specifications and implementation guide:
- Base Interfaces Reference - Complete type definitions
- Creating an Adapter - Step-by-step guide