﻿# Auth-Capture

## 1. 业务介绍

Auth-Capture模式和Sales模式都是支付处理（常见于卡支付）的基本交互模式：

- **Sales 模式（一次交互）**：用户支付时，同时完成授权与扣款，资金立即从用户银行卡中扣除；

- **Auth-Capture 模式（二次交互）**：交易分为两步进行，首先是授权（Authorization），冻结用户的资金；之后再由商户发起请款（Capture），实际完成扣款。

### 1.1 授权 (Authorization)

商家/机构向用户的发卡行请求授权特定金额。

- 发卡行对用户的银行卡进行校验，如：资金/信用额度是否充足、卡片是否有效（未被冻结或挂失）；

- 授权成功，发卡行会对该笔资金进行冻结；

- 此时尚未有资金流发生，只是临时冻结；

- 授权在有效期（7天）内如果未被请款，则会过期失效，冻结金额释放。

### 1.2 请款 (Capture)

- 商家确认完成交易后，请求转移已授权的资金；

- 资金流发生：从持卡人的银行账户扣款；

- 当前支持一次请款，不支持超额请款。

## 2. 适用场景

- **酒店与旅游行业**：用户预订酒店或租车时，先通过授权冻结信用卡资金作为押金，待用户离店或还车时，根据实际消费金额发起请款，完成扣款；

- **充电宝租借场景**：用户租借充电宝时，商户通过授权冻结充电宝押金，用户归还充电宝时，根据实际消费金额发起请款，完成扣款；

- **大型电商平台**：消费者在电商平台下单后，支付时先进行授权，待商家发货后进行请款，完成支付流程。

## 3. 集成准备

+ [注册开发者中心账号](https://docs.payermax.com/202606-version/developer/integration-guide.md#_3-2-注册成为开发者)；

+ [上传测试商户公钥](https://docs.payermax.com/202606-version/developer/integration-guide.md#_3-4-1-配置测试环境的密钥信息)，获取平台公钥、AppID、测试商户号等集成信息；

+ [配置回调地址（WebHook）](https://docs.payermax.com/202606-version/developer/integration-guide.md#_3-4-2-配置测试环境的回调地址)，包括支付结果回调地址、退款结果回调地址等；

+ [设置测试环境服务器IP白名单](https://docs.payermax.com/202606-version/developer/integration-guide.md#_3-5-设置测试环境的服务器ip白名单)；

+ [配置并开通相应支付方式](https://docs.payermax.com/202606-version/developer/integration-guide.md#_3-6-开通集成的支付方式)；

+ [查看不同环境的请求地址](https://docs.payermax.com/202606-version/developer/integration-guide.md#_2-环境信息)；

+ [理解请求报文加签和验签的原理](https://docs.payermax.com/202606-version/developer/config-settings.md)，用于生成每次HTTP请求Header的`sign`签名字符串；

## 4. 交互流程 

```mermaid
%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#e6f0ff',
    'primaryTextColor': '#333',
    'primaryBorderColor': '#5b9bd5',
    'lineColor': '#888',
    'actorMargin': 40,
    'noteBkgColor': '#0056b3',
    'noteTextColor': '#ffffff',
    'noteBorderColor': '#004a99'
  }
}}%%
sequenceDiagram
    participant User as 用户
    participant Client as 商户客户端
    participant MServer as 商户服务端
    participant Checkout as PayerMax收银页
    participant PMServer as PayerMax服务器
    participant Channel as 支付渠道
钱包/银行等

    %% 1. 下单与重定向
    User->>Client: 1.1 选择商品下单
    Client->>MServer: 1.2 下单
    MServer->>PMServer: 1.3 创建支付
调用收银台下单接口 (Auth)
    PMServer->>PMServer: 创建交易
    PMServer-->>MServer: 1.4 返回创建支付响应
含PayerMax收银页URL
    MServer-->>Client: 1.4 返回响应
    Client->>Checkout: 2.1 重定向，打开PayerMax收银页

    %% 2. 支付交互
    User->>Checkout: 3.1 选择支付方式并提交支付
    Checkout->>PMServer: 3.2 支付请求
    PMServer->>Channel: 3.3 支付请求
    PMServer-->>Checkout: 3.4 响应
含PayerMax支付结果页URL
    Checkout->>Checkout: 3.5 重定向，跳转至PayerMax支付结果页
    User->>Checkout: 4.1 用户点击【返回商户】
    Checkout-->>Client: 4.2 重定向，跳转至商户指定页面

    %% 3. 获取授权结果 (逻辑框)
    rect rgb(235, 245, 255)
        Note over MServer, PMServer: 获取授权结果
        Note over MServer, PMServer: 通过支付结果通知
        PMServer->>MServer: 5.1 支付结果异步通知
        MServer->>MServer: 5.2 更新支付结果
        MServer-->>PMServer: 5.3 返回响应

        Note over MServer, PMServer: 通过支付订单查询
        MServer->>PMServer: 6.1 查询支付交易单
        PMServer-->>MServer: 6.2 交易详情，含支付结果
        MServer->>MServer: 6.3 更新支付结果
    end

    %% 4. 请款流程
    MServer->>PMServer: 7.1 发起请款，调用请款接口
    PMServer->>Channel: 7.2 请款请求
    PMServer-->>MServer: 7.3 返回响应

    %% 5. 获取请款结果 (逻辑框)
    rect rgb(235, 245, 255)
        Note over MServer, PMServer: 获取请款结果
        Note over MServer, PMServer: 通过请款结果通知
        PMServer->>MServer: 8.1 请款结果异步通知
        MServer->>MServer: 8.2 更新请款结果
        MServer-->>PMServer: 8.3 返回响应
    end

    %% 6. 撤销流程
    MServer->>PMServer: 9.1 发起撤销，调用撤销接口
    PMServer->>Channel: 9.2 撤销请求
    PMServer-->>MServer: 9.3 返回响应

    %% 7. 获取撤销结果 (逻辑框)
    rect rgb(235, 245, 255)
        Note over MServer, PMServer: 获取撤销结果
        Note over MServer, PMServer: 通过撤销结果通知
        PMServer->>MServer: 10.1 撤销结果异步通知
        MServer->>MServer: 10.2 更新撤销结果
        MServer-->>PMServer: 10.3 返回响应
    end
```

## 5. 接口列表

| 关联交互时序                     | 调用方向             | 接口PATH                                                                                                                                          |
| -------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1.3 创建支付，调用收银台下单接口 | `商户` -> `PayerMax` | [/orderAndPay](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderAndPay/post) |
| 5.1 支付结果异步通知             | `PayerMax` -> `商户` | [/authResultNotifyUrl](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/authResultNotifyUrl/post)           |
| 6.1 查询支付交易                 | `商户` -> `PayerMax` | [/orderQuery](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderQuery/post)   |
| 7.1 发起请款                     | `商户` -> `PayerMax` | [/capture](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-capture/post)         |
| 8.1 请款结果异步通知             | `PayerMax` -> `商户` | [/captureResultNotifyUrl](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/captureResultNotifyUrl/post)     |
| 9.1 发起撤销                     | `商户` -> `PayerMax` | [/cancel](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-cancel/post)           |
| 10.1 撤销结果异步通知            | `PayerMax` -> `商户` | [/cancelResultNotifyUrl](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/cancelResultNotifyUrl/post)       |

## 6. 环境信息

- **测试环境**：https:// `pay-gate-uat.payermax.com`/aggregate-pay/api/gateway/ `<接口PATH>`

- **集成环境**：https:// `pay-gate.payermax.com`/aggregate-pay/api/gateway/ `<接口PATH>`

## 7. 集成步骤

### 7.1 授权申请

授权模式分为三种不同集成模式授权：

- [收银台授权](https://docs.payermax.com/202606-version/acquiring/start-integration/advanced-capabilities-integration/auth-capture/cash-payment-integration.md)

- [纯API授权](https://docs.payermax.com/202606-version/acquiring/start-integration/advanced-capabilities-integration/auth-capture/direct-api-integration.md)

- [前置组件授权](https://docs.payermax.com/202606-version/acquiring/start-integration/advanced-capabilities-integration/auth-capture/drop-in-integration.md)

### 7.2 获取授权结果

授权结果集成参考[获取支付结果集成](https://docs.payermax.com/202606-version/acquiring/start-integration/related-capabilities-integration/payment-result.md)对接步骤，功能相同。若使用了`Auth-capture`功能，在支付结果通知或支付订单查询返回中，则会返回如下字段：

| 字段名称            | 字段类型 | 是否必填 | 描述                                                   |
| ------------------- | -------- | -------- | ------------------------------------------------------ |
| `captureMode`       | `string` | `是`     | 请款模式：`MANUAL`                                     |
| `authorizationType` | `string` | `否`     | 授权类型：`PRE_AUTH`，`FINAL_AUTH`；默认为`FINAL_AUTH` |

#### 7.2.1 授权通知

授权通知可查看[授权通知/authResultNotifyUrl API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/authResultNotifyUrl/post)。

示例如下：

``` json
{
  "code": "APPLY_SUCCESS",
  "msg": "",
  "keyVersion": "1",
  "appId": "3b242b56a8b64274bcc37dac281120e3",
  "merchantNo": "020213827212251",
  "notifyTime": "2022-01-17T09:33:54.540+00:00",
  "notifyType": "PAYMENT",
  "data": {
    "outTradeNo": "P1642410680681",
    "tradeToken": "T2024062702289232000001",
    "totalAmount": 10000,
    "captureMode":"MANUAL",
    "authorizationType":"FINAL_AUTH",
    "currency": "IDR",
    "country": "ID",
    "status": "SUCCESS",
    "completeTime": "2023-10-20T03:28:23.092Z",
    "paymentDetails": [
      {
        "paymentMethodType": "CARD"
      }
    ],
    "reference": "020213827524152"
  }
}
``` 

#### 7.2.2 通过支付订单查询

商户还可以通过调用[交易查询/orderQuery API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderQuery/post)，获取支付结果。

[交易查询/orderQuery API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderQuery/post) 接口请求示例：

``` js
curl --request POST \
  --url https://pay-gate-uat.payermax.com/aggregate-pay/api/gateway/orderQuery \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'sign: FPFVT3o227JrFRbqu19boZCpVVTF9KznxyRawUmxpfXilHV/0yK46haPhAjNu1hPUMy7Vw/ILXhfzffNm4Fj0apWknlTY9OJxnSoQxS9BTFtc61tn5yV1q69x/kkBl82/qwg+XTJ4fOzy7Mar3VaC1E2PlDA6RkkKBUyNE6RYgsdB+Su7an4+4HVTNAnoe74WyvBgxTLMNg28igBTdqxaO3w/UBY6ObVp7vkqkQGdL1Y+HgmMYaAVwrM3+ALWGId0sJ+YqTY4WJ+0xCRGhaSnybiIjZsQEYyID68WNUfuavDLDsEhaMm/HfQvf5p0R1Ltovp3wwJnEbQcjY458iX5A==' \
  --data '{
  "version": "1.4",
  "keyVersion": "1",
  "requestTime": "2022-01-17T07:51:15.597+00:00",
  "appId": "a0dddd1f622243cb9aa1b676e808b5f8",
  "merchantNo": "02021382719993",
  "data": {
    "outTradeNo": "P1642410680681" # 商户单号
  }
}'
```

[交易查询/orderQuery API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderQuery/post) 接口响应示例：

``` json
{
  "msg": "Success.",
  "code": "APPLY_SUCCESS",
  "data": {
    "reference": "reference查询和回调返回",
    "country": "SA",
    "totalAmount": 10,
    "outTradeNo": "DEVTest1669616467952",
    "currency": "SAR",
    "channelNo": "DMCP000000000177005",
    "thirdChannelNo": "4ikqJ6ktEqyRawE1dvqb9c",
    "paymentCode": "2312121212",
    "tradeToken": "T2024062702289232000001",
    "completeTime": "2023-10-20T03:28:23.092Z",
    "captureMode":"MANUAL",
    "authorizationType":"FINAL_AUTH",
    "paymentDetails": [
      {
        "targetOrg": "*",
        "cardInfo": {
          "cardOrg": "VISA",
          "country": "SA",
          "cardIdentifierNo": "400555******0001",
          "cardIdentifierName": "**ngwei"
        },
        "payAmount": 10,
        "exchangeRate": "1",
        "paymentMethod": "CARD",
        "payCurrency": "SAR",
        "paymentMethodType": "CARD"
      }
    ],
    "fees": {
      "merFee": {
        "url": "https://cashier-n-test-new.payermax.com/static/invoice.html?country=AE&merchantNo=P01010113843429&timestamp=1687769788704&version=1.0&orderTaxToken=XWXFKKBOPExplK4aX0r7wgiMtiAMLBKObPFdCMpM9HmCq3AAOob%252BcAZOkP27Kh3W",
        "amount": "100",
        "currency": "SAR"
      }
    },
    "status": "SUCCESS",
    "resultMsg": ""
  }
}
```

### 7.3 发起请款

在授权成功后，当业务需要请款时，需再发起一笔请款请求。接口内容可查看[请款/capture API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-capture/post) 接口。

::: warning 注意：
1. 原授权必须是授权成功；
2. 以原订单号 **`outTradeNo`** 发起请款请求，并传入需要请款的金额。
:::

**关键参数**：

| 字段名称     | 字段类型 | 是否必填 | 描述                         |
| ------------ | -------- | -------- | ---------------------------- |
| `requestId`  | `string` | `是`     | 商户请款请求的唯一id         |
| `outTradeNo` | `string` | `是`     | 商户订单号                   |
| `currency`   | `string` | `是`     | 请款币种（与下单币种一致）   |
| `amount`     | `number` | `是`     | 请款金额（不能超过授权金额） |

[请款/capture API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-capture/post) 接口请求示例：

``` js
{
    "version": "1.4",
    "keyVersion": "1",
    "requestTime": "2024-11-06T11:56:13.000+08:00",
    "appId": "8f8b0895b60f41abbdb05405052971c8",
    "merchantNo": "P01010114178824",
    "data": {
        "requestId": "xxxxx",
        "outTradeNo": "xxxxxxxx",
        "currency": "USD",
        "amount": 100
    }
}
```
[请款/capture API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-capture/post) 接口响应示例：

``` js
{
    "msg": "Success.",
    "code": "APPLY_SUCCESS",
    "data": {
        "captureNo": "20230806235954ED7856775040587834005", // PayerMax 唯一的请款单号
        "requestId":"xxxxx", // 本次请求受理的requestId
        "outTradeNo":"xxxxxxxx", 
        "amount":10,
        "currency":"SAR"
        "status": "PENDING", // SUCCESS FAILED
        "isFinal": true,
        "createdTime": "2023-08-06T23:50:59 +0000",
        "succeededTime": null, // 成功时间
        "failedTime": null, //  失败时间
        "errorCode": null,  // 失败原因 
        "errorMsg": null
    }
}
```

当请款接口同步响应请款结果，请款状态如下：

| 状态      | 描述   | 备注     |
| --------- | ------ | -------- |
| `FAILED`  | 失败   | 请款失败 |
| `PENDING` | 处理中 | 请款中   |
| `SUCCESS` | 成功   | 请款完成 |

::: warning 注意：
目前只支持请款 **`一次`**，请款金额小于等于授予金额即可。暂不支持多次请款。
:::

### 7.4 获取请款结果

请款成功或失败后，也会回调请款状态通知到商户的服务器.通知内容可查看[请款通知/captureResultNotifyUrl API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/captureResultNotifyUrl/post) 接口。集成回调通知可参考[获取支付结果集成](https://docs.payermax.com/202606-version/acquiring/start-integration/related-capabilities-integration/payment-result.md)对接步骤。

**关键参数**：

| 字段名称     | 字段类型 | 是否必填 | 描述                |
| ------------ | -------- | -------- | ------------------- |
| `notifyType` | `string` | `否`     | 通知类型：`CAPTURE` |

当 **`notifyType = CAPTURE`** 时，为请款的回调，示例如下：

``` json
{
    "keyVersion": "1",
    "appId": "5f843bfc8cec49c2b8e9e99847325548",
    "merchantNo": "P01010114418097",
    "notifyTime": "2023-07-23T00:00:01 +0000",
    "notifyType": "CAPTURE", // 请款的类型
    "data": { 
        "captureNo": "20230806235954ED7856775040587834005", // paymermax 唯一的请款单号
        "requestId":"xxxxx", // 本次请求受理的requestId
        "outTradeNo":"xxxxxxxx", 
        "status": "SUCCESS", // SUCCESS FAILED
        "isFinal": true,
        "createdTime": "2023-08-06T23:50:59 +0000",
        "succeededTime": "2023-08-06T23:50:59 +0000", // 成功时间
        "failedTime": null, //  失败时间
        "errorCode": null,  // 失败原因 
        "errorMsg": null
      }
}
```

### 7.5 发起撤销

发起撤销时，必须是授权成功并且没有发起请款。可查看 [撤销/cancel API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-cancel/post) 接口。

以原订单号 **`outTradeNo`** 发起撤销请求，**关键参数**为：

| 字段名称     | 字段类型 | 是否必填 | 描述                 |
| ------------ | -------- | -------- | -------------------- |
| `requestId`  | `string` | `是`     | 商户撤销请求的唯一id |
| `outTradeNo` | `string` | `是`     | 商户订单号           |

撤销是全额撤销，不需要指定金额。 示例如下：

``` json
// 入参
{
"version": "1.4",
"keyVersion": "1",
"requestTime": "2024-11-06T11:56:13.000+08:00",
"appId": "8f8b0895b60f41abbdb05405052971c8",
"merchantNo": "P01010114178824",
"data": {
    "requestId": "xxxxx", // 本次请求单号
    "outTradeNo": "xxxxxxxx", // 原单号
  }
}
```

``` json
// 出参
{
    "msg": "Success.",
    "code": "APPLY_SUCCESS",
    "data": {
        "cancelNo": "20230806235954ED7856775040587834005", // PayerMax 唯一的撤销单号
        "requestId":"xxxxx", // 本次请求受理的requestId
        "outTradeNo":"xxxxxxxx", 
        "status": "SUCCESS", // SUCCESS FAILED
        "createdTime": "2023-08-06T23:50:59 +0000",
        "succeededTime": null, // 成功时间
        "failedTime": null, //  失败时间
        "errorCode": null,  // 失败原因 
        "errorMsg": null
    }
}
```
调用撤销接口会同步响应撤销结果，撤销状态为：

| 状态      | 描述   | 备注     |
| --------- | ------ | -------- |
| `FAILED`  | 失败   | 撤销失败 |
| `PENDING` | 处理中 | 撤销中   |
| `SUCCESS` | 成功   | 撤销成功 |

  
### 7.6 获取撤销结果

撤销成功或失败后，也会回调撤销状态通知到商户的服务器，通知内容可查看 [撤销通知/cancelResultNotifyUrl API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/cancelResultNotifyUrl/post) 接口。集成回调通知可参考[获取支付结果集成](https://docs.payermax.com/202606-version/acquiring/start-integration/related-capabilities-integration/payment-result.md)对接步骤。

**关键参数**：

| 字段名称     | 字段类型 | 是否必填 | 描述               |
| ------------ | -------- | -------- | ------------------ |
| `notifyType` | `string` | `是`     | 通知类型：`CANCEL` |

当 **`notifyType=CANCEL`** 时，为撤销的回调：

``` json
{
    "keyVersion": "1",
    "appId": "5f843bfc8cec49c2b8e9e99847325548",
    "merchantNo": "P01010114418097",
    "notifyTime": "2023-07-23T00:00:01 +0000",
    "notifyType": "CANCEL", 
    "data": { 
        "cancelNo": "20230806235954ED7856775040587834005", // paymermax 唯一的请款单号
        "requestId":"xxxxx", // 本次请求受理的requestId
        "outTradeNo":"xxxxxxxx", 
        "status": "SUCCESS", // SUCCESS FAILED
        "createdTime": "2023-08-06T23:50:59 +0000",
        "succeededTime": "2023-08-06T23:50:59 +0000", // 成功时间
        "failedTime": null, //  失败时间
        "errorCode": null,  // 失败原因 
        "errorMsg": null
      }
}
```

## 8. 测试上线

以下介绍Auth-Capture的集成测试模拟规则。

### 8.1 授权测试

授权测试可参考[发起测试](https://docs.payermax.com/202606-version/acquiring/integration-testing-and-troubleshooting/start-a-test.md)。

::: warning 注意：
请款、撤销必须在授权成功后才可发起。
:::

### 8.2 请款测试

请款接口参数`amount`指定以下值可以mock请款结果：

- `失败`：`amount` = 500,1000,1500,2000;

- `PENDING`：`amount` = 6000,900;

- `成功`：其他金额。

### 8.3 撤销测试

授权接口参数`totalAmount`指定以下值可以mock撤销结果：

- `失败`：`amount` = 2000,2500;

- `PENDING`：`amount` = 6500;

- `成功`：其他金额。
