Cancel
适用于 EC 和 In-Store(线下)场景。
如果您已预授权一笔支付但不希望 Capture 该笔支付(例如由于商品缺货或系统超时错误),您需要 cancel 该笔支付。
- 适用的支付方式(Applicable Payment Methods):您只能对支持 Authorization 与 Capture 分离的支付方式执行 cancel,并且必须在支付被 Capture 之前完成。
- 时效(Timing):建议在 Authorization 后的 7 天内 发起 cancel 请求,因为大多数发卡行会在该时限后清除预授权。
- Cancel 金额(Cancel Amount):Cancel 金额始终与初始 Payment 金额相同,因此您在 cancel 请求中无需指定金额参数。
Make cancel request
Step 1: Make a cancel request
当您收到 payment.status 为 Authorised、Pending 或 Verifying 的支付结果,或如果支付超时时,您可以从您的服务器向 EVO Payment 端点
/g2/v1/payment/mer/{sid}/cancel
发起 HTTP POST 请求以 cancel 该笔支付,
并指定以下参数。
| 参数 | 必填 | 说明 |
|---|---|---|
merchantTransID | M | 初始 Payment 的 merchantTransInfo.merchantTransID。 |
| 参数 | 必填 | 说明 |
|---|---|---|
merchantTransInfo | M | 本次 cancel 的引用信息,包含唯一的 merchantTransID 和 merchantTransTime(发起请求的时间)。 |
initiatingReason | O | 可选:本次请求的原因。 |
webhook | O | 用于接收通知的 URL。指定后可在支付成功后从 EVO Payment 接收通知。 |
paymentMethod | O | 支付方式对象。 |
paymentMethod.type | O | 本文档场景下须为 card。 |
metadata | O | 您可在请求中自定义的引用信息,将在响应中原样回显。Notification 中的 metadata 与请求中的 metadata 一致。 |
paymentMethod 对象的更多细节:
1.paymentMethod.type:请求中设置为 card。
2.paymentMethod.card.encryptedCardInfo:加密后的卡信息。如果使用 EVO Payment 客户端方案安全加密用户卡信息,前端会从 EVO Payment SDK 获取该值,需发送至您的服务器,再由服务器原样转发至 EVO Payment。
3.paymentMethod.card.cardInfo:卡信息原始数据。如果将原始卡数据采集并发送至 EVO Payment,需要在此对象中指定 cardNumber、expiryDate、cvc(可选)、track2 与 holderName。对于部分 UnionPay 借记卡,expiryDate 也为可选。 (如果 paymentMethod.card.encryptedCardInfo 和 paymentMethod.card.cardInfo 同时存在,将以 paymentMethod.card.cardInfo 为准。)
4.paymentMethod.card字段
| 字段路径 | 必填/选填 | 条件 | 说明 |
|---|---|---|---|
paymentMethod.card | M | paymentMethod.type=card | 卡相关交易对象。 |
paymentMethod.card.encryptedCardInfo | O | 已批准加密卡集成方案 | 加密卡信息。 |
paymentMethod.card.cardInfo | O | 已批准卡信息集成方案 | 卡信息容器。 |
paymentMethod.card.cardInfo.cardNumber | M | 手动/MOTO 或最终 schema 要求 | 卡号。在示例或测试数据中请勿使用真实值。 |
paymentMethod.card.cardInfo.expiryDate | O | MOTO 必填 | 过期日期,MMYY 格式。 |
paymentMethod.card.posEntryMode | O | POS 卡通道 | 卡数据输入方式。 |
paymentMethod.card.pinFlag | O | 终端支持 PIN | true 表示终端可接受 PIN;false 表示不接受。 |
paymentMethod.card.termReadability | O | 提供终端能力时 | 终端卡数据输入能力。 |
paymentMethod.card.icCardCondCode | O | UnionPay IC 场景 | UnionPay 卡条件码。 |
paymentMethod.card.noSecretNoSignFlag | O | UnionPay 场景 | UnionPay 无密/无签标识。 |
paymentMethod.card.cardInfo.track1 | O | 磁条或特定通道要求 | Track 1 数据。最终字段名以已批准的 schema 为准。 |
paymentMethod.card.cardInfo.track2 | O | 磁条、ICC、contactless 或 fallback 场景 | Track 2 数据。禁止以明文存储或记录。 |
paymentMethod.card.cardInfo.cardSequenceNum | O | ICC 或 contactless 场景 | IC 卡序列号。 |
paymentMethod.card.cardInfo.icCardData | O | ICC 或 contactless 场景 | EMV/ICC TLV 数据。 |
paymentMethod.card.pin | O | PIN 交易 | PIN 容器(如最终 schema 中包含)。 |
paymentMethod.card.pin.encryptedPin | M | PIN 交易 | 加密后的 PIN block。禁止以明文记录或持久化。 |
paymentMethod.card.pin.pinEncryptMethod | M | PIN 交易 | 已批准的 PIN 加密方式,例如支持时的 3DES。 |
paymentMethod.card.pin.checkValue | O | 启用密钥版本查询 | 用于识别适用工作密钥版本的值(如支持)。 |
5.Card posEntryMode 模式
| posEntryMode 模式 | 交易活动 | 典型条件数据 |
|---|---|---|
magnetic | 磁条读取 | track2 |
ICC | 接触式芯片插入 | track2 、icCardData 、cardSequenceNum |
contactless | NFC EMV 挥卡 | track2 、icCardData 、cardSequenceNum |
contactless magnetic | 使用磁条通道的 contactless 交易 | track2 |
fallback | EMV 回退至磁条 | track2 |
manual | 手工输入卡 | cardNumber 、expiryDate |
MOTO | 邮购/电话订购 | cardNumber 、expiryDate |
最终 API schema 是字段名、长度、条件必填与 PSP 特定限制的权威依据。
以下为 cancel 请求示例:
curl -X POST https://{EVO_Cloud_DOMAIN_NAME.com}/g2/v1/payment/mer/{sid}/cancel?merchantTransID={YOUR_TRANS_ID_OF_INITIAL_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": "YOUR_TRANS_ID_OF_INITIAL_CANCEL",
"merchantTransTime": "2021-12-31T08:35:59+08:00"
},
"paymentMethod": {
"type": "card",
"card": {
"posEntryMode": "ICC",
"pinFlag": true,
"cardInfo": {
"cardNumber": "6222021234567890123",
"track2": "6222021234567890123=26122011234567890123",
"icCardData": "9F02069F03069F1A029F26089F27019F36029F37049F1008",
"cardSequenceNum": "001"
},
"pin": {
"encryptedPin": "base64encodedPinBlock==",
"pinEncryptMethod": "3DES",
"checkValue": "A1B2C3"
}
}
},
"webhook": "https://YOUR_COMPANY.com/WEBHOOK",
"initiatingReason": "Customer cancels order",
"metadata": "This is a metadata" ,
"transInitiator": {
"platform": "POS",
"terminalID": "30100101",
"paymentScenario": "inStore"
}
}'如果请求成功,响应中将包含一个 cancel 对象和一个 payment 对象,分别提供 cancel 和原始 payment 的状态及相关信息。
cancel.status:本次 cancel 的状态,必填。取值可为Success、Failed或Received。如果cancel.status为Received,您需要再发起一次 HTTP GET 请求以获取 cancel 的最终状态(详见 Step 2),或等待 EVO Payment 的通知 webhook。cancel.merchantTransInfo:本次 cancel 的引用对象,由您的服务器生成,必填。从您的请求中原样回显。cancel.evoTransInfo:本次 cancel 的引用对象,由 EVO Payment 生成,必填。包含evoTransID和evoTransTime。cancel.pspTransInfo:本次 cancel 的引用对象,由 PSP 生成,可选。包含pspTransID和pspTransTime。如果 PSP 返回,EVO Payment 会将该信息从 PSP 转发至您的服务器。
以下为成功响应示例:
{
"result": {
"code": "S0000",
"message": "Success"
},
"paymentMethod": {
"card": {
"first6No": "476134",
"last4No": "0019",
"paymentBrand": "Visa",
"fundingType": "credit"
}
},
"payment": {
"status": "Cancelling",
"merchantTransInfo": {
"merchantTransID": "37693fac0946498f8afe35b9ffdcfe89",
"merchantTransTime": "2021-12-31T08:30:59+08:00"
},
"evoTransInfo": {
"evoTransID": "ecf19b3be090407b97d74884077f08a4",
"evoTransTime": "2021-12-31T00:30:59Z"
},
"pspTransInfo": {
"pspTransTime": "2021-12-31T08:30:59+08:00",
"authorizationCode": "091410",
"retrievalReferenceNum": "135616370503"
},
"transAmount": {
"currency": "USD",
"value": "10.00"
}
},
"cancel": {
"status": "Received",
"merchantTransInfo": {
"merchantTransID": "YOUR_TRANS_ID_OF_INITIAL_CANCEL",
"merchantTransTime": "2021-12-31T08:35:59+08:00"
},
"evoTransInfo": {
"evoTransID": "a36a6c5c6b224eaf923ca2c93ff3e63a",
"evoTransTime": "2021-12-31T08:35:59+08:00"
},
"transAmount": {
"currency": "USD",
"value": "10.00"
}
},
"pspData": {
"name": "Visa"
},
"metadata": "This is a metadata"
}Step 2: Retrieve the cancel result
如果收到 cancel.status 为 Received,且您未使用 notification webhook,可以从 EVO Payment 查询最终结果。
从您的服务器向 EVO Payment 端点
/g2/v1/payment/mer/{sid}/cancel
发起 HTTP GET 请求,并指定以下参数。
| 参数 | 必填 | 说明 |
|---|---|---|
merchantTransID | M | 初始 cancel 的 merchantTransInfo.merchantTransID。 |
以下为查询 cancel 结果示例:
curl https://{EVO_Cloud_DOMAIN_NAME.com}/g2/v1/payment/mer/{sid}/cancel?merchantTransID={YOUR_TRANS_ID_OF_INITIAL_CANCEL} \
-H "Content-Type: application/json" \
-H "DateTime: 2021-12-31T08:30:59+0800" \
-H "MsgID: 2d21a5715c034efb7e0aa383b885fc7a" \
-H "SignType: SHA256" \
-H "Authorization: YOUR_MESSAGE_SIGNATURE"以下为 GET 响应示例。POST 响应与 GET 响应类似。
{
"result": {
"code": "S0000",
"message": "Success"
},
"paymentMethod": {
"card": {
"first6No": "476134",
"last4No": "0019",
"paymentBrand": "Visa",
"fundingType": "credit"
}
},
"payment": {
"status": "Cancelled",
"merchantTransInfo": {
"merchantTransID": "37693fac0946498f8afe35b9ffdcfe89",
"merchantTransTime": "2021-12-31T08:30:59+08:00"
},
"evoTransInfo": {
"evoTransID": "ecf19b3be090407b97d74884077f08a4",
"evoTransTime": "2021-12-31T00:30:59Z"
},
"pspTransInfo": {
"pspTransTime": "2021-12-31T08:30:59+08:00",
"authorizationCode": "091410",
"retrievalReferenceNum": "135616370503"
},
"transAmount": {
"currency": "USD",
"value": "10.00"
}
},
"cancel": {
"status": "Success",
"merchantTransInfo": {
"merchantTransID": "YOUR_TRANS_ID_OF_INITIAL_CANCEL",
"merchantTransTime": "2021-12-31T08:35:59+08:00"
},
"evoTransInfo": {
"evoTransID": "a36a6c5c6b224eaf923ca2c93ff3e63a",
"evoTransTime": "2021-12-31T08:35:59+08:00"
},
"pspTransInfo": {
"pspTransTime": "2021-12-31T08:30:59+08:00"
},
"transAmount": {
"currency": "USD",
"value": "10.00"
}
},
"pspData": {
"name": "Visa"
},
"metadata": "This is a metadata"
}Make a refund instead
如果您发起 cancel 请求并收到 result.code 为 B0012,请再次核对响应中 payment.status 显示的原始交易状态。如果为 Captured,则表示该笔支付已被 Capture,您无法 cancel 该笔支付。这种情况下,您需要改用 refund。详见 Refund 章节。
Error handling
For HTTP POST request to EVO Payment: 建议在请求发送后至少等待 45 秒。如果在规定时间内未收到响应,需要从 EVO Payment 查询结果。请参阅 Step 2 发起请求。
For HTTP GET request to EVO Payment: 可以多次发起请求直到获取结果,建议相邻两次请求之间至少等待 45 秒。如果多次请求后仍无法获取结果,可以改为发起一次新的 cancel 请求。

