Defeating Friendly Fraud with Visa Compelling Evidence 3.0: The Exact Data Schema
When a cardholder files a dispute under Visa Reason Code 10.4 ("Fraud - Card-Absent Environment"), merchants historically faced low win rates. The merchant bore the burden of proving that the legitimate cardholder actual
When a cardholder files a dispute under Visa Reason Code 10.4 ("Fraud - Card-Absent Environment"), merchants historically faced low win rates. The merchant bore the burden of proving that the legitimate cardholder actually authorized and received the digital goods or service.
Under Visa Compelling Evidence 3.0 (CE 3.0), if a merchant can provide deterministic proof of qualifying historical transactions between the customer and their platform, liability shifts back to the issuing bank before a formal chargeback is finalized.
However, the evidentiary requirements are rigid. If your telemetry fails to match the required schema, the rebuttal is rejected.
Here is the exact data structure your payment logging pipeline must capture to satisfy Visa CE 3.0 rules.
The Rule of Historical Qualification
To invoke CE 3.0 on a disputed transaction, you must present evidence of at least two prior non-disputed transactions that satisfy three conditions:
- Age: The transactions must have settled between 120 and 365 calendar days prior to the disputed transaction date.
- Payment Credential: The transactions must have used the identical core account number (PAN) or network payment token.
- Core Identifiers: At least two core data elements must match identically across both historical transactions AND the disputed transaction.
The 4 Recognized Core Data Elements
Visa recognizes four specific data elements for establishing identity in digital environments:
- IP Address: The public client IP captured at checkout.
- Device Fingerprint / Device ID: A persistent cryptographic hash generated from device attributes.
- User Account ID / Login Credential: The unique merchant-assigned identifier (e.g., user UUID or validated customer profile ID).
- Delivery Address: Physical shipping address or validated endpoint destination.
Of these four, one of the matching elements MUST be either the IP Address or the Device ID. A match on User Account ID and Shipping Address alone is insufficient without network-level identity.
Transaction Schema Definition
To automate this defense, your backend checkout service should persist a normalized transaction fingerprint record upon every authorization:
interface CE30TransactionRecord {
transactionId: string;
panFingerprint: string; // SHA-256 hash of PAN or network token
settlementDate: string; // ISO-8601 UTC
disputed: boolean;
// Visa CE 3.0 Matching Elements
clientIp: string;
deviceId: string;
accountUserId: string;
shippingAddressHash?: string;
// Qualifying Signals
cvvMatch: boolean;
avsResultCode: string;
}
Automating the Historical Match Algorithm
When a pre-dispute alert (via Verifi CDRN or Order Insight) arrives via webhook, your system must scan previous settled transactions to compile the historical pair:
from datetime import datetime, timedelta
def find_ce30_qualifiers(disputed_tx, historical_txs):
"""
Evaluates historical transactions to identify qualifying Visa CE 3.0 pairs.
"""
dispute_date = datetime.fromisoformat(disputed_tx["settlement_date"])
window_start = dispute_date - timedelta(days=365)
window_end = dispute_date - timedelta(days=120)
candidates = []
for tx in historical_txs:
if tx.get("disputed", False):
continue
tx_date = datetime.fromisoformat(tx["settlement_date"])
if not (window_start <= tx_date <= window_end):
continue
# Verify PAN fingerprint match
if tx["pan_fingerprint"] != disputed_tx["pan_fingerprint"]:
continue
# Score matching core elements
matches = {
"ip": tx["client_ip"] == disputed_tx["client_ip"],
"device": tx["device_id"] == disputed_tx["device_id"],
"user_id": tx["account_user_id"] == disputed_tx["account_user_id"]
}
# Check rule: At least 2 matches, where one is IP or Device
has_network_match = matches["ip"] or matches["device"]
match_count = sum(matches.values())
if match_count >= 2 and has_network_match:
candidates.append(tx)
# Visa requires at least TWO distinct qualifying historical transactions
if len(candidates) >= 2:
return True, candidates[:2]
return False, []
Common Traps in Implementation
- IPv6 vs IPv4 Mismatches: Mobile users frequently transition between IPv6 cellular connections and residential Wi-Fi (IPv4). Relying strictly on exact IP equality without robust device fingerprinting causes many legitimate qualifying transactions to miss the match criteria.
- Ephemeral Guest Checkouts: Allowing unauthenticated checkouts without generating a stable device fingerprint leaves you with zero core identifiers to link historical purchases.
- Overly Aggressive Data Pruning: Many engineering teams purge raw connection logs after 90 days. If your transaction database does not retain the required hashed core elements for at least 365 days, you cannot produce the necessary historical evidence.
Building compliance into your payment pipeline before chargebacks occur transforms friendly fraud disputes from an expensive manual chore into an automated, programmatic win.
Audit your chargeback evidence against Visa CE 3.0 rules free: https://rebuttaldesk.pages.dev/?src=devto
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.