Data Only(仅数据):最大化授权通过率
Quick Reference
什么是 Data Only?
Data Only(仅数据) 使用 EMV 3DS 基础设施与卡组、发卡行共享交易、设备与行为数据 —— 全程不向持卡人展示 challenge。发卡行获得丰富数据后,可做出更有依据的授权决策。
结果是:更高的授权通过率、不会因认证导致的购物车放弃,以及无重定向或弹窗。
为何 Data Only 重要
数据足以说明问题:
| 指标 | 数值 | 来源 |
|---|---|---|
| 误拒相对欺诈的影响 | 3 倍 —— 拒绝好客户造成的损失约为欺诈的 3 倍 | Visa Global Client |
| 美国电商欺诈(预测) | 至 2026 年达 130 亿美元 | Visa |
| 全球购物车放弃率 | 平均 70% | Baymard Institute |
| 因 3DS 摩擦导致的转化下降 | 因市场而异 2–15% | Decta / US Payments Forum |
| 美国商户 3DS 采用率 | 仅约 3% 的交易 | US Payments Forum Brief #2 |
| Square 试点(600 万笔交易,9 个月) | 每家金融机构 +23 至 +646 个基点 | Broadcom/Arcot 案例研究 |
| 拒付率改善(同一试点) | 降低 6% | Broadcom/Arcot 案例研究 |
决策矩阵
| 条件 | 完整 3DS | Data Only | 无认证 |
|---|---|---|---|
| 卡品牌 | 全部支持 | 仅 Visa 与 Mastercard | 全部 |
| 持卡人 challenge | 发卡行要求时会有 | 永不 | 永不 |
| 责任转移 | 是 | 否 | 否 |
| 对授权通过率的影响 | 可能下降(摩擦) | 上升(数据更丰富) | 基准 |
| 拒付保护 | 发卡行承担(适用责任转移时) | 商户承担 | 商户承担 |
| 发往发卡行的数据 | 设备 + 行为 + challenge 结果 | 设备 + 行为(上下文更丰富) | 无 |
| 最适合 | 高价值、强监管、PSD2/SCA 市场 | 高交易量、低风险、拉美 | 低风险、低金额 |
| PSD2/SCA 市场 | 强制要求 | 不可用(SCA 优先) | 不合规 |
同一笔收费上,data_only 与 threeds_authentication 不能同时为 true。若将 threeds_authentication 设为 true,即强制完整 3DS 认证。此时系统要求 ECI 为 02 或 05(完全认证)。
Data Only 产生 ECI 06 或 07。因此无法满足上述强制 3DS 校验。
每笔交易请选择一种策略。
工作原理
要点:发卡行同时收到两类信号。一类来自卡组的风险评估,另一类来自 device_info 的丰富数据。
信息量高于标准授权,因此发卡行可以更自信地批准。
分步集成
采集设备与浏览器数据
在客户端采集真实浏览器数值。切勿伪造 —— 合成数据会提高拒绝率。
const deviceInfo = {
ip_address: await fetch('/api/ip').then(r => r.text()),
user_agent: navigator.userAgent,
http_accept_content: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
http_accept_browser_value: '*/*',
http_browser_language: navigator.language,
http_browser_java_enabled: navigator.javaEnabled?.() ?? false,
http_browser_javascript_enabled: true,
http_browser_color_depth: String(screen.colorDepth),
http_browser_screen_height: String(screen.height),
http_browser_screen_width: String(screen.width),
http_browser_time_difference: String(new Date().getTimezoneOffset()),
};
将 deviceInfo 发送至后端用于收费请求。
认证并获取访问令牌
- cURL
- Python
- Node.js
- Go
- Java
- PHP
curl -s -X POST "https://a55-auth.auth.us-east-1.amazoncognito.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET"
import os, requests
token_resp = requests.post(
"https://a55-auth.auth.us-east-1.amazoncognito.com/oauth2/token",
data={"grant_type": "client_credentials",
"client_id": os.environ["CLIENT_ID"],
"client_secret": os.environ["CLIENT_SECRET"]},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
access_token = token_resp.json()["access_token"]
const resp = await fetch(
"https://a55-auth.auth.us-east-1.amazoncognito.com/oauth2/token",
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: "grant_type=client_credentials"
+ "&client_id=" + process.env.CLIENT_ID
+ "&client_secret=" + process.env.CLIENT_SECRET,
}
);
const { access_token } = await resp.json();
data := url.Values{
"grant_type": {"client_credentials"},
"client_id": {os.Getenv("CLIENT_ID")},
"client_secret": {os.Getenv("CLIENT_SECRET")},
}
resp, _ := http.PostForm(
"https://a55-auth.auth.us-east-1.amazoncognito.com/oauth2/token",
data,
)
defer resp.Body.Close()
var tok struct{ AccessToken string `json:"access_token"` }
json.NewDecoder(resp.Body).Decode(&tok)
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://a55-auth.auth.us-east-1.amazoncognito.com/oauth2/token"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(
"grant_type=client_credentials&client_id=" + CLIENT_ID
+ "&client_secret=" + CLIENT_SECRET))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
String accessToken = new JSONObject(resp.body()).getString("access_token");
$ch = curl_init("https://a55-auth.auth.us-east-1.amazoncognito.com/oauth2/token");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/x-www-form-urlencoded"],
CURLOPT_POSTFIELDS => http_build_query([
"grant_type" => "client_credentials",
"client_id" => getenv("CLIENT_ID"),
"client_secret" => getenv("CLIENT_SECRET"),
]),
]);
$token = json_decode(curl_exec($ch))->access_token;
创建收费并设置 data_only: true
设置 data_only: true,并包含步骤 1 中的完整 device_info 对象。
- cURL
- Python
- Node.js
- Go
- Java
- PHP
curl -sS -X POST "https://core-manager.a55.tech/api/v1/bank/wallet/charge/" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: dataonly_001" \
-d '{
"wallet_uuid": "00000000-0000-4000-8000-000000000001",
"merchant_id": "merchant_123",
"payer_name": "张伟",
"payer_email": "zhangwei@example.com",
"payer_cell_phone": "+5511999999999",
"payer_tax_id": "12345678901",
"items": [{"name": "高级套餐", "quantity": 1, "value": 29900}],
"payer_address": {
"street": "Av. Paulista 1000", "city": "São Paulo",
"state": "SP", "zip_code": "01310100", "country": "BR"
},
"currency": "BRL",
"installment_value": 29900,
"installment_count": 1,
"due_date": "2026-12-31",
"description": "高级订阅",
"type_charge": "credit_card",
"card_name": "张伟",
"card_number": "4111111111111111",
"card_expiry_month": 12,
"card_expiry_year": 2030,
"card_cvv": "123",
"data_only": true,
"device_info": {
"ip_address": "203.0.113.10",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0",
"device_id": "dev_xyz",
"session_id": "sess_abc",
"http_accept_content": "text/html,application/xhtml+xml",
"http_accept_browser_value": "*/*",
"http_browser_language": "pt-BR",
"http_browser_java_enabled": false,
"http_browser_javascript_enabled": true,
"http_browser_color_depth": "24",
"http_browser_screen_height": "900",
"http_browser_screen_width": "1440",
"http_browser_time_difference": "180"
},
"reference_external_id": "dataonly_001",
"webhook_url": "https://merchant.example/webhooks/a55"
}'
import os, requests
payload = {
"wallet_uuid": "00000000-0000-4000-8000-000000000001",
"merchant_id": "merchant_123",
"payer_name": "张伟",
"payer_email": "zhangwei@example.com",
"payer_cell_phone": "+5511999999999",
"payer_tax_id": "12345678901",
"items": [{"name": "高级套餐", "quantity": 1, "value": 29900}],
"payer_address": {
"street": "Av. Paulista 1000", "city": "São Paulo",
"state": "SP", "zip_code": "01310100", "country": "BR",
},
"currency": "BRL",
"installment_value": 29900,
"installment_count": 1,
"due_date": "2026-12-31",
"description": "高级订阅",
"type_charge": "credit_card",
"card_name": "张伟",
"card_number": "4111111111111111",
"card_expiry_month": 12,
"card_expiry_year": 2030,
"card_cvv": "123",
"data_only": True,
"device_info": {
"ip_address": "203.0.113.10",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0",
"device_id": "dev_xyz",
"session_id": "sess_abc",
"http_accept_content": "text/html,application/xhtml+xml",
"http_accept_browser_value": "*/*",
"http_browser_language": "pt-BR",
"http_browser_java_enabled": False,
"http_browser_javascript_enabled": True,
"http_browser_color_depth": "24",
"http_browser_screen_height": "900",
"http_browser_screen_width": "1440",
"http_browser_time_difference": "180",
},
"reference_external_id": "dataonly_001",
"webhook_url": "https://merchant.example/webhooks/a55",
}
r = requests.post(
"https://core-manager.a55.tech/api/v1/bank/wallet/charge/",
headers={
"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
print(r.status_code, r.json())
const payload = {
wallet_uuid: "00000000-0000-4000-8000-000000000001",
merchant_id: "merchant_123",
payer_name: "张伟",
payer_email: "zhangwei@example.com",
payer_cell_phone: "+5511999999999",
payer_tax_id: "12345678901",
items: [{ name: "高级套餐", quantity: 1, value: 29900 }],
payer_address: {
street: "Av. Paulista 1000", city: "São Paulo",
state: "SP", zip_code: "01310100", country: "BR",
},
currency: "BRL",
installment_value: 29900,
installment_count: 1,
due_date: "2026-12-31",
description: "高级订阅",
type_charge: "credit_card",
card_name: "张伟",
card_number: "4111111111111111",
card_expiry_month: 12,
card_expiry_year: 2030,
card_cvv: "123",
data_only: true,
device_info: {
ip_address: "203.0.113.10",
user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0",
device_id: "dev_xyz",
session_id: "sess_abc",
http_accept_content: "text/html,application/xhtml+xml",
http_accept_browser_value: "*/*",
http_browser_language: "pt-BR",
http_browser_java_enabled: false,
http_browser_javascript_enabled: true,
http_browser_color_depth: "24",
http_browser_screen_height: "900",
http_browser_screen_width: "1440",
http_browser_time_difference: "180",
},
reference_external_id: "dataonly_001",
webhook_url: "https://merchant.example/webhooks/a55",
};
const res = await fetch(
"https://core-manager.a55.tech/api/v1/bank/wallet/charge/",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
}
);
console.log(await res.json());
payload := map[string]interface{}{
"wallet_uuid": "00000000-0000-4000-8000-000000000001",
"merchant_id": "merchant_123",
"payer_name": "张伟",
"payer_email": "zhangwei@example.com",
"payer_tax_id": "12345678901",
"currency": "BRL",
"installment_value": 29900,
"installment_count": 1,
"type_charge": "credit_card",
"card_name": "张伟",
"card_number": "4111111111111111",
"card_expiry_month": 12,
"card_expiry_year": 2030,
"card_cvv": "123",
"data_only": true,
"device_info": map[string]interface{}{
"ip_address": "203.0.113.10",
"user_agent": "Mozilla/5.0",
"http_accept_content": "text/html",
"http_accept_browser_value": "*/*",
"http_browser_language": "pt-BR",
"http_browser_java_enabled": false,
"http_browser_javascript_enabled": true,
"http_browser_color_depth": "24",
"http_browser_screen_height": "900",
"http_browser_screen_width": "1440",
"http_browser_time_difference": "180",
},
"reference_external_id": "dataonly_001",
"webhook_url": "https://merchant.example/webhooks/a55",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST",
"https://core-manager.a55.tech/api/v1/bank/wallet/charge/", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ACCESS_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)
String json = """
{
"wallet_uuid": "00000000-0000-4000-8000-000000000001",
"type_charge": "credit_card",
"card_name": "张伟",
"card_number": "4111111111111111",
"card_expiry_month": 12,
"card_expiry_year": 2030,
"card_cvv": "123",
"data_only": true,
"currency": "BRL",
"installment_value": 29900,
"installment_count": 1,
"device_info": {
"ip_address": "203.0.113.10",
"user_agent": "Mozilla/5.0",
"http_accept_content": "text/html",
"http_accept_browser_value": "*/*",
"http_browser_language": "pt-BR",
"http_browser_java_enabled": false,
"http_browser_javascript_enabled": true,
"http_browser_color_depth": "24",
"http_browser_screen_height": "900",
"http_browser_screen_width": "1440",
"http_browser_time_difference": "180"
},
"reference_external_id": "dataonly_001",
"webhook_url": "https://merchant.example/webhooks/a55"
}
""";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://core-manager.a55.tech/api/v1/bank/wallet/charge/"))
.header("Authorization", "Bearer " + System.getenv("ACCESS_TOKEN"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());
$payload = [
"wallet_uuid" => "00000000-0000-4000-8000-000000000001",
"type_charge" => "credit_card",
"card_name" => "张伟",
"card_number" => "4111111111111111",
"card_expiry_month" => 12,
"card_expiry_year" => 2030,
"card_cvv" => "123",
"data_only" => true,
"currency" => "BRL",
"installment_value" => 29900,
"installment_count" => 1,
"device_info" => [
"ip_address" => "203.0.113.10",
"user_agent" => "Mozilla/5.0",
"http_accept_content" => "text/html",
"http_accept_browser_value" => "*/*",
"http_browser_language" => "pt-BR",
"http_browser_java_enabled" => false,
"http_browser_javascript_enabled" => true,
"http_browser_color_depth" => "24",
"http_browser_screen_height" => "900",
"http_browser_screen_width" => "1440",
"http_browser_time_difference" => "180",
],
"reference_external_id" => "dataonly_001",
"webhook_url" => "https://merchant.example/webhooks/a55",
];
$ch = curl_init("https://core-manager.a55.tech/api/v1/bank/wallet/charge/");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("ACCESS_TOKEN"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
echo curl_exec($ch);
处理响应
Data Only 收费会立即得到结果 —— 无重定向、无 url_3ds、无需等待 challenge 完成。
- 已通过
- 已拒绝
- 认证错误
{
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "confirmed",
"reference_external_id": "dataonly_001",
"data_only": true,
"eci": "07",
"authentication_status": "data_only_succeeded",
"amount": 29900,
"currency": "BRL",
"type_charge": "credit_card"
}
{
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "error",
"reference_external_id": "dataonly_001",
"data_only": true,
"message": [{"message": "Card declined by issuer"}],
"code": "CARD_DECLINED"
}
{
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "error",
"reference_external_id": "dataonly_001",
"data_only": true,
"message": [{"message": "Transaction not authenticated 3DS or DataOnly is required for debit card."}],
"code": "error_threeds_authentication"
}
通过 Webhook 校验
A55 会向您的 webhook_url 发送包含最终状态的 Webhook(网络钩子)。请始终以 Webhook 为准。
{
"charge_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "paid",
"transaction_reference": "txn_ref_001",
"webhook_url": "https://merchant.example/webhooks/a55"
}
device_info 字段说明
这些字段会输入发卡行的风险模型。数据越多 = 风险评估越准 = 授权通过率越高。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
ip_address | string | 是 | 客户端公网 IP |
user_agent | string | 是 | 浏览器 User-Agent 头 |
http_accept_content | string | 是 | HTTP Accept 头取值 |
http_accept_browser_value | string | 是 | 浏览器 Accept 头 |
http_browser_language | string | 是 | 浏览器/操作系统语言(例如 pt-BR) |
http_browser_java_enabled | boolean | 是 | 是否启用 Java 插件 |
http_browser_javascript_enabled | boolean | 是 | 是否启用 JavaScript |
http_browser_color_depth | string | 是 | 屏幕色深(例如 "24") |
http_browser_screen_height | string | 是 | 屏幕高度(像素) |
http_browser_screen_width | string | 是 | 屏幕宽度(像素) |
http_browser_time_difference | string | 是 | 相对 UTC 的分钟偏移(例如 BRT 为 "180") |
device_id | string | 否 | 稳定设备标识 |
session_id | string | 否 | 结账会话标识 |
Visa 与 Mastercard 的响应差异
两家网络均支持 Data Only,但认证响应字段不同:
| 字段 | Visa Data Only | Mastercard Identity Check Insights |
|---|---|---|
| 项目名称 | Visa Data Only(VDO) | Identity Check Insights(IDCI) |
| ECI | 07 | 04 或 06(因收单机构而异) |
| 交易状态 | I(informational,信息性) | U(unauthenticated,未认证) |
| CAVV/AAV | 有 | 有 |
| 发送的 challenge 指示 | 06(data share only) | 06(data share only) |
| 消息类别 | 标准 | 80(IDCI 专用) |
| 责任转移 | 无 | 无 |
Visa DCAP(数字商务认证计划,Digital Commerce Authentication Program)
针对美国与加拿大交易,Visa 提供 DCAP 计划 —— 增强版 Data Only 路径,需填写特定字段以获得最大授权通过率收益。
DCAP 必填字段
| 字段 | 重要性 |
|---|---|
ip_address | 地理定位与速度检查 |
payer_email | 跨商户身份关联 |
payer_address(完整账单地址) | AVS 匹配与地址核验 |
设备指纹(device_info) | 设备信誉与行为分析 |
若向美国或加拿大发起跨境收费,请包含全部上述字段,以符合 DCAP 增强授权数据资格。
借记卡与 Data Only
Data Only 同样适用于借记卡交易。后端会校验借记卡收费必须包含完整 3DS 认证或 Data Only 之一:
| ECI | 借记卡是否接受 |
|---|---|
02 | 是(完整 3DS —— Mastercard) |
05 | 是(完整 3DS —— Visa) |
06 | 是(Data Only —— Mastercard) |
07 | 是(Data Only —— Visa) |
若借记卡收费未带有来自 3DS 或 Data Only 的有效 ECI,将拒绝,并返回消息:"Transaction not authenticated 3DS or DataOnly is required for debit card."(交易未认证——借记卡交易必须启用 3DS 或 DataOnly)
使用沙箱测试卡
| Card Number | Brand | Scenario | Expected Status |
|---|---|---|---|
4111 1111 1111 1111 | Visa | Data Only——已通过 | confirmed |
5500 0000 0000 0004 | Mastercard | Data Only——已通过(IDCI) | confirmed |
4000 0000 0000 0002 | Visa | Data Only——发卡行拒绝 | declined |
4000 0000 0000 0069 | Visa | Data Only——处理错误 | error |
在沙箱中,Data Only 扣款为模拟。系统接受 data_only 标志,响应包含 eci 与 authentication_status 字段,但不会发生真实网络通信。请使用上述测试卡验证集成逻辑。
面向 A55 合作伙伴:开通沟通
Data Only 现可通过 A55 使用,但需协调开通。起步步骤:
- 确认收单机构支持 —— 路由表中并非所有收单机构都支持 Data Only。您的对接经理将核实已启用的机构。
- 在商户配置中启用 Data Only —— 账户需设置
authentication_dataonly_enabled标志。 - 审查
device_info数据质量 —— 不完整或合成数据会抵消收益。A55 可审计您近期的载荷。 - 分析交易画像 —— 对接经理可根据当前拒绝模式估算预期授权通过率提升。
请联系对接经理或发送邮件至 tech.services@a55.tech 预约 Data Only 开通评审。
参考文献
本页综合 17 个行业来源:
- Visa Data Only for merchants and issuers
- CyberSource: Visa Data Only REST Example
- Adyen: Data-only flow
- Fiserv LATAM: Data Only — Mastercard and Visa
- PXP Kalixa: 3DS2 Data Only Flow
- PayPal: 3DS Data Only and authorization rates
- Square + Broadcom/Arcot: 6M transaction pilot case study
- US Payments Forum: 3DS Data Only Brief #2 (Aug 2025)
- Datos Insights: Lower Fraud, No Friction
- EMVCo: 3DS 2.2 specification — challengeInd "06"
- Mastercard: Identity Check Insights Program
- Stripe: Visa DCAP on Stripe
- Decta: 5 Optimization Tips for 3DS Approval Rates
- Cardinal/Verifi: Data Only
- Visa European EMV 3DS 2.2.0 Implementation Guide
- CyberSource: Visa Data Only Testing
- Merchant Advisory Group: Visa DCAP and VAMP Programs