Digital goods have a specific fraud problem that physical ecommerce doesn't. There's no shipping address to validate, no delivery delay to catch a problem in, and nothing to reclaim once it ships. A license key is useful the instant it's revealed and just as easy to resell the instant after. For Increddy, a storefront selling game and software license keys, that made a dedicated risk layer non-negotiable, not an afterthought bolted on after launch.

Why digital goods sit at the top of the chargeback-risk list

Payment processors rank digital goods among the highest-risk categories for a reason: the combination of instant delivery and zero physical recovery is exactly what makes a stolen card attractive to use. A fraudster doesn't need a shipping address that matches anything, doesn't need to wait for a package, and doesn't need the purchase to survive a delivery-confirmation check. The key is valuable the second it's issued. That's the threat model a license-key storefront's checkout has to design against, explicitly, rather than inheriting the assumptions a general-purpose ecommerce stack makes about physical goods.

Where Stripe's fraud tooling stops

Stripe's own fraud tooling scores the payment: the card, the device, the transaction pattern, against signals visible across Stripe's network. That's genuinely useful and Increddy keeps it in the stack. But it scores a payment, not a product category. It has no way to know that this particular checkout is for an instantly-deliverable, instantly-resellable digital asset, or that a chargeback here carries close to zero chance of recovering anything. A generic payment-risk score and a digital-goods-specific risk score are answering two different questions, and a storefront in this category needs both answered, not just the first one.

A module in the checkout path, not a rule bolted on after

The fix was architectural, not a config tweak: a custom risk-scoring module that sits in the checkout flow and can block checkout completion on its own authority, independently of whatever Stripe's checks return. That separation matters. If the risk layer only ran after Stripe approved a payment, it would be reacting to a decision already made instead of participating in the decision itself. Built as a first-class Medusa module rather than a webhook reacting after the fact, it gets a vote before the order is placed, not a note added to a transaction that already happened.

Selling something that's valuable the instant it's delivered?

Digital goods, subscriptions, and instant-access products all carry this exact risk profile. We'll walk through what a dedicated risk layer would need to catch for your specific product.

Talk to an engineer →

What we won't publish, and why

One thing this post deliberately doesn't do is list the exact signals the module scores or the thresholds it uses. That's not a hedge, it's the same reason banks don't publish their fraud rules: a risk-scoring system's value depends partly on fraud actors not being able to read the rulebook and engineer around it. What's worth saying publicly is the architecture, the "independent authority to block checkout" design and why that beats a bolted-on rule. What's not worth saying publicly is the specific heuristics, because publishing them would make them worse at their job.

The rule

Treat fraud risk as a property of the product category, not just the payment. A generic payment processor's fraud tooling is necessary but not sufficient for a product that's valuable the instant it's delivered and impossible to reclaim after. Give the risk decision a real seat in the checkout flow, with the authority to block completion on its own, and keep the specifics of how it decides unpublished on purpose. For the broader migration this checkout sits inside, see how we replaced Shopify's backend without touching the frontend, and for the other hard concurrency problem in the same checkout, see how we made key delivery idempotent. We build checkout and risk logic like this under Medusa development engagements.