跳转到内容

3D Secure ​

概述 ​

符合 3D Secure 2 条件的交易,会根据发卡行的要求走无感认证流程或挑战认证流程。

A. 3D Secure 2 无感认证流程(Frictionless)

在无感认证流程中,收单机构、发卡行和卡组织在后台交换所需信息,通过用户的设备指纹完成被动认证。整个交易无需用户进一步操作。

B. 3D Secure 2 挑战认证流程(Challenge)

在挑战认证流程中,发卡行要求用户进一步操作,例如生物识别、双因素认证、输入手机收到的一次性验证码,或输入密码。

C. EVO Payment 实现方式

在 EVO Payment 中,每个商户会在门店层级配置以下选项之一:

  1. 无需认证(Non-Authentication):

    • 门店未开通认证,所有支付都不会进入认证流程。
    • 在此选项下,无法启用令牌化功能。
  2. 强制认证(Require-Authentication):

    • 门店的每笔卡支付都必须进行认证。
    • 你必须在首次支付请求中提交认证相关字段。
    • 在此选项下,配置好令牌化所需参数后,即可启用令牌化功能。
    • 认证完成后,应答报文中会返回认证结果参数 threeDS.mpiData 或 securePlus.securePlusData。
  3. 可选认证(Optional-Authentication):

    • 发起支付请求时,由你通过 allowAuthentication 字段决定支付前是否进行认证。
    • 如果 allowAuthentication 设为 true,你必须在首次支付请求中提交认证相关字段。
    • 在此选项下,配置好令牌化所需参数后,即可启用令牌化功能。
    • 认证完成后,应答报文中会返回认证结果参数 threeDS.mpiData 或 securePlus.securePlusData。

EVO Payment 3D Secure 支持方案

EVO Payment 提供以下 2 种方案,支持两个 3D Secure 版本:

  1. 3D Secure 2 重定向方案:

    • 支持 3D Secure 最快的接入方式:将用户重定向到另一个站点完成支付验证。
    • 该模式名为 threeDSPage,是接入 3D Secure 时 EVO Payment 的默认设置;如需使用另一种方案,请将 authentication.type 设为 threeDSIntegrator。
  2. 3D Secure 2 原生方案:

    • 在你的网站或移动 App 内完成 3D Secure 2 认证,提供更好的用户体验。

3D Secure 2 重定向方案 ​

EVO Payment 通过重定向实现 3D Secure 2。EVO Payment 会检查发卡行支持的版本,并提供一个重定向 URL,用户在该页面完成 3D Secure 2 认证。

这是支持 3D Secure 最简单的方式,大部分后台处理步骤都由 EVO Payment 提供的重定向 URL 完成。

上图描述了你需要实现的服务端集成和客户端实现。

步骤 1:采集附加参数 ​

除了支付 / 令牌化中采集的基础参数外,你还需要向用户采集额外信息以进行 3D Secure 认证。附加参数列表可以从 /g2/v1/payment/mer/{sid}/paymentMethod 的 HTTP GET 应答中返回的 authenticationInfo 数组获取。详见“支付”章节的步骤 2。

万事达要求发起 3DS 认证时请尽量完整准确上送持卡人数据。持卡人标识、地址/收货、技术三类各至少提供一个完整且准确字段(当地法规禁止除外);上送 email 可同时满足“持卡人标识”与“地址/收货”两类。

步骤 2:发起支付或令牌化 ​

采集到附加参数后,从你的服务端向 EVO Payment 发起 HTTP POST 请求:

支付请求地址:

/g2/v1/payment/mer/{sid}/payment

令牌化请求地址:

/g2/v1/payment/mer/{sid}/paymentMethod

threeDSPage 模式下,进行 3D Secure 认证需要在请求中额外携带以下参数(M = 必填,O = 可选):

Body 参数是否必填说明
authenticationO支付或令牌化前用于用户认证的信息。
transInitiatorM支付或令牌化前用于用户认证的信息。
transInitiator.browserInfoO用于 3DS 认证的用户浏览器信息,会发送给认证服务提供方。
userInfoO支付或令牌化前用于用户认证的信息。
returnURLM用户完成认证后重定向回的 URL。
authenticationOnlyO在 POST /g2/v1/payment/mer/{sid}/payment 请求中,表示是否为仅认证的支付请求。详见“仅认证”章节。
allowAuthenticationO门店配置为可选认证时适用。在 POST /g2/v1/payment/mer/{sid}/payment 或 POST /g2/v1/payment/mer/{sid}/paymentMethod 请求中,表示该笔支付是否需要进行认证。注意:authenticationOnly 为 true 时该字段不适用。

authentication 对象详细说明:

  1. authentication.type:该笔支付使用的认证模式,可选。可设为 threeDSPage(也是默认值),告知 EVO Payment 你要使用 3D Secure 2 重定向方案。

  2. authentication.threeDS.merchantRiskIndicator:包含 3D Secure 2 附加风险字段的对象,可选。详见 EVO Payment API 规范。

transInitiator 对象详细说明:

  1. transInitiator.userCreateIP:发起支付的设备 IP 地址,可选。

  2. transInitiator.browserInfo.acceptHeader:用户浏览器的 accept header 值,必填。

  3. transInitiator.browserInfo.colorDepth:用户浏览器的颜色深度(单位:位/像素),必填。通过浏览器的 screen.colorDepth 属性获取。可接受的值:1、4、8、15、16、24、32 或 48 位。

  4. transInitiator.browserInfo.javaEnabled:布尔值,表示用户浏览器是否能执行 Java,必填。

  5. transInitiator.browserInfo.language:按 IETF BCP47 定义的浏览器语言,必填。通过浏览器的 navigator.language 属性获取。例如 NL、FR、US。

  6. transInitiator.browserInfo.screenHeight:用户屏幕总高度(单位:像素),必填。通过浏览器的 screen.height 属性获取。

  7. transInitiator.browserInfo.screenWidth:用户屏幕总宽度(单位:像素),必填。通过浏览器的 screen.width 属性获取。

  8. transInitiator.browserInfo.timeZoneOffset:UTC 时间与用户浏览器本地时间的差值(单位:分钟),必填。通过浏览器的 getTimezoneOffset() 方法获取。

  9. transInitiator.browserInfo.userAgent:用户浏览器的 user agent 值,必填。

userInfo 对象详细说明:

  1. userInfo.billingAddress:包含用户账单地址的对象,可选。详见 EVO Payment API 规范。

  2. userInfo.deliveryAddress:包含商品收货地址的对象,可选。详见 EVO Payment API 规范。

  3. userInfo.accountInfo:包含 3D Secure 2 所需用户账户信息的对象,可选。详见 EVO Payment API 规范。

  4. userInfo.email:用户邮箱地址,可选。

以下示例为一笔需要 3D Secure 认证的 10 USD 信用卡支付:

js
curl -X POST https://{EVO_Cloud_DOMAIN_NAME.com}/g2/v1/payment/mer/{sid}/payment \
-H "Content-Type: application/json" \
-H "DateTime: 2021-12-31T08:30:59+0800" \
-H "MsgID: 2d21a5715c034efb7e0aa383b885fc7a" \
-H "SignType: SHA256" \
-H "Authorization: YOUR_MESSAGE_SIGNATURE" \
-d '{
    "merchantTransInfo": {
        "merchantTransID": "f2d45e3397704f2a818b7b74bc94e7ce",
        "merchantTransTime": "2021-12-31T08:30:59+08:00"
    },
    "transAmount": {
        "currency": "USD",
        "value": "10.00"
    },
    "allowAuthentication": true,
    "returnURL": "https://YOUR_COMPANY.com/RETURNURL",
    "paymentMethod": {
        "type": "card",
        "card": {
            "cardInfo": {
                "cardNumber": "4761340000000019",
                "expiryDate": "2212",
                "cvc": "946"
            }
        }
    },
    "transInitiator": {
        "browserInfo": {
            "acceptHeader": "application/json, text/plain, */*",
            "colorDepth": "1",
            "javaEnabled": true,
            "language": "US",
            "screenHeight": "300",
            "screenWidth": "200",
            "timeZoneOffset": "480",
            "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
        }
    },
    "webhook": "https://YOUR_COMPANY.com/WEBHOOK",
    "metadata": "This is a metadata"
}'

如果应答中没有 action 对象,使用 result.code 和 payment.status / paymentMethod.token.status 向用户展示支付 / 令牌化结果。

否则,说明还需要额外步骤才能完成支付 / 令牌化。你需要把 action 对象发给 Web 前端或客户端 App,然后进入下一步。

以下为需要重定向的支付应答示例:

js
{
    "result": {
        "code": "S0000",
        "message": "Success"
    },
    "action": {
        "type": "threeDSRedirect",
        "threeDSData": {
            "url": "https://YOUR_REDIRECT_URL",
            "method": "GET"
        }
    },
    "paymentMethod": {
        "card": {
            "first6No": "476134",
            "last4No": "0019",
            "paymentBrand": "Visa",
            "fundingType": "credit"
        }
    },
    "payment": {
        "status": "Verifying",
        "merchantTransInfo": {
            "merchantTransID": "f2d45e3397704f2a818b7b74bc94e7ce",
            "merchantTransTime": "2021-12-31T08:30:59+08:00"
        },
        "evoTransInfo": {
            "evoTransID": "8a0d5cd24b5b4156b94010cee115bceb",
            "evoTransTime": "2021-12-31T00:30:59Z"
        },
        "pspTransInfo": {
            "pspTransTime": "2021-12-31T08:30:59+08:00",
            "authorizationCode": "091410"
        },
        "transAmount": {
            "currency": "USD",
            "value": "10.00"
        }
    },
    "pspData": {
        "name": "Visa"
    },
    "metadata": "This is a metadata"
}

步骤 3:处理 threeDSRedirect ​

在 3D Secure 2 重定向方案下(authentication.type 为 threeDSPage),应答中收到的 action.type 通常是 threeDSRedirect,表示你需要使用同一应答中的 action.threeDSData,将用户重定向到 EVO Payment 托管页面完成 3DS 2 认证。

A. 将用户重定向到 EVO Payment 托管页面

使用 action.threeDSData.method 指定的 HTTP 方法,将用户重定向到 action.threeDSData.url。

以下为 action.threeDSData.method 为 GET 时,在前端执行 threeDSRedirect 操作的示例:

:::tip[提示]

用户随后会被重定向到 EVO Payment 托管页面,EVO Payment 会与用户及发卡行 ACS 完成后续的 3D Secure 认证流程。

:::

B. 用户完成认证后重定向回商户

EVO Payment 会在 10 分钟内通过 HTTP GET 请求将用户重定向回你的 returnURL。你可以用应答中的 merchantTransID 参数匹配首次请求。

  • 如果应答中的 status 参数为 finished,表示 3D Secure 认证成功。你需要调用 GET 接口或接收 EVO Payment 的通知来获取交易详情。
  • 如果 10 分钟内没有收到任何应答,或 status 参数不是 finished,表示 3D Secure 认证失败。此时同样应调用 GET 接口或接收 EVO Payment 的通知来获取交易详情。

步骤 4:展示结果 ​

用户完成支付或令牌化、前端或客户端 App 无需进一步操作后,你可以接收通知或发起 GET 请求获取详情。使用 result.code 和 payment.status / paymentMethod.status 告知用户支付或令牌化的状态。

结果码说明
S0000Success

其他可能的 result.code 值及建议向用户展示的提示信息,见 EVO Payment API 规范附录。

状态说明
Authorised用于卡交易,表示交易授权已成功,等待完成(商户可发起撤销)。
Captured卡交易表示授权和完成均已成功;电子钱包交易表示交易已成功。
Failed支付失败
状态说明
Success令牌已创建
Failed令牌创建失败

其他可能的 payment.status / paymentMethod.status 值及说明,见 EVO Payment API 规范中的 payment.status / paymentMethod.status。

异常处理 ​

  • 向 EVO Payment 发起的 HTTP POST 请求:建议请求发出后至少等待 45 秒。如果在该时间内没有收到应答,需要向 EVO Payment 查询结果。发起查询请参考“支付 / 令牌化”章节的步骤 6。
  • 向 EVO Payment 发起的 HTTP PUT 请求:HTTP PUT 请求是幂等的。如果在一定时间内(例如 45 秒)没有收到 EVO Payment 的应答,可以用完全相同的请求报文重新发送。多次重发仍未收到应答时,可以改为发起一笔新的支付 / 令牌化请求。

3D Secure 2 原生方案 ​

EVO Payment 可以通过原生方式实现 3D Secure 2,提供更好的用户体验。

步骤 1:采集附加参数 ​

此步骤与“3D Secure 2 重定向方案”的步骤 1 相同,详见该章节。

万事达要求发起 3DS 认证时请尽量完整准确上送持卡人数据。持卡人标识、地址/收货、技术三类各至少提供一个完整且准确字段(当地法规禁止除外);上送 email 可同时满足“持卡人标识”与“地址/收货”两类。

步骤 2:发起支付或令牌化 ​

此步骤与“3D Secure 2 重定向方案”的步骤 2 相同,详见该章节。区别仅在于:

  1. POST 请求中需将 authentication.type 设为 threeDSIntegrator,而不是 threeDSPage。
  2. POST 请求中需传入 transInitiator.browserInfo。
  3. 建议在 returnURL 中带上你的 merchantTransInfo.merchantTransID,便于后续步骤处理应答。例如:R_COMPANY.com/RETURNURL/YOUR_MERCHANT_TRANS_ID。
  4. 除了 action.type 为 threeDSRedirect 外,EVO Payment 的应答中还可能返回 threeDSIdentify 或 threeDSChallenge。

步骤 3-1:处理 threeDSIdentify ​

如果服务端收到 action.type 为 threeDSIdentify,你需要执行 3D Secure 2 设备指纹采集。

A. 创建 iframe 并向发卡行发起设备指纹请求

在浏览器中渲染一个隐藏的 HTML iframe,并在 iframe 中使用 action.threeDSData.method 指定的 HTTP 方法向 action.threeDSData.url 发起 HTTP 请求。

如果 action.threeDSData.method 为 GET:

js
curl {action.threeDSData.url}

如果 action.threeDSData.method 为 POST 且存在 action.threeDSData.parameter,则 action.threeDSData.parameter 中应包含 base64 编码的 threeDSMethodData:

js
{
    "threeDSMethodData": "eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9ZT1VSX0NPTVBBTlkuY29tL1JFVFVSTlVSTCIsInRocmVlRFNTZXJ2ZXJUcmFuc0lEIjoiN2MzOWJkOTYtOThlZS00N2IwLTgzYWYtNjMwNjE2NmE3MDE4In0="
}

此时需要在前端通过表单 POST 执行 threeDSIdentify 操作:

js
<form method="POST" action="{action.threeDSData.url}" id="threeDSIdentify" target="NAME_OF_YOUR_IFRAME">
  <input type="hidden" name="threeDSMethodData" value="eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9ZT1VSX0NPTVBBTlkuY29tL1JFVFVSTlVSTCIsInRocmVlRFNTZXJ2ZXJUcmFuc0lEIjoiN2MzOWJkOTYtOThlZS00N2IwLTgzYWYtNjMwNjE2NmE3MDE4In0=" />
</form>

POST 请求中 key 的大小写必须与 EVO Payment 应答中 action.threeDSData.parameter 返回的参数名保持一致。

提示:

  • 如果之前的 POST 请求中 returnURL 没有带 merchantTransID,你需要对 base64 编码的 threeDSMethodData 进行解码。
  • 从解码后的数据中获取并保存 threeDSServerTransID,用于下一步处理应答。

B. 在 Return URL 等待设备指纹结果

从发起请求开始,在 returnURL 上等待发卡行推送的应答,等待时长 10 秒。使用 returnURL 中的 merchantTransID 匹配首次请求:

  • 将 threeDSCompInd 标记为 Y。
  • 保存应答中的 threeDSMethodData 参数,进入下一步。

如果 returnURL 中没有带 merchantTransID,你需要:

  1. 使用 base64 方法解码应答中的 threeDSMethodData 参数。
  2. 获取 threeDSServerTransID 以匹配首次请求。

如果 10 秒内没有收到任何应答,或应答中取不到 threeDSMethodData 参数,可将 threeDSCompInd 标记为 N,进入下一步。

C. 提交设备指纹结果

从服务端向 EVO Payment 发起 HTTP PUT 请求:

  • 支付:/g2/v1/payment/mer/{sid}/payment
  • 令牌化:/g2/v1/payment/mer/{sid}/paymentMethod

需传入以下参数:

Query 参数是否必填说明
merchantTransIDM首次支付 / 令牌化请求中的 merchantTransInfo.merchantTransID。
Body 参数是否必填说明
authentication.threeDS.redirectData.threeDSCompIndM设备指纹采集结果。

示例:

js
curl -X PUT https://{EVO_Cloud_DOMAIN_NAME.com}/g2/v1/payment/mer/{sid}/payment?merchantTransID={YOUR_TRANS_ID_OF_INITIAL_REQUEST} \
-H "Content-Type: application/json" \
-H "DateTime: 2021-12-31T08:30:59+0800" \
-H "MsgID: 2d21a5715c034efb7e0aa383b885fc7a" \
-H "SignType: SHA256" \
-H "Authorization: YOUR_MESSAGE_SIGNATURE" \
-d '{
    "authentication": {
        "threeDS": {
            "redirectData": {
                "threeDSCompInd": "Y"
            }
        }
    },
    "metadata": "This is a metadata"
}'

如果应答中不含 action 对象,可使用 result.code 和 payment.status / paymentMethod.token.status 向用户展示支付 / 令牌化结果。

如果应答中包含 action 对象,说明还需要额外步骤才能完成支付 / 令牌化。你需要把 action 对象发给 Web 前端或客户端 App,然后进入下一步。

以下为需要用户进行挑战认证的应答示例:

js
{
    "result": {
        "code": "S0000",
        "message": "Success"
    },
    "action": {
        "type": "threeDSChallenge",
        "threeDSData": {
            "url": "https://YOUR_REDIRECT_URL",
            "method": "GET",
            "parameter": {
                "creq": "eyJtZXNzYWdlVHlwZSI6IkNSZXEiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMS4wIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiI3YzM5YmQ5Ni05OGVlLTQ3YjAtODNhZi02MzA2MTY2YTcwMTgiLCJhY3nUcmFuc0lEIjoiMTE4ZDNiNjEtYjU5Ny00Nzg2LTg1ZWMtNzA0Mzc3ZDhjMWU4IiwiY2hhbGxlbmdlV2luZG93U2l6ZSI6IjAyIn0="
            }
        }
    },
    "paymentMethod": {
        "card": {
            "first6No": "476134",
            "last4No": "0019",
            "paymentBrand": "Visa",
            "fundingType": "credit"
        }
    },
    "authentication": {
        "type": "threeDSIntegrator"
    },
    "payment": {
        "status": "Verifying",
        "merchantTransInfo": {
            "merchantTransID": "f2d45e3397704f2a818b7b74bc94e7ce",
            "merchantTransTime": "2021-12-31T08:30:59+08:00"
        },
        "evoTransInfo": {
            "evoTransID": "8a0d5cd24b5b4156b94010cee115bceb",
            "evoTransTime": "2021-12-31T00:30:59Z"
        },
        "pspTransInfo": {
            "pspTransTime": "2021-12-31T08:30:59+08:00",
            "authorizationCode": "091410"
        },
        "transAmount": {
            "currency": "USD",
            "value": "10.00"
        }
    },
    "pspData": {
        "name": "Visa"
    },
    "metadata": "This is a metadata"
}

步骤 3-2:处理 threeDSChallenge ​

如果服务端收到 action.type 为 threeDSChallenge,表示发卡行要进行额外校验,确认该用户确实是持卡人本人。

A. 创建 iframe 并向发卡行发送 cReq(挑战请求)

在浏览器中渲染一个 HTML iframe,并在 iframe 中使用 action.threeDSData.method 指定的 HTTP 方法向 action.threeDSData.url 发起 HTTP 请求。

如果 action.threeDSData.method 为 POST 且存在 action.threeDSData.parameter,将 parameter 对象中的子字段作为 POST 请求的表单数据传入。iframe 中会随之打开挑战窗口。

在前端执行 threeDSChallenge 操作的示例(GET 方法):

bash
curl {action.threeDSData.url}

如果 action.threeDSData.method 为 POST 且存在 action.threeDSData.parameter,则 action.threeDSData.parameter 中应包含 base64 编码的 creq:

js
{
    "creq": "eyJtZXNzYWdlVHlwZSI6IkNSZXEiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMS4wIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiI3YzM5YmQ5Ni05OGVlLTQ3YjAtODNhZi02MzA2MTY2YTcwMTgiLCJhY3nUcmFuc0lEIjoiMTE4ZDNiNjEtYjU5Ny00Nzg2LTg1ZWMtNzA0Mzc3ZDhjMWU4IiwiY2hhbGVuZ2V3aW5kb3dTaXplIjoiMDIifQ=="
}

此时需要在前端通过表单 POST 执行 threeDSData 操作:

js
<form method="POST" action="{action.threeDSData.url}" id="threeDSChallenge" target="NAME_OF_YOUR_IFRAME">
  <input name="creq" value="eyJtZXNzYWdlVHlwZSI6IkNSZXEiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMS4wIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiI3YzM5YmQ5Ni05OGVlLTQ3YjAtODNhZi02MzA2MTY2YTcwMTgiLCJhY3nUcmFuc0lEIjoiMTE4ZDNiNjEtYjU5Ny00Nzg2LTg1ZWMtNzA0Mzc3ZDhjMWU4IiwiY2hhbGxlbmdlV2luZG93U2l6ZSI6IjAyIn0=" />
</form>

POST 请求中 key 的大小写必须与 EVO Payment 应答中 action.threeDSData.parameter 返回的参数名保持一致。

:::tip[提示]

如果之前的 POST 请求中 returnURL 没有带 merchantTransID,你需要对 base64 编码的 creq 进行解码,从解码后的数据中获取并保存 threeDSServerTransID,用于下一步处理应答。

:::

B. 在 Return URL 等待 cRes(挑战应答)

从发送请求开始,在 returnURL 上等待发卡行推送的应答,等待时长 10 分钟。使用 returnURL 中的 merchantTransID 匹配首次请求:

  • 将 threeDSFinished 标记为 Y。
  • 保存应答中的 cres 参数,然后进入下一步。

提示:

  • 如果 returnURL 中没有带 merchantTransID,你需要使用 base64 方法解码应答中的 cres 参数,并获取 threeDSServerTransID 以匹配首次请求。
  • 如果 10 分钟内没有收到任何应答,或应答中取不到 cres 参数,可将 threeDSFinished 标记为 N,进入下一步。

C. 提交挑战结果

从服务端向 EVO Payment 发起 HTTP PUT 请求:

  • 支付:/g2/v1/payment/mer/{sid}/payment
  • 令牌化:/g2/v1/payment/mer/{sid}/paymentMethod

需传入以下参数:

Query 参数是否必填说明
merchantTransIDM首次支付 / 令牌化请求中的 merchantTransInfo.merchantTransID。
Body 参数是否必填说明
authentication.threeDS.redirectData.threeDSFinishedM挑战结果。
authentication.threeDS.redirectData.cresO发卡行在推送到你 returnURL 的应答中返回的挑战应答,base64 编码。请不要解码,原样转发给 EVO Payment。

示例:

js
curl -X PUT https://{EVO_Cloud_DOMAIN_NAME.com}/g2/v1/payment/mer/{sid}/payment?merchantTransID={YOUR_TRANS_ID_OF_INITIAL_REQUEST} \
-H "Content-Type: application/json" \
-H "DateTime: 2021-12-31T08:30:59+0800" \
-H "MsgID: 2d21a5715c034efb7e0aa383b885fc7a" \
-H "SignType: SHA256" \
-H "Authorization: YOUR_MESSAGE_SIGNATURE" \
-d '{
    "authentication": {
        "threeDS": {
            "redirectData": {
                   "cres":"eyJtZXNzYWdlVHlwZSI6IkNSZXMiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMS4wIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiI3YzM5YmQ5Ni05OGVlLTQ3YjAtODNhZi02MzA2MTY2YTcwMTgiLCJhY3nUcmFuc0lEIjoiMTE4ZDNiNjEtYjU5Ny00Nzg2LTg1ZWMtNzA0Mzc3ZDhjMWU4IiwiY2hhbGxlbmdlQ29tcGxldGlvbkluZCI6IlkiLCJ0cmFuc1N0YXR1cyI6IlkifQ==",
                "threeDSFinished": "Y"
            }
        }
    },
    "metadata": "This is a metadata"
}'

INFO

如果支付或令牌化成功,你会收到 result.code 为 S0000,表示成功。

js
{
    "result": {
        "code": "S0000",
        "message": "Success",
        "pspResponseCode": "00",
        "pspMessage": " Approval and completed successfully; Accepted and processed"
    },
    "paymentMethod": {
        "card": {
            "first6No": "476134",
            "last4No": "0019",
            "paymentBrand": "Visa",
            "fundingType": "credit"
        }
    },
    "authentication": {
        "type": "threeDSIntegrator",
        "threeDS": {
            "mpiData": {
                "status": "Y",
                "eci": "05"
            }
        }
    },
    "payment": {
        "status": "Authorised",
        "merchantTransInfo": {
            "merchantTransID": "f2d45e3397704f2a818b7b74bc94e7ce",
            "merchantTransTime": "2021-12-31T08:30:59+08:00"
        },
        "evoTransInfo": {
            "evoTransID": "8a0d5cd24b5b4156b94010cee115bceb",
            "evoTransTime": "2021-12-31T00:30:59Z"
        },
        "pspTransInfo": {
            "pspTransTime": "2021-12-31T08:30:59+08:00",
            "authorizationCode": "091410"
        },
        "transAmount": {
            "currency": "USD",
            "value": "10.00"
        }
    },
    "pspData": {
        "name": "Visa"
    },
    "metadata": "This is a metadata"
}

步骤 4:展示结果 ​

用户完成支付或令牌化、前端或客户端 App 无需进一步操作后,使用 result.code 和 payment.status / paymentMethod.status 告知用户支付或令牌化的状态。

结果码说明
S0000Success
V0007Missing field {} when
B0025Authentication not finished
B00263DS version not supported

其他可能的 result.code 值及建议向用户展示的提示信息,见 EVO Payment API 规范附录。

如果 result.code 为 S0000,还需要检查 payment.status / paymentMethod.status,确定支付或令牌化状态并告知用户。

状态说明
Authorised用于卡交易,表示交易授权已成功,等待完成(商户可发起撤销)。
Captured卡交易表示授权和完成均已成功;电子钱包交易表示交易已成功。
Failed支付失败。
状态说明
Success令牌已创建。
Failed令牌创建失败。

其他可能的 payment.status / paymentMethod.status 值及说明,见 EVO Payment API 规范中的 payment.status / paymentMethod.status 部分。

异常处理 ​

向 EVO Payment 发起的 HTTP POST 请求:建议请求发出后至少等待 45 秒。如果在该时间内没有收到应答,需要向 EVO Payment 查询结果。发起查询请参考“支付 / 令牌化”章节的步骤 6。

向 EVO Payment 发起的 HTTP PUT 请求:HTTP PUT 请求是幂等的。如果在一定时间内(例如 45 秒)没有收到 EVO Payment 的应答,可以用完全相同的请求报文重新发送。多次重发仍未收到应答时,可以改为发起一笔新的支付 / 令牌化请求。