接口参考
接入发卡事件推送前,请先阅读本页公共规则。Onerway 会将卡操作、卡交易和 3DS 事件推送到商户配置的回调地址。
报文头
| Header | 类型 | 必填 | 说明 |
|---|---|---|---|
Content-Type | String | 是 | 固定为 application/json;charset=UTF-8。 |
x-timestamp | String | 是 | Unix 秒级时间戳。 |
x-signature | String | 是 | 使用 webhook_secret、x-timestamp + "." + raw_body 生成 HMAC-SHA256 签名,参考验签与签名。 |
报文结构
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id | String | 是 | 唯一事件标识,用于幂等去重。 |
event_type | String | 是 | 事件类型。发卡当前推送 issuing.cardOperateEvent、issuing.cardTransactionEvent 和 issuing.card3dsEvent。 |
created_at | String | 是 | 事件创建时间,ISO 8601 格式。 |
version | String | 否 | 创建 Webhook 订阅时选择的 API 版本;未指定时默认为 1.0。 |
data | Object | 是 | 业务数据,结构随 event_type 变化。 |
商户响应要求
商户回调接口必须返回 JSON 响应。Onerway 根据该响应判断推送是否成功。
| 字段 | 类型 | 说明 |
|---|---|---|
respCode | String | 返回 20000 表示确认收到。 |
respMsg | String | 响应信息。 |
如果回调响应码不是 20000,Onerway 会每 15 秒重试一次,最多重试 10 次。
验签与签名
Onerway 会对卡操作、卡交易和 3DS 等异步通知进行签名。商户处理事件前应先完成验签。
签名原文按以下方式拼接:
x-timestamp + "." + raw_body
使用 HMAC-SHA256 生成期望签名,并与 x-signature 进行大小写不敏感比较。
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.HexFormat;
public final class HmacSHA256Util {
private HmacSHA256Util() {
}
public static String signHmacSHA256(String webhook_secret, String content) throws Exception {
byte[] key = Base64.getDecoder().decode(webhook_secret);
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
return HexFormat.of().formatHex(mac.doFinal(content.getBytes(StandardCharsets.UTF_8)));
}
public static boolean verifyHmacSHA256(String webhook_secret, String content, String signed) throws Exception {
String expected = signHmacSHA256(webhook_secret, content);
return MessageDigest.isEqual(
expected.toLowerCase().getBytes(StandardCharsets.UTF_8),
signed.toLowerCase().getBytes(StandardCharsets.UTF_8)
);
}
}
import base64
import hashlib
import hmac
def sign_hmac_sha256(webhook_secret: str, content: str) -> str:
key = base64.b64decode(webhook_secret)
return hmac.new(key, content.encode("utf-8"), hashlib.sha256).hexdigest()
def verify_hmac_sha256(webhook_secret: str, content: str, signed: str) -> bool:
expected = sign_hmac_sha256(webhook_secret, content)
return hmac.compare_digest(expected.lower(), signed.lower())
<?php
final class HmacSHA256Util
{
public static function signHmacSHA256(string $webhook_secret, string $content): string
{
$key = base64_decode($webhook_secret, true);
if ($key === false) {
throw new InvalidArgumentException('Invalid webhook secret.');
}
return hash_hmac('sha256', $content, $key);
}
public static function verifyHmacSHA256(string $webhook_secret, string $content, string $signed): bool
{
$expected = self::signHmacSHA256($webhook_secret, $content);
return hash_equals(strtolower($expected), strtolower($signed));
}
}