Data Only: Maximize Approval Rates
Quick Reference
What is Data Only?
Data Only uses EMV 3DS infrastructure to share transaction, device, and behavioral data with card networks and issuers — without ever showing a challenge to the cardholder. The issuer receives enriched data and makes a more informed authorization decision.
The result: higher approval rates, zero cart abandonment from authentication, and no redirect or popup.
Why Data Only matters
The numbers make the case:
| Metric | Value | Source |
|---|---|---|
| False decline impact vs fraud | 3x greater — declining a good customer costs 3x more than fraud | Visa Global Client |
| US eCommerce fraud (projected) | $13 billion by 2026 | Visa |
| Global cart abandonment rate | 70% average | Baymard Institute |
| Conversion drop from 3DS friction | 2–15% depending on market | Decta / US Payments Forum |
| US merchant 3DS adoption | Only ~3% of transactions | US Payments Forum Brief #2 |
| Square pilot (6M transactions, 9 months) | +23 to +646 basis points per financial institution | Broadcom/Arcot case study |
| Chargeback rate improvement (same pilot) | 6% reduction | Broadcom/Arcot case study |
Decision matrix
| Criterion | Full 3DS | Data Only | No authentication |
|---|---|---|---|
| Brands | All supported | Visa and Mastercard only | All |
| Challenge to cardholder | Yes, when required by issuer | Never | Never |
| Liability shift | Yes | No | No |
| Approval rate impact | May decrease (friction) | Increases (enriched data) | Baseline |
| Chargeback protection | Issuer bears (when shift applies) | Merchant bears | Merchant bears |
| Data sent to issuer | Device + behavioral + challenge result | Device + behavioral (richer context) | None |
| Best for | High-value, regulated, PSD2/SCA markets | High-volume, low-risk, LATAM | Low-risk, low-value |
| PSD2/SCA markets | Required | Not available (SCA takes priority) | Not compliant |
data_only and threeds_authentication cannot both be true on the same charge. If you force full 3DS authentication (threeds_authentication: true), the system requires ECI 02 or 05 (fully authenticated). Data Only produces ECI 06 or 07, which fails forced 3DS validation.
Choose one strategy per transaction.
How it works
The key insight: the issuer receives two signals — the risk evaluation from the network and the enriched data from your device_info. This is more information than a standard authorization, so the issuer can approve with higher confidence.
Step-by-step integration
Collect device and browser data
Capture real browser values on the client side. Never fabricate these — synthetic data increases decline rates.
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()),
};
Send deviceInfo to your backend for the charge request.
Authenticate and get an access token
- 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;
Create a charge with data_only: true
Set data_only: true and include the full device_info object from Step 1.
- 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": "Jane Doe",
"payer_email": "jane@example.com",
"payer_cell_phone": "+5511999999999",
"payer_tax_id": "12345678901",
"items": [{"name": "Premium Plan", "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": "Premium subscription",
"type_charge": "credit_card",
"card_name": "JANE DOE",
"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": "Jane Doe",
"payer_email": "jane@example.com",
"payer_cell_phone": "+5511999999999",
"payer_tax_id": "12345678901",
"items": [{"name": "Premium Plan", "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": "Premium subscription",
"type_charge": "credit_card",
"card_name": "JANE DOE",
"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: "Jane Doe",
payer_email: "jane@example.com",
payer_cell_phone: "+5511999999999",
payer_tax_id: "12345678901",
items: [{ name: "Premium Plan", 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: "Premium subscription",
type_charge: "credit_card",
card_name: "JANE DOE",
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": "Jane Doe",
"payer_email": "jane@example.com",
"payer_tax_id": "12345678901",
"currency": "BRL",
"installment_value": 29900,
"installment_count": 1,
"type_charge": "credit_card",
"card_name": "JANE DOE",
"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": "JANE DOE",
"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" => "JANE DOE",
"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);
Handle the response
Data Only charges resolve immediately — no redirect, no url_3ds, no waiting for challenge completion.
- Confirmed
- Declined
- Authentication error
{
"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"
}
Verify via webhook
A55 sends a webhook to your webhook_url with the final status. Always use the webhook as the source of truth.
{
"charge_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "paid",
"transaction_reference": "txn_ref_001",
"webhook_url": "https://merchant.example/webhooks/a55"
}
device_info reference
These fields feed the issuer's risk model. More data = better risk assessment = higher approval rates.
| Field | Type | Required | Description |
|---|---|---|---|
ip_address | string | Yes | Client public IP address |
user_agent | string | Yes | Browser User-Agent header |
http_accept_content | string | Yes | HTTP Accept header value |
http_accept_browser_value | string | Yes | Browser Accept header |
http_browser_language | string | Yes | Browser/OS language (e.g., pt-BR) |
http_browser_java_enabled | boolean | Yes | Whether Java plugin is enabled |
http_browser_javascript_enabled | boolean | Yes | Whether JavaScript is enabled |
http_browser_color_depth | string | Yes | Screen color depth (e.g., "24") |
http_browser_screen_height | string | Yes | Screen height in pixels |
http_browser_screen_width | string | Yes | Screen width in pixels |
http_browser_time_difference | string | Yes | Minutes offset from UTC (e.g., "180" for BRT) |
device_id | string | No | Stable device identifier |
session_id | string | No | Checkout session identifier |
Visa vs Mastercard response differences
Both networks support Data Only, but the authentication response fields differ:
| Field | Visa Data Only | Mastercard Identity Check Insights |
|---|---|---|
| Program name | Visa Data Only (VDO) | Identity Check Insights (IDCI) |
| ECI | 07 | 04 or 06 (acquirer-dependent) |
| Transaction status | I (informational) | U (unauthenticated) |
| CAVV/AAV | Present | Present |
| Challenge indicator sent | 06 (data share only) | 06 (data share only) |
| Message category | Standard | 80 (IDCI-specific) |
| Liability shift | No | No |
Visa DCAP (Digital Commerce Authentication Program)
For US and Canada transactions, Visa offers the DCAP program — an enhanced Data Only path that requires specific fields for maximum approval rate benefit.
DCAP-required fields
| Field | Why it matters |
|---|---|
ip_address | Geolocation and velocity checks |
payer_email | Identity correlation across merchants |
payer_address (full billing address) | AVS matching and address verification |
Device fingerprint (device_info) | Device reputation and behavioral analysis |
If you send cross-border charges to the US or Canada, include all these fields to qualify for DCAP's enhanced authorization data.
Debit cards and Data Only
Data Only also applies to debit card transactions. The backend validates that debit charges include either full 3DS authentication or Data Only:
| ECI | Accepted for debit |
|---|---|
02 | Yes (full 3DS — Mastercard) |
05 | Yes (full 3DS — Visa) |
06 | Yes (Data Only — Mastercard) |
07 | Yes (Data Only — Visa) |
If a debit charge arrives without a valid ECI from 3DS or Data Only, it is rejected with the message: "Transaction not authenticated 3DS or DataOnly is required for debit card."
Test with sandbox cards
| Card Number | Brand | Scenario | Expected Status |
|---|---|---|---|
4111 1111 1111 1111 | Visa | Data Only — confirmed | confirmed |
5500 0000 0000 0004 | Mastercard | Data Only — confirmed (IDCI) | confirmed |
4000 0000 0000 0002 | Visa | Data Only — declined by issuer | declined |
4000 0000 0000 0069 | Visa | Data Only — processing error | error |
In sandbox, Data Only charges are simulated. The data_only flag is accepted and the response includes eci and authentication_status fields, but no actual network communication occurs. Use these test cards to validate your integration logic.
For A55 partners: activation discussion
Data Only is available today through A55 but requires coordination to activate. To start:
- Confirm acquirer support — not all acquirers in your routing table support Data Only. Your integration manager will verify which providers are enabled.
- Enable Data Only in your merchant configuration — the
authentication_dataonly_enabledflag must be set on your account. - Review your
device_infodata quality — incomplete or synthetic data negates the benefit. A55 can audit your recent payloads. - Analyze your transaction profile — your integration manager can model expected approval rate uplift based on your current decline patterns.
Contact your integration manager or email tech.services@a55.tech to schedule a Data Only activation review.
References
This page is built from 17 industry sources:
- 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