Learn how to check fraud risk in Stripe payments using Stripe Radar, custom rules, webhooks, and best practices to protect your business from online payment fraud.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
How to Check Fraud Risk in Stripe Payments: A Comprehensive Guide
Introduction
Preventing fraud is crucial when processing online payments. Stripe offers robust tools to help merchants identify and mitigate fraud risks. This tutorial provides a detailed walkthrough of implementing fraud detection in your Stripe integration.
Step 1: Set Up Your Stripe Account
Before implementing fraud detection, ensure you have a Stripe account properly configured:
Step 2: Install the Stripe Library
First, you need to install the Stripe library for your programming language:
For Node.js:
npm install stripe
For Python:
pip install stripe
For PHP:
composer require stripe/stripe-php
Step 3: Initialize the Stripe Client
Set up the Stripe client with your API keys:
For Node.js:
const stripe = require('stripe')('sk_test_your_secret_key');
// For better security, load the key from environment variables
// const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
For Python:
import stripe
stripe.api_key = "sk_test_your_secret\_key"
# Better practice using environment variables
# import os
# stripe.api_key = os.environ.get('STRIPE_SECRET\_KEY')
For PHP:
\Stripe\Stripe::setApiKey('sk_test_your_secret_key');
// Better security using environment variables
// \Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
Step 4: Implement Radar for Fraud Detection
Stripe Radar is Stripe's built-in fraud detection system. Here's how to use it:
Step 5: Check the Radar Risk Score During Payment Processing
When processing payments, you can check the risk level:
For Node.js:
async function createPaymentIntent(amount, currency) {
try {
const paymentIntent = await stripe.paymentIntents.create({
amount: amount,
currency: currency,
});
// Retrieve the payment intent to check risk score
const retrievedIntent = await stripe.paymentIntents.retrieve(
paymentIntent.id
);
// Check risk score if available
if (retrievedIntent.charges && retrievedIntent.charges.data.length > 0) {
const riskScore = retrievedIntent.charges.data[0].outcome.risk\_score;
const riskLevel = retrievedIntent.charges.data[0].outcome.risk\_level;
console.log(`Risk Score: ${riskScore}, Risk Level: ${riskLevel}`);
// Take action based on risk level
if (riskLevel === 'elevated' || riskLevel === 'highest') {
// Consider additional verification steps
console.log('High risk payment detected. Additional verification recommended.');
}
}
return paymentIntent;
} catch (error) {
console.error('Error creating payment intent:', error);
throw error;
}
}
For Python:
def create_payment_intent(amount, currency):
try:
payment\_intent = stripe.PaymentIntent.create(
amount=amount,
currency=currency,
)
# Retrieve the payment intent to check risk score
retrieved_intent = stripe.PaymentIntent.retrieve(payment_intent.id)
# Check risk score if available
if retrieved_intent.charges and len(retrieved_intent.charges.data) > 0:
risk_score = retrieved_intent.charges.data[0].outcome.risk\_score
risk_level = retrieved_intent.charges.data[0].outcome.risk\_level
print(f"Risk Score: {risk_score}, Risk Level: {risk_level}")
# Take action based on risk level
if risk\_level in ['elevated', 'highest']:
# Consider additional verification steps
print('High risk payment detected. Additional verification recommended.')
return payment\_intent
except Exception as e:
print(f"Error creating payment intent: {str(e)}")
raise e
Step 6: Check Fraud Risk in Payment Webhooks
Set up webhooks to receive real-time fraud assessments:
For Node.js (using Express):
const express = require('express');
const app = express();
// You need the raw request body for signature verification
app.use('/webhook', express.raw({type: 'application/json'}));
app.post('/webhook', async (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
'whsec_your_webhook_signing_secret'
);
} catch (err) {
console.log(`Webhook Error: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle successful charges
if (event.type === 'charge.succeeded') {
const charge = event.data.object;
// Check for fraud indicators
const outcome = charge.outcome;
if (outcome) {
console.log(`Risk Level: ${outcome.risk_level}`);
console.log(`Risk Score: ${outcome.risk_score}`);
console.log(`Seller Message: ${outcome.seller_message}`);
// Take appropriate actions based on risk assessment
if (outcome.risk_level === 'elevated' || outcome.risk_level === 'highest') {
// Log high-risk transactions
console.log(`High risk transaction detected: ${charge.id}`);
// Optionally flag for review or additional verification
// await flagTransactionForReview(charge.id);
}
}
}
res.json({received: true});
});
For Python (using Flask):
from flask import Flask, request, jsonify
import stripe
app = Flask(**name**)
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.data
sig\_header = request.headers.get('Stripe-Signature')
try:
event = stripe.Webhook.construct\_event(
payload, sig_header, 'whsec_your_webhook_signing\_secret'
)
except ValueError as e:
# Invalid payload
return jsonify(error=str(e)), 400
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return jsonify(error=str(e)), 400
# Handle successful charges
if event['type'] == 'charge.succeeded':
charge = event\['data']\['object']
# Check for fraud indicators
outcome = charge.get('outcome', {})
if outcome:
print(f"Risk Level: {outcome.get('risk\_level')}")
print(f"Risk Score: {outcome.get('risk\_score')}")
print(f"Seller Message: {outcome.get('seller\_message')}")
# Take appropriate actions based on risk assessment
if outcome.get('risk\_level') in ['elevated', 'highest']:
# Log high-risk transactions
print(f"High risk transaction detected: {charge['id']}")
# Optionally flag for review or additional verification
# flag_transaction_for\_review(charge['id'])
return jsonify(success=True)
Step 7: Create Custom Radar Rules
You can create custom rules in the Stripe Dashboard:
Example rule syntax:
:card_country: = 'US' AND :ip_country: != 'US'
This rule identifies transactions where the card is from the US but the IP address is not.
Step 8: Implement Advanced Fraud Detection with Additional Data
Send additional data to Stripe to improve fraud detection:
For Node.js:
// When creating a PaymentIntent
const paymentIntent = await stripe.paymentIntents.create({
amount: 2000,
currency: 'usd',
payment_method_types: ['card'],
// Additional data for fraud detection
metadata: {
order\_id: '6735',
customer\_id: '1234'
}
});
// When using Checkout Session
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line\_items: [{
price\_data: {
currency: 'usd',
product\_data: {
name: 'T-shirt',
},
unit\_amount: 2000,
},
quantity: 1,
}],
mode: 'payment',
success\_url: 'https://example.com/success',
cancel\_url: 'https://example.com/cancel',
// Additional data for fraud detection
customer\_email: '[email protected]',
metadata: {
order\_id: '6735'
},
payment_intent_data: {
description: 'Purchase of t-shirt',
metadata: {
order\_id: '6735'
},
shipping: {
name: 'Jenny Rosen',
address: {
line1: '123 Main St',
city: 'San Francisco',
state: 'CA',
postal\_code: '94111',
country: 'US',
},
},
},
});
Step 9: Set Up Fraud Alerts and Notifications
Configure alerts for high-risk transactions:
Custom webhook notification example (Node.js):
// In your webhook handler
if (event.type === 'charge.succeeded') {
const charge = event.data.object;
if (charge.outcome && charge.outcome.risk\_level === 'highest') {
// Send notification to your internal systems
await sendHighRiskAlert({
chargeId: charge.id,
amount: charge.amount,
currency: charge.currency,
riskScore: charge.outcome.risk\_score,
customerEmail: charge.billing\_details.email
});
}
}
Step 10: Monitor and Review Fraud Patterns
Regularly review and analyze fraud patterns:
Example code to fetch blocked payments for analysis (Node.js):
async function getBlockedPayments() {
try {
const charges = await stripe.charges.list({
limit: 100,
});
// Filter blocked or high-risk charges
const blockedOrHighRisk = charges.data.filter(charge => {
if (!charge.outcome) return false;
return charge.outcome.type === 'blocked' ||
charge.outcome.risk\_level === 'highest' ||
charge.outcome.risk\_level === 'elevated';
});
// Analyze patterns
const countryFrequency = {};
const ipFrequency = {};
blockedOrHighRisk.forEach(charge => {
// Count card countries
const country = charge.payment_method_details?.card?.country || 'unknown';
countryFrequency[country] = (countryFrequency[country] || 0) + 1;
// Count IP addresses if available
if (charge.metadata && charge.metadata.ip\_address) {
const ip = charge.metadata.ip\_address;
ipFrequency[ip] = (ipFrequency[ip] || 0) + 1;
}
});
return {
blockedOrHighRisk,
countryFrequency,
ipFrequency
};
} catch (error) {
console.error('Error fetching blocked payments:', error);
throw error;
}
}
Conclusion
Implementing proper fraud detection with Stripe Radar can significantly reduce your risk exposure. This tutorial covered the essential steps to configure, implement, and monitor fraud detection in your Stripe integration. Remember to regularly review your fraud prevention strategy and adjust it based on emerging patterns and your business needs.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.