# 灵途造物支付 SDK

Node.js 22+ 服务端 SDK，无第三方运行时依赖。应用 `clientSecret` 只保存在产品后端。

公开分发目录为 `/sdk/payment-sdk/`。可直接读取 [运行源码](./index.mjs)、[TypeScript 类型](./index.d.mts)、[包配置](./package.json) 和 [SHA-256 校验清单](./SHA256SUMS)。

## 安装

将 SDK 发布到账号站点后，在产品项目中安装：

```sh
npm install https://login.lingtuzaowu.com/sdk/payment-sdk/lingtu-payment-sdk-0.1.0.tgz
```

也可下载 `index.mjs`、`index.d.mts` 和 `package.json` 到本地目录，通过本地包路径安装。此包尚不代表已发布到 npm 公共注册表。

## 创建商品支付单

```js
import { PaymentClient } from '@lingtu/payment-sdk';

const payments = new PaymentClient({
  origin: 'https://login.lingtuzaowu.com',
  clientId: process.env.OIDC_CLIENT_ID,
  clientSecret: process.env.OIDC_CLIENT_SECRET,
});

// 产品先持久化业务订单；用户与金额必须由产品后端确认。
const result = await payments.createOrder({
  businessOrderNo: localOrder.id,
  sub: user.centralSub,
  amountFen: '9900', // 99 元，单位为分
  description: '产品月度会员',
  returnUrl: 'https://product.example/account/orders',
}, localOrder.idempotencyKey);

// 保存 result.order.id，再让浏览器跳转完整 result.checkoutUrl。
```

应用需在账号后台开通支付权限、绑定场景并登记通知地址及返回地址白名单。用户须已通过 OIDC 授权当前应用。下单超时使用原业务订单号及原幂等键重试。

## 付款通知

```js
// rawBody 是未被重新序列化的原始 HTTP 请求正文。
const event = payments.verifyEvent(rawBody, requestHeaders);
const order = await payments.getOrder(event.orderId);
```

验签后核对中心订单与本地订单的业务单号、金额、币种及用户归属；付款状态须为 `paid`，并结合当前退款情况决定权益。将通知 inbox 去重与权益交付放在同一事务，提交成功才返回 HTTP 2xx。浏览器返回页及通知本身均不能替代查单。还应定时主动补单，处理通知延迟、重复和乱序。

## 接口

- `createOrder(input, idempotencyKey)`：商品支付下单。
- `getOrder(id)` / `queryOrder(id)`：读取持久化状态／主动向微信核验。
- `closeOrder(id)`：核验并关闭未付款单。
- `createRefund(id, { businessRefundNo, amountFen })`：按原单申请退款，需应用退款权限。
- `getRefund(id)` / `queryRefund(id)`：读取退款／主动核验。
- `verifyEvent(rawBody, headers)`：通知验签；不代替持久化去重。

请求失败抛出 `PaymentApiError`，包含 `status`、`code` 和 `message`。网络超时保持原单并重试或查询。

本 SDK 当前用于产品商品支付，不提供产品后端的公共算力充值下单方法。公共算力充值引导到账号域名 `/checkout?recharge=1`。

完整接口和通知契约见 [统一支付接入文档](https://login.lingtuzaowu.com/docs/payments.md)。
