# 付款码支付（B扫C）

B扫C支付模式。支付平台会自动根据支付码识别支付方式。

**注意**：如果pay同步返回的order_status不是最终状态，需要马上发起轮询（调用查询接口）。轮询间隔3~5s，总时长控制在40~50s。

**商户系统订单号必须在商户系统内唯一，支付失败订单的二次支付请求，请上送新的商户系统订单号。**

## 接口说明

- 请求方式：`POST`
- 请求地址：`https://vsi-api.shouqianba.com/upay/v2/pay`
- Operation ID：`pay`

## 请求参数

无请求参数。

## 请求体

| 字段名 | 类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| client_sn | string | 是 | 商户系统订单号。必须在商户系统内唯一；且长度不超过32字节 |
| description | string | 否 | 商品详情。对商品或本次交易的描述 |
| device_id | string | 否 | 设备指纹 |
| dynamic_id | string | 是 | 条码内容。不超过32字节 |
| extended | object | 否 | 扩展参数集合，JSON格式。最多支持24个字段，每个字段key长度不超过64字节，value长度不超过256字节。 |
| extended.attach | string | 否 | 附加数据。小程序扫码点餐订单必传：OrderSource=FoodOrder |
| extended.extend_params | object | 否 | 扩展参数。如：花呗分期参数 hb_fq_num、hb_fq_seller_percent 等。 |
| extended.extend_params.hb_fq_num | string | 否 | 花呗分期数，支持3/6/12期 |
| extended.extend_params.hb_fq_seller_percent | string | 否 | 花呗分期卖家承担手续费比例。100：商家承担；0：用户承担 |
| extended.goods_tag | string | 否 | 商品标记 |
| extended.sub_appid | string | 否 | 指定上送appid获取用户身份标识 |
| goods_details | array[object] | 否 | 商品详情列表 |
| goods_details[].goods_id | string | 是 | 商品的编号 |
| goods_details[].goods_name | string | 是 | 商品名称，如ipad |
| goods_details[].price | number | 是 | 商品单价，单位为分，如2000 |
| goods_details[].promotion_type | number | 是 | 优惠类型。0：没有优惠（收钱吧不处理单品信息）；1：支付机构优惠（收钱吧处理单品信息并上送到支付机构） |
| goods_details[].quantity | number | 是 | 商品数量，如10 |
| latitude | string | 否 | 纬度。经纬度必须同时出现 |
| longitude | string | 否 | 经度。经纬度必须同时出现 |
| notify_url | string | 否 | 支付回调的地址。通知失败后重试间隔时间为1s,5s,30s,600s |
| operator | string | 是 | 门店操作员。发起本次交易的操作员 |
| payway | string | 否 | 支付方式。非必传。内容为数字的字符串。一旦设置，则根据支付码判断支付通道的逻辑失效。1:支付宝 3:微信 4:百度钱包 5:京东钱包 6:qq钱包 |
| reflect | string | 否 | 反射参数。任何调用者希望原样返回的信息，可用于关联商户ERP系统的订单或记录附加订单内容 |
| subject | string | 是 | 交易简介。本次交易的简要介绍 |
| terminal_sn | string | 是 | 收钱吧终端ID，不超过32位的纯数字 |
| total_amount | string | 是 | 交易总金额。以分为单位，不超过10位纯数字字符串。超过1亿元的收款请使用银行转账 |

## 请求示例

```json
{
  "client_sn": "8529061153479888",
  "dynamic_id": "281234305112341234",
  "extended": {
    "extend_params": {
      "hb_fq_num": "12",
      "hb_fq_seller_percent": "0"
    }
  },
  "operator": "Roy",
  "subject": "收钱吧",
  "terminal_sn": "100003612347111234",
  "total_amount": "1"
}
```

## 响应体

| 字段名 | 类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| biz_response | object | 否 |  |
| biz_response.data | object | 否 | 支付业务数据 |
| biz_response.data.channel_finish_time | string | 否 | 付款动作在支付服务商的完成时间（时间戳）。只有支付成功时才有值返回 |
| biz_response.data.client_sn | string | 是 | 商户订单号 |
| biz_response.data.finish_time | string | 否 | 付款动作在收钱吧的完成时间（时间戳）。只有order_status为最终状态时才返回 |
| biz_response.data.net_amount | string | 是 | 实收金额。无退款时等于total_amount；否则等于 total_amount 减去退款金额 |
| biz_response.data.operator | string | 是 | 门店操作员 |
| biz_response.data.order_status | string | 是 | 订单状态。当前订单状态 |
| biz_response.data.payer_login | string | 否 | 付款人账号 |
| biz_response.data.payer_uid | string | 否 | 付款人ID。支付平台（微信，支付宝）上的付款人ID |
| biz_response.data.payment_list | array[object] | 否 | 活动优惠信息概览 |
| biz_response.data.payment_list[].amount | string | 是 | 此次交易变更的金额 |
| biz_response.data.payment_list[].amount_total | string | 是 | 活动出资总金额 |
| biz_response.data.payment_list[].type | string | 是 | 活动类型。见附录《活动优惠类型列表》 |
| biz_response.data.payway | string | 是 | 一级支付方式。取值见附录《支付方式列表》 |
| biz_response.data.payway_name | string | 是 | 支付方式名称 |
| biz_response.data.provider_response | object | 否 | 优惠详情。格式为json，内容有两部分：goods_details为核销单品信息数组，voucher_details为核销券信息数组。 |
| biz_response.data.provider_response.goods_details | array[object] | 否 |  |
| biz_response.data.provider_response.voucher_details | array[object] | 否 |  |
| biz_response.data.reflect | string | 否 | 透传参数 |
| biz_response.data.settlement_amount | string | 是 | 本次支付金额 |
| biz_response.data.sn | string | 是 | 收钱吧唯一订单号 |
| biz_response.data.status | string | 是 | 流水状态。本次操作产生的流水的状态 |
| biz_response.data.sub_payway | string | 是 | 二级支付方式。取值见附录《二级支付方式列表》 |
| biz_response.data.subject | string | 是 | 交易概述 |
| biz_response.data.terminal_sn | string | 是 | 收钱吧终端ID |
| biz_response.data.total_amount | string | 是 | 交易总额，以分为单位 |
| biz_response.data.trade_no | string | 否 | 支付服务商订单号。只有支付成功时才有值返回 |
| biz_response.error_code | string | 否 | 业务执行错误码。业务执行失败时返回。 |
| biz_response.error_message | string | 否 | 业务执行错误信息。 |
| biz_response.result_code | string | 是 | 业务执行响应码。SUCCESS：成功；FAIL：失败；INPROGRESS：进行中；ERROR：未知。具体取值见附录《业务数据响应码列表》 |
| error_code | string | 否 | 通讯错误码。通讯失败时返回。见附录《公共错误码》 |
| error_message | string | 否 | 通讯错误信息描述。通讯失败时返回。 |
| result_code | string | 是 | 通讯响应码。200：通讯成功；400：客户端错误；500：服务端错误 |

## 响应示例

```json
{
  "biz_response": {
    "data": {
      "channel_finish_time": "string_value",
      "client_sn": "string_value",
      "finish_time": "string_value",
      "net_amount": "string_value",
      "operator": "string_value",
      "order_status": "string_value",
      "payer_login": "string_value",
      "payer_uid": "string_value",
      "payment_list": [
        {
          "amount": "string_value",
          "amount_total": "string_value",
          "type": "string_value"
        }
      ],
      "payway": "string_value",
      "payway_name": "string_value",
      "provider_response": {
        "goods_details": [
          {}
        ],
        "voucher_details": [
          {}
        ]
      },
      "reflect": "string_value",
      "settlement_amount": "string_value",
      "sn": "string_value",
      "status": "string_value",
      "sub_payway": "string_value",
      "subject": "string_value",
      "terminal_sn": "string_value",
      "total_amount": "string_value",
      "trade_no": "string_value"
    },
    "error_code": "string_value",
    "error_message": "string_value",
    "result_code": "string_value"
  },
  "error_code": "string_value",
  "error_message": "string_value",
  "result_code": "string_value"
}
```

## 示例代码

### cURL

```bash
curl -X POST "https://vsi-api.shouqianba.com/upay/v2/pay" \
  -H "Authorization: 100000000000000000 0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"client_sn":"8529061153479888","dynamic_id":"281234305112341234","extended":{"extend_params":{"hb_fq_num":"12","hb_fq_seller_percent":"0"}},"operator":"Roy","subject":"收钱吧","terminal_sn":"100003612347111234","total_amount":"1"}'
```

### Python

```python
import requests

url = "https://vsi-api.shouqianba.com/upay/v2/pay"
headers = {"Content-Type": "application/json",
    "Authorization": "100000000000000000 0123456789abcdef0123456789abcdef",
}
json_data = {
    "client_sn": "8529061153479888",
    "dynamic_id": "281234305112341234",
    "extended": {
        "extend_params": {
            "hb_fq_num": "12",
            "hb_fq_seller_percent": "0"
        }
    },
    "operator": "Roy",
    "subject": "收钱吧",
    "terminal_sn": "100003612347111234",
    "total_amount": "1"
}

response = requests.post(
    url,
    headers=headers,
    json=json_data,
)

print(response.json())
```

### Java

```java
// 付款码支付（B扫C）
OkHttpClient client = new OkHttpClient();
String json = "{\"client_sn\":\"8529061153479888\",\"dynamic_id\":\"281234305112341234\",\"extended\":{\"extend_params\":{\"hb_fq_num\":\"12\",\"hb_fq_seller_percent\":\"0\"}},\"operator\":\"Roy\",\"subject\":\"收钱吧\",\"terminal_sn\":\"100003612347111234\",\"total_amount\":\"1\"}";
RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));

Request request = new Request.Builder()
    .url("https://vsi-api.shouqianba.com/upay/v2/pay")
    .addHeader("Authorization", "100000000000000000 0123456789abcdef0123456789abcdef")
    .post(body)
    .build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
```

### Go

```go
package main

import (
    "fmt"
    "io"
    "net/http"
    "bytes"
)

func main() {
	jsonBody := []byte(`{"client_sn":"8529061153479888","dynamic_id":"281234305112341234","extended":{"extend_params":{"hb_fq_num":"12","hb_fq_seller_percent":"0"}},"operator":"Roy","subject":"收钱吧","terminal_sn":"100003612347111234","total_amount":"1"}`)
	reqBody := bytes.NewBuffer(jsonBody)
	req, err := http.NewRequest("POST", "https://vsi-api.shouqianba.com/upay/v2/pay", reqBody)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "100000000000000000 0123456789abcdef0123456789abcdef")
	resp, err := (&http.Client{}).Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	respBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(respBytes))
}
```

### Node.js

```javascript
const https = require("https");

const options = {
  method: "POST",
  hostname: "vsi-api.shouqianba.com",
  path: "/upay/v2/pay",
  headers: {
    "Authorization": "100000000000000000 0123456789abcdef0123456789abcdef",
    "Content-Type": "application/json"
  }
};

const postData = JSON.stringify({"client_sn":"8529061153479888","dynamic_id":"281234305112341234","extended":{"extend_params":{"hb_fq_num":"12","hb_fq_seller_percent":"0"}},"operator":"Roy","subject":"收钱吧","terminal_sn":"100003612347111234","total_amount":"1"});

const req = https.request(options, (res) => {
  let data = "";
  res.on("data", (chunk) => { data += chunk; });
  res.on("end", () => { console.log(JSON.parse(data)); });
});
req.write(postData);
req.end();
```
