# PayBox开放接口文档

## PayBox开放接口文档

## 引导

PayBox是一个Web3多链资产聚合支付系统。依靠SwapBox跨链兑换能力，收款商户接入PayBox只需要选择想要收到的资产，而用户可以选择自己拥有的各种链上资产进行付款，而商户无需关心兑换的滑点和汇率。我们希望借助这个产品帮助更多国际互联网产品以及游戏项目提供方便快捷的接入区块链资产支付能力。

1. 对接流程
2. Web端换起PayBox支付页面
3. 回调通知
4. 查询接口
5. Demo

## 1. 对接流程

### 1.1. 必要条件

1. 注册Nabox ID账户

> 测试环境注册地址：<https://beta.id.nabox.io>

> 正式环境注册地址：<https://id.nabox.io>

1. 提供交易到账通知回调URL
2. 创建PayBox 收银台和收款二维码。

### 1.2. 名词释义约定

业务系统：指要对接 PayBox 的应用系统

PayBox：指 PayBox跨链支付收款系统

商户：指业务系统在PayBox 中注册的一个收款主体

用户：指业务系统的用户

支付链：指用户在发起转账交易的区块链网络

支付资产：指用户在支付链转账交易支付的资产

收款链：指商户获得用户支付资产兑换成 USDT 后接收资产的区块链网络

收款地址：指商户在注册 Nabox ID时使用的区块链地址

### 1.3. 业务流程

1. 业务系统创建支付订单号
2. 换起PayBox支付页，传入订单号、收款金额、支付链等信息
3. 用户在PayBox支付页完成转账交易发送
4. PayBox完成资产跨链兑换
5. PayBox通过提供的通知URL 通知业务系统交易已完成
6. 业务系统可通过查询接口查询交易订单信息

### 1.4. 时序图

<figure><img src="https://162443479-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWNe3SZnjpZsV0cUuTT-887967055%2Fuploads%2FWAalD9OHtDO9xhpvW4zp%2FUntitled.png?alt=media&#x26;token=3df3e528-f5b7-4fa8-96ce-cfbd0a480f4f" alt=""><figcaption></figcaption></figure>

## 2. Web 端换起PayBox支付页面

测试网 URL: <https://dev.web.paybox.id.nabox.io/pay>

正式网 URL: <https://paybox.id.nabox.io/pay>

页面参数：

| 参数名         | 是否可为空 | 释义                             |
| ----------- | ----- | ------------------------------ |
| qrcodeId    | 否     | 注册Nabox ID生成商户后会获得一个默认qrcodeId |
| amount      | 是     | 收款金额，如果不填，需要用户在支付页面输入          |
| orderNo     | 否     | 业务订单号                          |
| chain       | 是     | 支付链，如果不填，用户在支付页选择              |
| callbackUrl | 否     | 用户完成支付后调整页面，需要对值进行 URL 编码      |

## 3. 回调通知

当订单在支付链的交易确认时和收款链转给商户的资产到账后，PayBox会调用商户提供的回调地址通知交易状态。回调地址需提前提供给PayBox完成配置。PayBox在通知的请求参数中会进行签名，业务系统应对签名进行验证，确保可靠性。

请求Method：POST

请求Content-type：Application-json

请求参数：

| 参数名           | 类型      | 是否可为空 | 释义          |
| ------------- | ------- | ----- | ----------- |
| ourderOrderNo | string  | 否     | 业务系统订单编号    |
| orderNo       | string  | 否     | PayBox订单编号  |
| fromTxHash    | string  | 是     | 支付链交易 Hash  |
| fromAmount    | Coin    | 否     | 支付链支付资产数量   |
| fromAddress   | string  | 否     | 支付链支付地址     |
| fromChain     | string  | 否     | 支付链名称       |
| toAmount      | Coin    | 否     | 到账金额        |
| payeeFee      | Coin    | 否     | 收款方手续费      |
| toTxHash      | string  | 是     | 到账交易 Hash   |
| toAddress     | string  | 否     | 收款地址        |
| fromTimestamp | int     | 是     | 支付时间（时间戳，秒） |
| toTimestamp   | int     | 是     | 到账时间（时间戳，秒） |
| txState       | TxState | 否     | 交易状态        |
| sendTime      | int     | 否     | 发送时间（时间戳，秒） |
| sign          | string  | 否     | 签名          |

TxState:

| 枚举值           | 释义         |
| ------------- | ---------- |
| Unsent        | 未支付        |
| Panding       | 支付链确认中     |
| SourceConfirm | 支付链交易已确认   |
| Confirm       | 已发送资产到收款地址 |
| Fail          | 交易失败       |

请求参数示例：

```json
{
    "outerOrderNo": "A10001231023154807",
    "orderNo": "A10001230925165043",
    "fromTxHash": "dec04090fff51057dceb8f2d00da7f85bfbb78b303c97e54c808ed51a56014ad",
    "fromAmount": {
        "symbol": "NVT",
        "amount": "63.20416992",
        "cent": "6320416992",
        "decimal": 8
    },
    "fromAddress": "TNVTdTSPRgJo5kUEBRvqKWuLZYfNNksNsSTjt",
    "fromChain": "NERVE",
    "toAmount": {
        "symbol": "USDTN",
        "amount": "0.198",
        "cent": "198000000000000000",
        "decimal": 18
    },
    "payeeFee": {
        "symbol": "USDTN",
        "amount": "0.00786913",
        "cent": "7869133898641243",
        "decimal": 18
    },
    "toTxHash": "b9a6930b893f3f6f990e3c62700603e622e5f3adee48a2120bfefbf73e2b1f48",
    "toAddress": "TNVTdTSPTW9oftjhqLxZ7j9zq9W9cF8SqXqsd",
    "fromTimestamp": 1695631846,
    "toTimestamp": 1695631887,
    "txState": "Confirm",
    "sign": "304402206f32214fed292b82e49bb73ce204e4a739fa2fca68e5b6f9f4ee0df3b1619b89022055c0d19e7f8e95a24d8c3a4043ae50dbc925c97f22df86893614a0b0faa51a99",
    "sendTime": 1699004550
}
```

返回值：SUCCESS/FAIL

订单在支付链交易确认时和收款地址到账时会调用回调通知。 支付链交易确认只会通知一次，无论是否成功都不会重新通知。而收款地址到账通知会进行通知补偿，如果没有返回 SUCCESS，或者调用失败，都回重新通知。如果重试序列全部失败，后续不再通知。

通知的时间序列暂定为：

| 时间   |
| ---- |
| 10 秒 |
| 20 秒 |
| 40 秒 |
| 1 分钟 |
| 1 分半 |
| 3 分钟 |
| 6 分钟 |
| 半小时  |
| 1 小时 |
| 2 小时 |
| 4 小时 |
| 8 小时 |
| 1 天  |

验签方法：ECKey.verify(key,sign,pubKey);

ECKey: ECDSA算法（椭圆曲线加密算法）的实现

key: 为签名内容，取回调请求参数中的 outerOrderNo和 sendTime 参数，拼接在一起。

sign: 签名值，回调请求中的 sign 参数

pubKey：签名公钥

测试网验签公钥：02a6b09b370bf0588e67547f1a5c375cf2d78c5af89a0ced775365ffecb517d8df

正式网验签公钥：02b4bcc1ecbe8785fba3d592fea4dc74e9071fa7399a72cd43993046682c877261

ECDSA 算法java 包：

```json
<!-- https://mvnrepository.com/artifact/org.bitcoinj/bitcoinj-core -->
<dependency>
    <groupId>org.bitcoinj</groupId>
    <artifactId>bitcoinj-core</artifactId>
    <version>0.16.1</version>
</dependency>
或
<!-- https://mvnrepository.com/artifact/network.nerve/nerve-sdk4j -->
<dependency>
    <groupId>network.nerve</groupId>
    <artifactId>nerve-sdk4j</artifactId>
    <version>1.2.5</version>
</dependency>
```

示例代码：

```java
public void handleOrderNotify(
            @RequestBody OuterOrderNotifyDto req,
            HttpServletResponse res,
            HttpServletRequest request
            ) throws IOException {
        log.info("req:{}",req);
        //验签的公钥
        byte[] pubKey = HexUtil.decode("02a6b09b370bf0588e67547f1a5c375cf2d78c5af89a0ced775365ffecb517d8df");
        //签名字符串业务系统订单号和发送时间时间戳的字符串拼接， 时间戳单位为秒，验签的同时验证时间戳是否在合理时间区间内，比如当前时间正负 10 秒。
        String key = req.getOuterOrderNo() + req.getSendTime();
        byte[] keyByte = key.getBytes(StandardCharsets.UTF_8);
        byte[] sign = HexUtil.decode(req.getSign());
        try{
            //使用 ECDSA 算法对签名进行验证。
            boolean verify = ECKey.verify(keyByte,sign, pubKey);
            log.info("sign verify:{}",verify);
            if(verify){
                log.info("订单已完成");
                //获取订单对象进行业务处理
            }
            res.getWriter().write(verify ? "SUCCESS" : "FAIL");
        }catch (Throwable e){
            res.getWriter().write("FAIL");
        }
        res.getWriter().flush();
        res.getWriter().close();
    }
```

## 4. 查询接口

测试网 URL：<https://beta.api.paybox.id.nabox.io>

正式网 URL：<https://api.paybox.id.nabox.io>

接口返回值格式：

```json
{
    "code": 0,       //code 值等于 0 时为成功
    "msg": "成功",    //接口信息
    "data": [XXXX]     //业务值，根据接口不同，类型不同
}
```

#### 4.1. 获取支持的链列表

method：GET

path: /chains

参数：无

data字段返回值：

| 字段名称  | 类型     | 释义      |
| ----- | ------ | ------- |
| chain | string | 链名称     |
| logo  | string | 链图标 URL |

返回值示例：

```json
{
    "code": 0,
    "msg": "成功",
    "data": [
        {
            "chain": "Ethereum",
            "logo": "https://files.nabox.io/icon/Ethereum.png"
        },
        {
            "chain": "BSC",
            "logo": "https://files.nabox.io/icon/BSC.png"
        },
        {
            "chain": "Polygon",
            "logo": "https://files.nabox.io/icon/Polygon.png"
        },
        {
            "chain": "TRON",
            "logo": "https://files.nabox.io/icon/tron.png"
        },
        {
            "chain": "NULS",
            "logo": "https://files.nabox.io/icon/Nuls.png"
        },
        {
            "chain": "NERVE",
            "logo": "https://files.nabox.io/icon/NERVE.png"
        }
    ]
}
```

#### 4.2. 获取指定链支持的资产列表

method:GET

path：/{chain}/assets

参数：chain: 上一个接口中的链名称

data字段返回值：

| 参数名     | 类型     | 释义       |
| ------- | ------ | -------- |
| assetId | string | 资产 ID    |
| symbol  | string | 资产符号     |
| logo    | string | 资产图标 URL |

返回值示例：

```json
{
    "code": 0,
    "msg": "成功",
    "data": [
        {
            "assetId": "93043",
            "symbol": "NULS",
            "logo": "https://files.nabox.io/icon/NULS.png"
        },
        {
            "assetId": "93051",
            "symbol": "NNERVENABOXTOMOON",
            "logo": "https://files.nabox.io/icon/NULL.png"
        },
        {
            "assetId": "93093",
            "symbol": "NABOX",
            "logo": "https://files.nabox.io/icon/NULL.png"
        }
    ]
}
```

#### 4.3. 试算兑换价格

method：GET

path：/asset/price

参数:

| 参数名      | 是否可为空 | 释义                   |
| -------- | ----- | -------------------- |
| chain    | 否     | 支付链名称                |
| assetId  | 否     | 支付资产ID               |
| quantity | 是     | 需要收到的USDT 数量，如果不填为 1 |

请求 URL 示例：

```json
%URL%/asset/price?chain=NERVE&assetId=93059&quantity=10
```

返回值：

| 参数名           | 类型   | 释义        |
| ------------- | ---- | --------- |
| fromPayAmount | Coin | 需要支付的资产数量 |
| fee           | Coin | 其中手续费数量   |

Coin类型：

```json
{
    "symbol": "NVT",            //资产符号
    "amount": "68.57450743",    //资产数量
    "cent": "6857450743",       //转换成最小单位的数量
    "decimal": 8                //小数位数
}
```

返回值示例：

```json
{
    "code": 0,
    "msg": "成功",
    "data": {
        "fromPayAmount": {
            "symbol": "NVT",
            "amount": "68.57450743",
            "cent": "6857450743",
            "decimal": 8
        },
        "fee": {
            "symbol": "NVT",
            "amount": "0",
            "cent": "0",
            "decimal": 8
        }
    }
}
```

#### 4.4. 通过业务订单号查询订单信息

method: GET

path: /order/{address}/{outerOrderNo}

参数：

address: 收款地址

outerOrderNo: 业务系统订单编号，换起支付页时传入

请求 URL 示例：

```html
%URL%/order/TNVTdTSPLtaRJ6SXKgoTfrE4qfDsK6YpuzRWy/A10001231023154807
```

data字段返回值：

| 参数名           | 类型      | 是否可为空 | 释义          |
| ------------- | ------- | ----- | ----------- |
| ourderOrderNo | string  | 否     | 业务系统订单编号    |
| orderNo       | string  | 否     | PayBox订单编号  |
| fromTxHash    | string  | 是     | 支付链交易 Hash  |
| fromAmount    | Coin    | 否     | 支付链支付资产数量   |
| fromAddress   | string  | 否     | 支付链支付地址     |
| fromChain     | string  | 否     | 支付链名称       |
| toAmount      | Coin    | 否     | 到账金额        |
| payeeFee      | Coin    | 否     | 收款方手续费      |
| toTxHash      | string  | 是     | 到账交易 Hash   |
| toAddress     | string  | 否     | 收款地址        |
| fromTimestamp | int     | 是     | 支付时间（时间戳，秒） |
| toTimestamp   | int     | 是     | 到账时间（时间戳，秒） |
| txState       | TxState | 否     | 交易状态        |

TxState:

| 枚举值           | 释义         |
| ------------- | ---------- |
| Unsent        | 未支付        |
| Panding       | 支付链确认中     |
| SourceConfirm | 支付链交易已确认   |
| Confirm       | 已发送资产到收款地址 |
| Fail          | 交易失败       |

返回值示例：

```json
{
    "code": 0,
    "msg": "成功",
    "data": {
        "outerOrderNo": "A10001231023154807",
        "orderNo": "A10001231023154809",
        "fromTxHash": "9296a59f7100d26a8429d7c22a7c2254066f50cfb31123240fa9255c072e63e3",
        "fromAmount": {
            "symbol": "NVT",
            "amount": "1.26981127",
            "cent": "126981127",
            "decimal": 8
        },
        "fromAddress": "TNVTdTSPRgJo5kUEBRvqKWuLZYfNNksNsSTjt",
        "fromChain": "NERVE",
        "toAmount": {
            "symbol": "USDTN",
            "amount": "0.01954",
            "cent": "19540000000000000",
            "decimal": 18
        },
        "payeeFee": null,
        "toTxHash": "31f40f450ca47364746113da074930a881a09c590782c650a9e15bc8c9d97069",
        "toAddress": "TNVTdTSPLtaRJ6SXKgoTfrE4qfDsK6YpuzRWy",
        "fromTimestamp": 1698047291,
        "toTimestamp": 1698047320,
        "txState": "Confirm"
    }
}
```

## 5. Demo下载

1. [Java Demo](https://oit.oss-cn-hangzhou.aliyuncs.com/paybox-demo.tgz)

<https://oit.oss-cn-hangzhou.aliyuncs.com/paybox-demo.tgz>

#### 如有疑问请与我们联系和反馈，感谢您的支持！

***

* Website: [https://nabox.io](https://nabox.io/)
* Twitter: <https://twitter.com/naboxwallet>
* Telegram: <https://t.me/naboxcommunity>
* Discord: <https://discord.gg/mQVXZJXMkn>
* Medium: [https://naboxwallet.medium.com](https://naboxwallet.medium.com/)
* Forum: [https://forum.nabox.io](https://forum.nabox.io/)
* GitHub: [https://github.com/naboxwallet](https://github.com/naboxwallet/)
