跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://waffo.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

要求

  • Node.js >= 18.0.0

安装

npm install @waffo/waffo-node
# or
yarn add @waffo/waffo-node
# or
pnpm add @waffo/waffo-node

初始化

import { Waffo, Environment } from '@waffo/waffo-node';

const waffo = new Waffo({
  apiKey: 'your-api-key',
  privateKey: 'your-base64-encoded-private-key',
  waffoPublicKey: 'waffo-public-key',
  merchantId: 'your-merchant-id',
  environment: Environment.SANDBOX,
});

支付

import { randomUUID } from 'crypto';

const paymentRequestId = randomUUID().replace(/-/g, '');

const response = await waffo.order().create({
  paymentRequestId,
  merchantOrderId: `ORDER_${Date.now()}`,
  orderCurrency: 'HKD',
  orderAmount: '100.00',
  orderDescription: 'Test Product',
  notifyUrl: 'https://your-site.com/webhook',
  userInfo: {
    userId: 'user_123',
    userEmail: 'user@example.com',
    userTerminal: 'WEB',
  },
  paymentInfo: { productName: 'ONE_TIME_PAYMENT' },
  goodsInfo: { goodsUrl: 'https://your-site.com/product/001' },
});

if (response.isSuccess()) {
  const data = response.getData();
  console.log('Redirect URL:', data.orderAction);
  console.log('Acquiring Order ID:', data.acquiringOrderId);
}

查询

const inquiry = await waffo.order().inquiry({ acquiringOrderId: 'ACQ...' });

订阅

const response = await waffo.subscription().create({ ... });
const inquiry = await waffo.subscription().inquiry({ subscriptionId: '...' });
await waffo.subscription().cancel({ subscriptionId: '...' });

退款

const response = await waffo.order().refund({
  refundRequestId: 'ref_...',
  acquiringOrderId: 'ACQ...',
  refundAmount: '50.00',
  refundReason: 'Customer requested',
});

const inquiry = await waffo.refund().inquiry({ refundRequestId: 'ref_...' });

Webhook 处理

const handler = waffo.webhook()
  .onPayment((notification) => {
    console.log('Payment:', notification.orderStatus);
  })
  .onRefund((notification) => {
    console.log('Refund:', notification.refundStatus);
  })
  .onSubscriptionStatus((notification) => {
    console.log('Subscription:', notification.subscriptionStatus);
  })
  .onSubscriptionChange((notification) => {
    console.log('Subscription Change:', notification.subscriptionChangeStatus);
  });

// Express.js 示例
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const body = req.body.toString();
  const signature = req.headers['x-signature'] as string;

  const result = await waffo.webhook().handleWebhook(body, signature);

  res.setHeader('X-SIGNATURE', result.responseSignature);
  res.setHeader('Content-Type', 'application/json');
  res.status(200).send(result.responseBody);
});

错误处理

import { WaffoUnknownStatusError, WaffoError } from '@waffo/waffo-node';

try {
  const response = await waffo.order().create({ ... });
  if (response.isSuccess()) {
    // 处理成功
  } else {
    // API 返回错误(code != "0")
  }
} catch (error) {
  if (error instanceof WaffoUnknownStatusError) {
    // 重要:支付可能已成功!请通过查询 API 进行确认
    const inquiry = await waffo.order().inquiry({ paymentRequestId });
  } else if (error instanceof WaffoError) {
    // 客户端错误(配置、签名等);修复后重试
  }
}

源码与文档