Introduction
Stripe Radar protects payments with a machine learning-powered fraud detection engine. In 2026, businesses handle high volumes of international transactions, making static rules insufficient. This tutorial shows how to create dynamic rules, automate reviews, and integrate contextual signals. You will learn to reduce false positives while blocking sophisticated fraud. Each step includes functional TypeScript code ready to deploy.
Prerequisites
- Stripe account with Radar enabled (Pro plan or higher)
- Node.js 20+ and TypeScript
- Stripe API keys (test and live)
- Solid knowledge of webhooks and transactions
Initialize the Stripe Client
import Stripe from 'stripe';
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2025-12-31.acacia',
typescript: true,
});Initialize the client with the latest API version. Store the key in environment variables and enable strict typing to avoid runtime errors.
Create a Custom Radar Rule
import Stripe from 'stripe';
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2025-12-31.acacia',
typescript: true,
});This rule triggers a manual review for high-risk countries. Use value lists to easily maintain the list without changing code.
Handle Review Events via Webhook
import { stripe } from '../lib/stripe';
async function createRadarRule() {
const rule = await stripe.radar.valueLists.create({
alias: 'high_risk_countries_2026',
name: 'Pays à risque élevé 2026',
items: [
{ value: 'NG' },
{ value: 'RU' }
]
});
const radarRule = await stripe.radar.rules.create({
action: 'review',
predicate: `card.country in ${rule.id}`,
scope: 'all'
});
console.log('Règle créée:', radarRule.id);
}
createRadarRule();Verify the webhook signature to secure the endpoint. Process review.created and review.closed events to automate decisions and internal notifications.
Dynamically Update Value Lists
import { stripe } from '@/lib/stripe';
import { headers } from 'next/headers';
export async function POST(req: Request) {
const body = await req.text();
const sig = headers().get('stripe-signature')!;
let event;
try {
event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
} catch (err) {
return new Response('Webhook signature invalide', { status: 400 });
}
if (event.type === 'review.created' || event.type === 'review.closed') {
const review = event.data.object;
await handleRadarReview(review);
}
return new Response('OK', { status: 200 });
}
async function handleRadarReview(review: any) {
console.log('Revue Radar:', review.id, review.reason);
// Logique métier : notifier l'équipe ou bloquer l'utilisateur
}Add countries dynamically without recreating the list. Avoid duplicates to keep rules performant and prevent unnecessary costs.
Real-Time Radar Decision Query
import { stripe } from '../lib/stripe';
async function updateValueList(listId: string, newCountries: string[]) {
const list = await stripe.radar.valueLists.retrieve(listId);
const existing = list.items.map((i: any) => i.value);
const toAdd = newCountries.filter(c => !existing.includes(c));
for (const country of toAdd) {
await stripe.radar.valueListItems.create({
value_list: listId,
value: country
});
}
console.log('Liste mise à jour avec', toAdd.length, 'nouveaux pays');
}Retrieve the risk score after PaymentIntent creation. Automatically cancel high-risk transactions to reduce losses.
Best Practices
import { stripe } from './stripe';
export async function evaluateWithRadar(paymentIntentId: string) {
const pi = await stripe.paymentIntents.retrieve(paymentIntentId, {
expand: ['latest_charge']
});
const charge = pi.latest_charge as any;
if (charge && charge.outcome && charge.outcome.risk_score > 75) {
await stripe.paymentIntents.cancel(paymentIntentId);
return { blocked: true, reason: 'Radar score élevé' };
}
return { blocked: false };
}Always test rules in test mode before going live. Use value lists instead of hardcoded predicates. Monitor false positive metrics weekly. Combine Radar with 3D Secure for medium scores. Document every rule with its expected impact on fraud rate.
Common Mistakes to Avoid
- Forgetting to verify webhook signatures (risk of spoofing)
- Creating too many conflicting rules that cancel each other out
- Ignoring review.closed events and accumulating manual reviews
- Not updating value lists with fresh data
Further Reading
Deepen your automation with our Learni trainings on Stripe and fraud.