# 支付 API

> 使用 2328.io 支付 API 创建并管理加密货币支付会话。

支付 API 让您可以创建支付会话、将客户引导至托管支付页面，并跟踪支付状态。

## 创建支付

创建一个支付会话并返回供客户付款的 URL。

### 请求参数

| 字段 | 类型 | 必需 | 描述 | 取值 |
|------|------|------|------|------|
| `amount` | decimal | 是 | 该币种下的支付金额，例如 `100.00` |  |
| `currency` | string | 是 | 法币（USD、EUR、RUB……）或加密货币（USDT、TRX、BTC……） | `USD`, `EUR`, `RUB`, `KZT`, `UAH`, `UZS`, `USDT`, `USDC`, `BTC`, `ETH`, `GRAM`, `SOL`, `TRX`, `BNB`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `order_id` | string | 是 | 您的订单 ID，例如 `ORDER-12345`（最多 128 个字符） |  |
| `to_currency` | string | 否 | 预选的加密货币 | `USDT`, `USDC`, `BTC`, `ETH`, `GRAM`, `SOL`, `TRX`, `BNB`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `network` | string | 否\* | 网络代码（当 `to_currency` 已设置或 `currency` 为加密货币时必填） | `TRX-TRC20`, `ETH-ERC20`, `BASE`, `BSC-BEP20`, `AVAX-C`, `POL-MATIC`, `TON`, `SOL`, `BTC`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `url_return` | string | 否 | 支付完成后的跳转 URL，例如 `https://your-site.com/return` |  |
| `url_success` | string | 否 | `url_return` 的替代项 |  |
| `url_callback` | string | 是 | webhook 通知 URL，例如 `https://your-site.com/webhook` |  |
| `invite_code` | string | 否 | 推荐人代码 |  |
| `fee_split` | decimal | 否 | 由付款人承担的商户手续费比例（0–100，单位 %）。0 = 商户全额承担，100 = 付款人全额承担。覆盖项目级设置。**示例：`30`**（付款人承担 30%）。 |  |
| `price_markup` | decimal | 否 | 在账单金额上的加价或折扣（−99 到 100，单位 %）。覆盖项目级设置。**示例：`5`**（+5%）或 `-10`（10% 折扣）。 |  |
| `description` | string | 否 | 可选的账单描述（最多 200 个字符），将展示在付款页面。**示例：`Premium plan — Order #12345`**。 |  |
| `ttl_seconds` | int | 否 | 账单有效期（秒），范围 `300`（5 分钟）到 `86400`（24 小时）。超过此时间后账单将过期，无法再支付。默认值：`3600`（1 小时）。**示例：`3600`**。 |  |

### 响应说明

```json
{
  "state": 0,
  "result": {
    "uuid": "abc123-def456-...",
    "order_id": "ORDER-12345",
    "amount": "100.00",
    "currency": "USD",
    "amount_usd": "100.00",
    "exchange_rate": null,
    "url": "https://2328.io/pay/abc123-def456-...",
    "tg_deeplink": "https://t.me/my2328bot?start=pay_abc123-def456-...",
    "expires_at": "2026-01-11T21:00:00Z",
    "created_at": "2026-01-11T20:00:00Z",
    "payer_currency": "USDT",
    "payer_amount": "100.50",
    "network": "TRX-TRC20",
    "address": "TXYZabc123...",
    "payment_status": "check",
    "txid": null,
    "payment_amount": null,
    "qr": "data:image/png;base64,iVBORw0..."
  }
}
```

- 将客户重定向至 `result.url` 完成支付。
- `tg_deeplink` —— 通过 Telegram MiniApp 付款的 Telegram 机器人深度链接。
- `qr` —— 收款地址的 Base64 编码二维码（data URI）。仅当地址已分配时存在（`network` 和 `to_currency` 同时设置，或 `currency` 为加密货币）；否则为 `null`。
- `txid`、`payment_amount` —— 客户付款前为 `null`，链上交易被检测到后填充。可监听 `payment_status: paid` webhook 来获知。
- `exchange_rate` —— 当兑换尚不适用时为 `null`（例如还未确定付款币种）。一旦付款币种锁定即填充。

> Use your project UUID and the endpoint-appropriate API key from the merchant dashboard.

#### Interactive request: `POST /v1/payment`
  - `amount` (decimal, required)
  - `currency` (enum, required): USD,EUR,RUB,KZT,UAH,UZS,USDT,USDC,BTC,ETH,GRAM,SOL,TRX,BNB,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `order_id` (string, required)
  - `to_currency` (enum): USDT,USDC,BTC,ETH,GRAM,SOL,TRX,BNB,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `network` (enum): TRX-TRC20,ETH-ERC20,BASE,BSC-BEP20,AVAX-C,POL-MATIC,TON,SOL,BTC,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `url_return` (string)
  - `url_success` (string)
  - `url_callback` (string, required)
  - `invite_code` (string)
  - `fee_split` (decimal)
  - `price_markup` (decimal)
  - `description` (string)
  - `ttl_seconds` (integer)

## Hosted checkout、H2H 以及确切的加密金额

同一端点支持三种不同的 invoice 形状。特意挑选一个；不要混合它们的数量语义。

### Hosted checkout 付款人选择

发送 `amount`、`currency`、`order_id` 和 `url_callback`，但省略 `to_currency` 和 `network`。响应包含`result.url`； `address`、`qr`，有时付款人字段保留为 `null`，直到付款人在托管页面上选择方向。

```json
{
  "amount": "125.00",
  "currency": "EUR",
  "order_id": "ORDER-2026-1042",
  "url_callback": "https://merchant.example/webhooks/2328",
  "url_return": "https://merchant.example/orders/ORDER-2026-1042"
}
```

### 直接地址 H2H invoice

发送 `to_currency` 和 `network`。 2328.io 在 API call 期间创建区块链 invoice，因此可以在结帐内呈现成功的响应，而无需重定向客户。

```json
{
  "amount": "100.00",
  "currency": "USD",
  "to_currency": "USDT",
  "network": "TRX-TRC20",
  "order_id": "ORDER-2026-1043",
  "url_callback": "https://merchant.example/webhooks/2328"
}
```

完全按照返回值渲染这些值：

- `payer_amount`和`payer_currency`——支付指令；
- `network` 和 `address` — 此 invoice 的唯一目的地；
- `qr` — 同一地址的数据 URI；
- `expires_at` — invoice 截止日期；
- `url` — 当自定义结账无法完成时，有用的托管 fallback。

> **DANGER:** 切勿生成或替换地址、重复使用另一个 invoice 的地址或根据公开现货价格计算 `payer_amount`。 API响应具有权威性。

### Invoice 确切的加密金额

当 invoice 本身以加密货币计价时，将加密货币放入 `currency` 中：

```json
{
  "amount": "25.000000",
  "currency": "USDT",
  "network": "TRX-TRC20",
  "order_id": "ORDER-2026-1044",
  "url_callback": "https://merchant.example/webhooks/2328"
}
```

请求的加密值保存在 `payer_currency` / `payer_amount` 中。该服务还可以在内部维护会计和费率字段的美元估值；不要用该估值替换确切的加密指令。保留返回的十进制字符串，包括尾随精度。

对于仅支持一个网络的加密货币，可能会自动选择该网络。对于确定性集成，仍建议显式提供 `network`。对于稳定币等多网络资产，请始终发送。

## Idempotency 和 retries

`order_id` 的范围仅限于经过身份验证的 merchant 项目，并充当创建 idempotency 密钥。如果付款已存在，API 将返回该会话并显示 `state: 0`。

> **WARNING:** 具有相同 `order_id` 的 retry 的 **not** 的意思是“更新此 invoice”。更改的金额、货币、回调、标记、TTL 或方向字段可能会被忽略，因为会返回现有会话。保留第一个请求并拒绝您自己的应用程序中存在冲突的 retries。

推荐的创建算法：

1. 在一笔数据库交易中插入您的本地付款尝试和唯一的 `order_id`。
2. 发送签名的 API 请求。
3. 保留返回的 `uuid` 和完整响应。
4. 如果HTTP结果丢失，则retry相同的请求或通过`order_id`查询`/v1/payment/info`。
5. 切勿仅仅因为上游请求超时而创建第二个本地订单。

## 支付边缘案例

| 情况 | 正确处理 |
|-----------|------------------|
| `address` / `qr` 是 `null` | 付款人方向尚未初始化。重定向到 `url`，或使用新的 `order_id` 创建一个新的正确指定的 H2H invoice。 |
| HTTP `400` 验证错误 | 读取字段级`errors`；不要将retry 不变地输入。 |
| HTTP `429` | Retry 具有抖动指数退避并保持相同的 `order_id`。 |
| HTTP `503` / `direction_disabled` | 刷新`/v1/directions`；暂时隐藏方向或稍后隐藏方向 retry。 |
| 客户请求 timeout | 将结果视为未知。在创建其他内容之前通过 `order_id` 进行查询。 |
| `underpaid_check` | 存储部分事件并等待充值或稍后状态。当更多 txids 到达时，不要重复记入。 |
| `underpaid` | 最终支付不足的状态。将您配置的履行/手动审核政策应用于实际贷记金额。 |
| `overpaid` | 成功支付剩余资金。履行幂等并保留reconciliation/退款政策的实际金额。 |
| `aml_lock` | 不自动履行或释放资金；通往合规性/支持工作流程的途径。 |
| `cancel` | Invoice 已过期或被取消。不要推断迟到的链上转移是不可能的；与支持协调任何后续事件。 |

浏览器返回 URL 仅用于导航。客户可以在不付款的情况下打开它，付款后关闭它，或稍后重播。只有经过验证的 API/webhook 状态才可以结算 merchant 订单。

## 支付信息

通过 `uuid` 或 `order_id` 获取当前支付状态。

### 请求参数

| 字段 | 类型 | 必需 | 描述 | 取值 |
|------|------|------|------|------|
| `uuid` | string | 是\* | 支付 UUID（创建时来自 `result.uuid`） |  |
| `order_id` | string | 是\* | 您的订单 ID |  |

> **INFO:** `uuid` 与 `order_id` 至少需要提供其一。

#### Interactive request: `POST /v1/payment/info`
  - `uuid` (string)
  - `order_id` (string)

## 支付列表

获取所有支付的列表，支持筛选与分页。

### 请求参数

| 字段 | 类型 | 必需 | 描述 | 取值 |
|------|------|------|------|------|
| `status` | string | 否 | 按支付状态过滤（详见 [References](/docs/references)） | `pending`, `check`, `paid`, `underpaid_check`, `underpaid`, `overpaid`, `cancel` |
| `date_from` | date | 否 | 起始日期（YYYY-MM-DD），例如 `2026-01-01` |  |
| `date_to` | date | 否 | 结束日期（YYYY-MM-DD），例如 `2026-01-31` |  |
| `page` | int | 否 | 页码，默认 `1` |  |
| `per_page` | int | 否 | 每页条数，默认 `15`，最大 `5000` |  |

#### Interactive request: `POST /v1/payment/list`
  - `status` (enum): pending,check,paid,underpaid_check,underpaid,overpaid,cancel
  - `date_from` (string)
  - `date_to` (string)
  - `page` (integer)
  - `per_page` (integer)