Risk Evaluation

Access Stripe's machine learning system judgments in the Dashboard and the API. If you need help after reading this, get in touch or chat live with other developers in #stripe on freenode.

At Radar’s core is an adaptive machine learning system that evaluates each payment’s risk level in real-time. It uses hundreds of signals about each payment and taps into data across our network of 100,000+ businesses to predict whether a payment is likely to be fraudulent.

Our machine learning system is flexible and responsive, continuously learns from new customer behaviors and transaction features, and incorporates feedback from you whenever payments are indicated as fraudulent.

Outcomes in the Dashboard

Stripe’s machine learning models evaluate how likely it is that a payment might be fraudulent. This judgment can take one of three values: normal, elevated, or high (referred to as highest through the API). Payments with an elevated or high risk level include the factor that Stripe’s machine learning models identified as the primary driver of risk on the payment. On the payment detail page, you can see both the risk level and the factor that Stripe identified as the primary driver of risk on the payment.

High risk

Stripe reports payments as high risk when we believe they are likely to be fraudulent, blocking them by default.

Elevated risk

Elevated risk payments have an increased chance of being fraudulent. Stripe allows these payments by default while also automatically placing them into your review queue for you to take a closer look at.

Normal risk

Payments with a normal risk evaluation have fewer characteristics that are strongly indicative of fraud than payments that have elevated or high risk. However, we recommend that you continue to be vigilant when fulfilling these orders. Payments that have normal risk can still turn out to be fraudulent and there are other possible types of fraud that can be committed later on in the order process.

Feedback on risk evaluations in the Dashboard

Stripe’s machine learning models respond to feedback you share with us. While we utilize information across our network to evaluate a payment, you may have additional information about a payment as a result of a customer interaction. You can override any of our decisions based on the knowledge you have about your customers.

If you believe payment that was not blocked is actually fraudulent, you can refund and report it as fraudulent in the Dashboard. We use this information to improve our fraud detection algorithms and the accuracy of our risk evaluations for this payment, and similar ones in the future.

Searching for a specific risk level in the Dashboard

You can search for payments of a specific risk level using the risk_level search term and the desired risk level. For example, a search for risk_level:highest returns a list of all payments with a high risk level. Likewise, a search for risk_level:elevated returns a list of all payments with an elevated risk level.

Outcomes in the API

The risk evaluation for each payment is also available programmatically through the Stripe API. The Charge object contains the Outcome attribute. This includes all of the payment’s risk information and overall outcome of the payment. Here is an example outcome of a successful payment:

...
"outcome":
{
  network_status: "approved_by_network",
  reason: null,
  seller_message: "The charge was authorized.",
  risk_level: "normal",
  type: "authorized",
}
...

Here is an example outcome of a payment that was evaluated as high risk and blocked by Stripe without appearing on your customer’s statement:

...
"outcome":
{
  network_status: "not_sent_to_network",
  reason: "highest_risk_level",
  risk_level: "highest",
  seller_message: "Stripe blocked this charge as too risky.",
  type: "blocked",
}
...

If a payment is declined by the customer’s bank, the outcome also includes any additional information for why it was declined when that information is available to Stripe:

...
"outcome":
{
  network_status: "declined_by_network",
  type: "issuer_declined",
  reason: "insufficient_funds",
  risk_level: "elevated",
  seller_message: "The card issuer declined to process this charge due to insufficient funds.",
}
...

Feedback on Stripe’s risk evaluation in the API

Stripe’s machine learning models respond to feedback you share with us. In addition to providing feedback in the Dashboard, you can also override any of our risk evaluations through the API. You can indicate that a payment is fraudulent when making a refund request by providing fraudulent as the value for reason. If you have refunded a payment but did not provide a reason, you can still report that it was fraudulent.

# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

# If you haven't refunded the charge, you can do so and let Stripe
# know it was fraudulent in one step.
charge = Stripe::Charge.retrieve(charge_id)
charge.refunds.create(reason: 'fraudulent')

# If you already refunded the charge (without specifying the
# 'fraudulent' reason), you can still let us know it was fraudulent.
refunded_charge = Stripe::Charge.retrieve(refunded_charge_id)
refunded_charge.mark_as_fraudulent
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

# If you haven't refunded the charge, you can do so and let Stripe
# know it was fraudulent in one step.
charge = stripe.Charge.retrieve(charge_id)
charge.refunds.create(reason='fraudulent')

# If you already refunded the charge (without specifying the
# 'fraudulent' reason), you can still let us know it was fraudulent.
refunded_charge = stripe.Charge.retrieve(refunded_charge_id)
refunded_charge.mark_as_fraudulent()
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

// If you haven't refunded the charge, you can do so and let Stripe
// know it was fraudulent in one step.
$charge = \Stripe\Charge::retrieve($charge_id);
$charge->refunds->create(array("reason" => "fraudulent"));

// If you already refunded the charge (without specifying the
// 'fraudulent' reason), you can still let us know it was fraudulent.
$refunded_charge = \Stripe\Charge::retrieve($refunded_charge_id);
$refunded_charge->markAsFraudulent();
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";

// If you haven't refunded the charge, you can do so and let Stripe
// know it was fraudulent in one step.
Charge charge = Charge.retrieve(chargeId);

Map<String, Object> refundParams = new HashMap<String, Object>();
refundParams.put("reason", "fraudulent");

charge.refund(refundParams);

// If you already refunded the charge (without specifying the
// 'fraudulent' reason), you can still let us know it was fraudulent.
Charge refundedCharge = Charge.retrieve(refundedChargeId);
refundedCharge.markFraudulent((RequestOptions) null);
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

// If you haven't refunded the charge, you can do so and let Stripe
// know it was fraudulent in one step.
stripe.charges.createRefund(
  charge_id, {"reason": "fraudulent"})

// If you already refunded the charge (without specifying the
// 'fraudulent' reason), you can still let us know it was fraudulent.
stripe.charges.markAsFraudulent(charge_id);

Next steps