Mutt
Professional
- Messages
- 1,369
- Reaction score
- 912
- Points
- 113
3D-Secure (3DS) integration via API is a process that allows online merchants and payment gateways to implement two-factor authentication to improve the security of online transactions, especially in the context of PSD2 (Payment Services Directive 2) requirements in Europe. 3D-Secure (e.g. Verified by Visa, MasterCard SecureCode, Amex SafeKey) adds an extra layer of verification by requiring the cardholder to verify their identity via a one-time password (OTP), biometrics or other methods. In the context of carding, this makes the use of Non-VBV, Auto-VBV and Non-MCSC bins extremely difficult, since without access to the cardholder's data (phone, email, biometrics) the transaction will not go through. Below, I will describe in detail the technical aspects of 3DS integration via API, including the architecture, process, code samples and impact on carding, for educational purposes.
If you want to dive deeper into other aspects, like comparing Stripe and Adyen APIs for 3DS or creating custom rules in Stripe Radar, let me know!
1. What is 3D-Secure and its role in API integration
3D-Secure (3DS) is a security protocol developed by payment systems (Visa, MasterCard, American Express) that adds an authentication layer to online transactions. 3DS version 2.0 (introduced in 2019) improves the user experience and supports PSD2 requirements, including Strong Customer Authentication (SCA).- Basic elements of 3DS:
- Authentication: Confirmation of cardholder identity (e.g. OTP via SMS, push notification, biometrics).
- Risk-Based Authentication (RBA): The issuing bank analyzes the transaction parameters (IP, device, amount) and decides whether full verification is required (Challenge) or automatic approval is sufficient (Frictionless).
- API Integration: Payment gateways (e.g. Stripe, Adyen) provide APIs to manage 3DS, allowing merchants to initiate authentication and process results.
- Role in the context of carding:
- 3DS requires identity verification, making it impossible to use Non-VBV and Non-MCSC bins without access to the owner's OTP or biometrics.
- Auto-VBV bins can pass Frictionless flow, but only for low-risk transactions, and anti-fraud systems often detect suspicious attempts.
- PSD2 and SCA: In Europe, PSD2 requires SCA for most online transactions, making 3DS mandatory except for low-risk transactions, small amounts (up to €30) or recurring payments.
2. Technical aspects of 3DS integration via API
3DS integration via API involves interaction between the store, payment gateway, issuing bank and payment system. The main stages and components are:a) Integration architecture
- Client side (Frontend):
- The store uses a JavaScript SDK (such as stripe.js for Stripe) to collect card and device data.
- The SDK sends data to the store server or directly to the payment gateway via a secure connection (HTTPS/TLS).
- Server side (Backend):
- The store server interacts with the payment gateway API (e.g. Stripe, Adyen) via REST API, sending transaction data (amount, currency, card details).
- The gateway initiates 3DS if required and returns the result (Frictionless or Challenge).
- Payment gateway:
- Processes requests, interacts with the issuing bank through payment systems (VisaNet, MasterCard).
- Manages the 3DS protocol by transmitting transaction parameters and receiving a response (e.g. approval or OTP request).
- Issuing bank:
- Analyzes transaction parameters (up to 100+ signals: IP, device, amount, history) and decides whether a Challenge is needed.
- Provides an authentication page (e.g. to enter OTP) or approves the transaction automatically.
b) Basic API methods
Payment gateways provide APIs to manage 3DS. For example, for Stripe:- Payment Intents API: Manages the transaction lifecycle, including 3DS.
- Создание Payment Intent: POST /v1/payment_intents
- 3DS confirmation: POST /v1/payment_intents/:id/confirm
- Setup Intents API: Used to save the card for future payments with 3DS authentication.
- Webhooks: Notify about 3DS status (e.g. payment_intent.authentication_required).
c) 3DS Integration Process
- Map data collection:
- The user enters card details (number, expiration date, CVV) on the store's website through a form integrated with an SDK (e.g. Stripe Elements).
- The SDK collects additional device data (browser, OS, screen resolution) for Device Fingerprinting.
- Creating a Payment Intent:
- The store server sends a request to the gateway API to create a Payment Intent, specifying the amount, currency, and card details (or token).
- Example (Stripe API, Node.js):
JavaScript:const stripe = require('stripe')('sk_test_xxx'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1000, // Сумма в центах (€10) currency: 'eur', payment_method: 'pm_card_visa', // Токен карты confirmation_method: 'automatic', return_url: 'https://your-site.com/return' });
- 3DS Initiation:
- The gateway determines whether 3DS is required (based on region, amount, issuing bank and PSD2).
- If required, the requires_action status is returned with the URL for authentication.
- Example answer:
JSON:{ "id": "pi_123456789", "status": "requires_action", "next_action": { "type": "redirect_to_url", "redirect_to_url": { "url": "https://hooks.stripe.com/3ds2/challenge" } } }
- User redirection:
- Frontend redirects the user to the bank page to enter OTP, push notification or biometric verification.
- For Stripe, this is done via stripe.handleCardAction:
JavaScript:const stripe = Stripe('pk_test_xxx'); stripe.handleCardAction(paymentIntent.client_secret).then(result => { if (result.error) { console.error('3DS failed:', result.error); } else { console.log('3DS completed:', result.paymentIntent); } });
- Transaction confirmation:
- After successful authentication, the gateway confirms the Payment Intent and the issuing bank authorizes the transaction.
- The store server receives a notification via a webhook (e.g. payment_intent.succeeded).
- Example webhook:
JSON:{ "type": "payment_intent.succeeded", "data": { "object": { "id": "pi_123456789", "status": "succeeded", "amount": 1000, "currency": "eur" } } }
- Exception handling:
- If authentication fails (e.g. invalid OTP), the gateway returns an error (requires_action or canceled).
- If the transaction is low risk (Frictionless), 3DS may not be requested.
d) Risk-Based Authentication (RBA)
- 3DS 2.0 uses RBA by analyzing transaction parameters (IP, device, amount, history) to determine whether full authentication is required:
- Frictionless flow: Low risk, transaction is approved without OTP (e.g. repeat purchase at a familiar store).
- Challenge flow: High risk, requires OTP, push notification or biometrics.
- The gateway API passes the transaction parameters to the issuing bank via a 3DS protocol (e.g. EMV 3-D Secure), which returns a decision.
e) Tokenization
- After successful 3DS authentication, the gateway generates a token for the card, which is used for future transactions (e.g. subscriptions).
- Example: Stripe returns payment_method (pm_123), which the store stores instead of the card details.
3. Example of 3DS integration with API (based on Stripe)
Below is an example of 3DS integration via Stripe API, including client and server parts.a) Client side (Frontend, JavaScript)
HTML:
<!DOCTYPE html>
<html>
<head>
<script src="https://js.stripe.com/v3/"></script>
</head>
<body>
<form id="payment-form">
<div id="card-element"></div>
<button type="submit">Pay</button>
</form>
<script>
const stripe = Stripe('pk_test_xxx');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
const form = document.getElementById('payment-form');
form.addEventListener('submit', async (event) => {
event.preventDefault();
const { paymentIntent, error } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});
if (error) {
console.error(error);
return;
}
// Sending payment_method to the server
const response = await fetch('/create-payment-intent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payment_method: paymentIntent.payment_method })
});
const paymentIntentData = await response.json();
if (paymentIntentData.status === 'requires_action') {
const result = await stripe.handleCardAction(paymentIntentData.client_secret);
if (result.error) {
console.error('3DS failed:', result.error);
} else {
console.log('3DS succeeded:', result.paymentIntent);
// Sending a confirmed Payment Intent to the server
await fetch('/confirm-payment-intent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payment_intent_id: result.paymentIntent.id })
});
}
} else {
console.log('Payment succeeded:', paymentIntentData);
}
});
</script>
</body>
</html>
b) Server side (Backend, Node.js)
JavaScript:
const express = require('express');
const stripe = require('stripe')('sk_test_xxx');
const app = express();
app.use(express.json());
app.post('/create-payment-intent', async (req, res) => {
try {
const paymentIntent = await stripe.paymentIntents.create({
amount: 1000, // €10
currency: 'eur',
payment_method: req.body.payment_method,
confirmation_method: 'automatic',
return_url: 'https://your-site.com/return'
});
res.json({
client_secret: paymentIntent.client_secret,
status: paymentIntent.status
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post('/confirm-payment-intent', async (req, res) => {
try {
const paymentIntent = await stripe.paymentIntents.confirm(req.body.payment_intent_id);
res.json({ status: paymentIntent.status });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
c) Webhook for event handling
JavaScript:
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, 'whsec_xxx');
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
if (event.type === 'payment_intent.succeeded') {
console.log('Payment succeeded:', event.data.object);
// Complete the order in the store
} else if (event.type === 'payment_intent.payment_failed') {
console.log('Payment failed:', event.data.object);
// Notify user
}
res.json({ received: true });
});
4. Impact on carding and Non-VBV/Auto-VBV/Non-MCSC bins
3DS integration via API makes carding using Non-VBV, Auto-VBV and Non-MCSC bins extremely difficult:a) Non-VBV bins
- Problem for carders: In Europe, PSD2 requires SCA, and the gateway API (e.g. Stripe) automatically initiates 3DS for most transactions. Non-VBV beans require OTP or biometrics, which are not available to carders.
- Example: Carder uses Non-VBV bin (e.g. 479126, ESL FCU) to make a purchase in a European store. Stripe API creates a Payment Intent, initiates 3DS, redirecting to the bank page to enter the OTP. Without access to the owner's phone, the transaction is rejected.
- Exceptions: For low-risk transactions (up to €30) 3DS may not be requested (Frictionless flow), but anti-fraud systems (e.g. Stripe Radar) analyze IP, device and behavior, blocking suspicious attempts.
b) Auto-VBV bins
- Problem for carders: Auto-VBV bins can pass Frictionless flow if the transaction is low risk, but the API passes parameters (IP, device) to the issuing bank, which can request a Challenge for suspicious transactions.
- Example: Carder uses Auto-VBV bin (e.g. 440393, Bank of America) with IP from Russia. Stripe API initiates 3DS and bank requires OTP due to geolocation mismatch, making transaction impossible.
c) Non-MCSC bins
- Problem for carders: Similar to Non-VBV, Non-MCSC beans face 3DS checks via API that require SCA. Without OTP or biometrics, the transaction fails.
- Example: A Non-MCSC bin (eg 523236, Santander Consumer Bank) is rejected if the gateway API initiates a 3DS and the carder cannot provide the code.
d) Card Testing
- Carders often test cards through small transactions ($1–$5). The gateway API integrates with anti-fraud systems (e.g. Stripe Radar), which detect:
- Multiple attempts from one card/IP.
- Suspicious patterns (e.g. one-time emails, VPNs).
- Example: Carder tests Non-VBV bin with 5 $1 transactions. Stripe API sends data to Radar, which blocks the card after 2-3 attempts.
e) 3DS bypass
- Carders try to bypass the 3DS by using:
- Clean IPs: Proxy/VPN corresponding to the map region.
- Fake data: Accurate holder data from leaks.
- Social Engineering: Resetting 3DS password via bank.
- API Countermeasures:
- The gateway API passes parameters to RBA, including IP, device and behavior, allowing the bank to detect anomalies.
- Anti-fraud systems (for example, Device Fingerprinting) detect VPN/Tor or suspicious devices.
- Attempts to reset the password often result in the card being blocked by the bank.
5. Technical features and advantages
- Speed: 3DS via API is processed in <100ms (RBA analysis), minimizing latency.
- Flexibility: Dynamic 3DS allows you to skip authentication for low-risk transactions, improving UX.
- Security: Card data is tokenized and transmitted via HTTPS/TLS.
- PSD2 compliance: Gateway APIs (Stripe, Adyen) support SCA, making them mandatory for Europe.
- Integration with anti-fraud systems: The API transmits data to systems such as Stripe Radar for additional analysis.
6. Limitations and Challenges
- False Positives: Overly strict 3DS settings can block legitimate transactions, especially for international customers.
- Integration complexity: Requires frontend and backend configuration, including webhooks and error handling.
- Issuing bank dependency: Some banks (especially outside the EEA) have poor support for 3DS 2.0, which can lead to failures.
- User experience: Challenge flow (OTP, biometrics) can be a turn-off for customers if used too often.
7. Conclusion
3D-Secure integration via API (e.g. Stripe Payment Intents) enables secure transaction processing, compliant with PSD2 requirements and preventing carding. The API allows merchants to initiate 3DS, process Frictionless and Challenge flows, and integrate with anti-fraud systems like Stripe Radar. For carders, this creates significant obstacles: Non-VBV and Non-MCSC beans require OTP or biometrics, Auto-VBV beans are blocked if they are high risk, and bypass attempts (VPN, fake data) are detected through IP, device and behavior analysis. Technical features like tokenization, RBA and webhooks make 3DS via API a powerful security tool, especially in Europe where PSD2 makes SCA mandatory.If you want to dive deeper into other aspects, like comparing Stripe and Adyen APIs for 3DS or creating custom rules in Stripe Radar, let me know!