# 3-D Secure (3DS) (/zh/docs/cartao/three-d-secure)

<QuickLinks>
  <QuickLink href="/docs/cartao/endpoints/charges/post_charges" title="创建收款" method="POST" path="/charges" />

  <QuickLink href="/docs/cartao/test-cards" title="3DS 测试卡" />

  <QuickLink href="/docs/cartao/antifraud" title="反欺诈" />
</QuickLinks>

**3DS** 由发卡行确认付款人确实是持卡人。经过认证的交易可以降低欺诈风险，并且在认证成功时将拒付责任转移给发卡行或卡组织。

在 3DS 认证过程中,买家的信息会共享给卡组织和发卡行,由它们评估交易风险,并决定是否需要**挑战验证**(例如短信验证码或在银行 App 内认证)来验证持卡人的身份。

### 优势 [#优势]

* 降低欺诈
* 通过认证的交易享有&#x2A;*责任转移 (liability shift)**:发生拒付时由发卡行或卡组织承担责任
* 通过 JavaScript 即可轻松集成
* 支持**无摩擦**认证(买家看不到任何挑战验证),适用于交易风险被判定为低的场景

## 认证流程 [#认证流程]

<Mermaid
  chart="`
flowchart TD
  A[&#x22;加载并初始化 3DS 脚本&#x22;]
  A --> B[&#x22;payzu3DS.checkout(paymentObject)&#x22;]
  B --> C{&#x22;卡片符合认证条件?&#x22;}
  C -->|否| D[&#x22;unenrolled 事件:仅返回 Eci&#x22;]
  C -->|是| E[&#x22;卡组织与发卡行评估风险&#x22;]
  E --> F{&#x22;需要挑战验证?&#x22;}
  F -->|否| G[&#x22;无摩擦认证&#x22;]
  F -->|是| H[&#x22;向持卡人发起挑战验证&#x22;]
  G --> I[&#x22;success 事件:Cavv、Xid 和 Eci&#x22;]
  H --> J{&#x22;认证完成?&#x22;}
  J -->|是| I
  J -->|否| K[&#x22;failure 事件:仅返回 Eci&#x22;]
  I --> L[&#x22;携带 externalAuthentication 创建收款&#x22;]
  K --> M[&#x22;责任仍由商户承担&#x22;]
  D --> M

  style I fill:#14ce71,stroke:#0eb464,color:#ffffff
  style L fill:#14ce71,stroke:#0eb464,color:#ffffff
  style K fill:#f59e0b,stroke:#d97706,color:#ffffff
  style M fill:#ef4444,stroke:#dc2626,color:#ffffff
`"
/>

<Callout type="info">
  当交易使用 `success` 事件返回的变量完成授权时,责任 (liability) 转移给发卡行。在其他所有场景中,责任仍由商户承担。
</Callout>

## 分步集成 [#分步集成]

<Steps>
  <Step>
    ### 初始化脚本 [#初始化脚本]

    在您的网页中引入以下脚本,它负责与卡组织和发卡行进行通信:

    ```html
    <script src="https://static.payzu.io/scripts/3ds20.min.js"></script>
    ```

    脚本加载完成后,需要按如下方式初始化:

    ```javascript
    const config = {
      amount: 350,
      currency: 'BRL',
      options: {
        enabled: true,
        sandbox: true,
        debug: true,
        suppressChallenge: false
      }
    };

    payzu3DS.init(config);
    ```

    | 参数                          | 描述                                              | 类型        |
    | --------------------------- | ----------------------------------------------- | --------- |
    | `amount`                    | 交易总金额,单位为分                                      | 整数        |
    | `currency`                  | 货币代码                                            | 固定为 "BRL" |
    | `options.enabled`           | 定义该交易是否提交到 3DS 认证流程                             | boolean   |
    | `options.sandbox`           | 定义运行环境为 sandbox 还是生产环境                          | boolean   |
    | `options.debug`             | 启用后,日志和报告将输出到浏览器控制台                             | boolean   |
    | `options.suppressChallenge` | 决定是否跳过挑战验证。如果跳过挑战验证且交易被授权,责任 (liability) 仍由商户承担 | boolean   |
  </Step>

  <Step>
    ### 注册认证事件 [#注册认证事件]

    注册事件监听器,以处理认证的每一种可能结果:

    ```javascript
    payzu3DS.on("ready", function (e) {

    });
    ```

    #### ready [#ready]

    当脚本的所有加载步骤成功完成(包括访问 token 的校验)时触发此事件,表示 checkout 已就绪,可以开始认证流程。

    #### 认证结果 [#认证结果]

    仅当认证成功完成时才发生 liability shift:此时拒付责任转移给发卡行或卡组织。在其他所有场景中,责任仍由商户承担。

    | 事件           | 场景与返回                                    | 责任 (liability) | 建议操作                             |
    | ------------ | ---------------------------------------- | -------------- | -------------------------------- |
    | `success`    | 卡片符合认证条件且认证成功完成。返回 `Cavv`、`Xid` 和 `Eci`。 | 转移给发卡行         | 将 `Cavv`、`Xid` 和 `Eci` 包含在授权请求中。 |
    | `failure`    | 卡片符合认证条件,但认证失败。仅返回 `Eci`。                | 仍由商户承担         | 如果决定继续授权,在请求中包含 `Eci`。           |
    | `unenrolled` | 卡片不符合认证条件:持卡人和/或发卡行未参与 3DS 计划。仅返回 `Eci`。 | 仍由商户承担         | 提示买家向发卡行确认该卡是否已开通电商认证。           |
    | `disabled`   | 商户选择不认证,将 `options.enabled` 设为 `false`。  | 仍由商户承担         | -                                |
    | `error`      | 认证流程发生系统性错误。                             | 仍由商户承担         | -                                |

    #### unsupportedBrand [#unsupportedbrand]

    当所用卡片的卡组织不支持 3DS 协议时触发此事件。此时不会进行认证。

    #### 返回的属性 [#返回的属性]

    | 属性              | 描述            | 类型                  | 是否必填 |
    | --------------- | ------------- | ------------------- | ---- |
    | `Cavv`          | 代表认证签名的数据     | string              | 是    |
    | `Xid`           | 认证交易的标识符      | string              | 否    |
    | `Eci`           | 代表认证结果的代码     | [ECI 表](#eci-表)     | 是    |
    | `Version`       | 所使用的 3DS 协议版本 | string              | 是    |
    | `ReferenceId`   | 认证请求的标识符      | string              | 是    |
    | `ReturnCode`    | 认证的返回码        | [3DS 返回码](#3ds-返回码) | 是    |
    | `ReturnMessage` | 认证的返回消息       | [3DS 返回码](#3ds-返回码) | 是    |
  </Step>

  <Step>
    ### 发起挑战验证 [#发起挑战验证]

    实例化 `paymentObject` 对象,注意下表中明确标为必填的字段。执行 checkout 时,认证流程随即启动,其结果将通过事件返回。

    ```javascript
    const paymentObject = {
      installments: '01',
      cardnumber: '4000000000001091',
      cardexpirationmonth: '01',
      cardexpirationyear: '2027',
      cardalias: 'JOAO SOUZA',
      paymentmethod: 'Credit'
    }

    payzu3DS.checkout(paymentObject)
    ```

    如果认证成功完成,将触发 `success` 事件。此时会返回 `Cavv`、`Xid` 和 `Eci` 变量:应将它们发送到您的后端,并在授权时包含在请求中。在这种情况下,liability shift 转移给发卡行。

    <Accordions type="single">
      <Accordion title="paymentObject 字段">
        | 属性名                              | 描述                                          | 类型                                                            | 长度    | 是否必填 |
        | -------------------------------- | ------------------------------------------- | ------------------------------------------------------------- | ----- | ---- |
        | `installments`                   | 交易的分期数                                      | number                                                        | 2     | 是    |
        | `cardnumber`                     | 卡号                                          | number                                                        | 19    | 是    |
        | `cardexpirationmonth`            | 卡片有效期的月份                                    | number                                                        | 2     | 是    |
        | `cardexpirationyear`             | 卡片有效期的年份                                    | number                                                        | 4     | 是    |
        | `cardalias`                      | 卡面印刷的持卡人姓名                                  | string                                                        | 128   | 否    |
        | `paymentmethod`                  | 要认证的卡类型。多功能卡必须指定其中一种类型,Credit 或 Debit       | Credit: 信用卡。Debit: 借记卡                                        | 6     | 是    |
        | `default_card`                   | 标识是否为客户在店铺中的默认卡                             | boolean                                                       | -     | 否    |
        | `recurring_enddate`              | 标识循环扣款的结束日期                                 | string (YYYY-MM-DD)                                           | 10    | 否    |
        | `recurring_frequency`            | 标识循环扣款的频率                                   | number: 1 = 每月, 2 = 每两个月, 3 = 每季度, 4 = 每四个月, 6 = 每半年, 12 = 每年 | -     | 否    |
        | `recurring_originalpurchasedate` | 产生循环扣款的首笔交易日期                               | string (YYYY-MM-DD)                                           | 10    | 否    |
        | `order_recurrence`               | 标识该订单是否会产生后续循环扣款                            | boolean                                                       | -     | 否    |
        | `order_productcode`              | 购买类型 (PHY, CHA, ACF, QCT, PAL)              | string                                                        | -     | 是    |
        | `order_countlast24hours`         | 最近 24 小时内的订单数                               | number                                                        | 3     | 否    |
        | `order_countlast6months`         | 最近 6 个月内的订单数                                | number                                                        | 4     | 否    |
        | `order_countlast1year`           | 最近一年内的订单数                                   | number                                                        | 3     | 否    |
        | `order_cardattemptslast24hours`  | 最近 24 小时内使用同一张卡的交易数                         | number                                                        | 3     | 否    |
        | `order_marketingoptin`           | 是否同意接收营销优惠                                  | boolean                                                       | -     | 否    |
        | `order_marketingsource`          | 营销活动来源                                      | string                                                        | 40    | 否    |
        | `billto_customerid`              | 买家的 CPF/CNPJ                                | string                                                        | 11-14 | 否    |
        | `billto_contactname`             | 账单地址的联系人姓名                                  | string                                                        | 120   | 是    |
        | `billTo_phonenumber`             | 账单地址的电话                                     | string                                                        | 15    | 是    |
        | `billTo_email`                   | 账单地址的电子邮箱                                   | string                                                        | 255   | 是    |
        | `billTo_street1`                 | 账单地址的街道和门牌号                                 | string                                                        | 60    | 是    |
        | `billTo_street2`                 | 账单地址的补充信息和街区                                | string                                                        | 60    | 是    |
        | `billTo_city`                    | 账单地址的城市                                     | string                                                        | 50    | 是    |
        | `billTo_state`                   | 账单地址的州缩写                                    | string                                                        | 2     | 是    |
        | `billto_zipcode`                 | 账单地址的邮编                                     | string                                                        | 8     | 是    |
        | `billto_country`                 | 账单地址的国家                                     | string 例: BR                                                  | 2     | 是    |
        | `shipto_sameasbillto`            | 账单地址与收货地址相同                                 | boolean                                                       | -     | 否    |
        | `shipto_addressee`               | 收货地址的联系人姓名                                  | string                                                        | 60    | 否    |
        | `shipTo_phonenumber`             | 收货地址的电话                                     | string                                                        | 15    | 否    |
        | `shipTo_email`                   | 收货地址的电子邮箱                                   | string                                                        | 255   | 否    |
        | `shipTo_street1`                 | 收货地址的街道和门牌号                                 | string                                                        | 60    | 否    |
        | `shipTo_street2`                 | 收货地址的补充信息和街区                                | string                                                        | 60    | 否    |
        | `shipTo_city`                    | 收货地址的城市                                     | string                                                        | 50    | 否    |
        | `shipTo_state`                   | 收货地址的州缩写                                    | string                                                        | 2     | 否    |
        | `shipto_zipcode`                 | 收货地址的邮编                                     | string                                                        | 8     | 否    |
        | `shipto_country`                 | 收货地址的国家                                     | string 例: BR                                                  | 2     | 否    |
        | `shipTo_shippingmethod`          | 配送方式类型 (lowcost, sameday, oneday, twoday 等) | string                                                        | -     | 否    |
        | `shipto_firstusagedate`          | 收货地址的首次使用日期                                 | string (YYYY-MM-DD)                                           | 10    | 否    |

        <Callout type="info">
          类型列沿用来源文档。在上方官方示例中,`installments`、`cardnumber`、`cardexpirationmonth` 和 `cardexpirationyear` 均以字符串形式发送;请遵循示例,尤其是 `cardnumber`,以避免数值精度丢失。
        </Callout>
      </Accordion>
    </Accordions>
  </Step>

  <Step>
    ### 在收款中使用认证结果 [#在收款中使用认证结果]

    要使用 3DS 创建收款,需要将 `authenticate` 字段设为 `true`,并在 `creditCardPayment` 中提供 `externalAuthentication` 字段:

    ```json
    {
      "creditCardPayment": {
        "authenticate": true,
        "externalAuthentication": {
          "cavv": "Ag5zZ2ElCIUbLFj6gS0J9gByv//rRg5qGTqWqf8vTjt5",
          "xid": "198b924ea7db1014b64c8b426a0e6f1e",
          "eci": "05",
          "version": "2.2",
          "referenceId": "abcd1234-efgh-5678-ijkl-9012mnopqrst"
        }
      }
    }
    ```

    请求的其余字段请参阅[创建收款](/docs/cartao/endpoints/charges/post_charges)。
  </Step>
</Steps>

## 返回码与 ECI [#返回码与-eci]

### 3DS 返回码 [#3ds-返回码]

3DS 认证流程返回的代码。

| 3DS 代码   | 描述                  | 建议操作                                                    |
| -------- | ------------------- | ------------------------------------------------------- |
| `100`    | 交易成功完成。             | -                                                       |
| `101`    | 请求缺少一个或多个必填字段。      | 检查响应中的 `missingField_0` 至 `missingField_N` 字段,然后重新发送请求。 |
| `102`    | 请求中一个或多个字段包含无效数据。   | 检查响应中的 `invalidField_0` 至 `invalidField_N` 字段,然后重新发送请求。 |
| `150`    | 错误:系统整体故障。          | 请等待几分钟后重新发送请求。                                          |
| `151`    | 错误:请求已被接收,但服务器发生超时。 | 请等待几分钟后重新发送请求。                                          |
| `152`    | 错误:请求已被接收,但服务发生超时。  | 请等待几分钟后重新发送请求。                                          |
| `234`    | 您的 merchant 配置存在问题。 | 请勿重新发送该请求,请联系支持团队。                                      |
| `475`    | 该客户已注册付款人认证。        | 在继续交易前,请先完成持卡人认证。                                       |
| `476`    | 无法对该客户进行认证。         | 请复核该客户的订单。                                              |
| `MPI901` | 意外错误。               | -                                                       |
| `MPI902` | 认证返回了意外响应。          | -                                                       |
| `MPI900` | 发生了一个错误。            | -                                                       |
| `MPI601` | 认证挑战已被省略。           | -                                                       |
| `MPI600` | 卡组织不支持该认证。          | -                                                       |

### ECI 表 [#eci-表]

ECI 表按卡组织显示认证结果,以及由谁承担拒付(chargeback)风险:

| Mastercard         | Visa          | Elo           | Amex          | 认证结果                             | 交易是否已认证? |
| ------------------ | ------------- | ------------- | ------------- | -------------------------------- | -------- |
| `02`               | `05`          | `05`          | `05`          | 由发卡行认证:拒付风险转由发卡行承担。              | 是        |
| `01`               | `06`          | `06`          | `06`          | 由卡组织认证:拒付风险转由发卡行承担。              | 是        |
| 非 `01`、`02` 和 `04` | 非 `05` 和 `06` | 非 `05` 和 `06` | 非 `05` 和 `06` | 未认证:拒付风险仍由商户承担。                  | 否        |
| `04`               | `7`           | -             | -             | 未认证,交易被标记为 Data Only:拒付风险仍由商户承担。 | 否        |

<Callout type="warn">
  当交易未通过认证时,拒付风险仍由商户承担。在决定是否继续该笔收款之前,请先核对上表中的 ECI 值。
</Callout>

## 参考 [#参考]

* 在 sandbox 中模拟各种 3DS 认证场景的卡片:[测试卡](/docs/cartao/test-cards)