Fraud detection API for e-commerce: know who is at checkout before the card is charged
Card testers, carders and coupon farmers all arrive with a card or a code that looks valid. The visit is harder to fake: a residential proxy, a fake browser, a script, one device behind many accounts. Maskbreak checks that visit in one server-side call and answers allow, review or block with the reasons, before your payment request leaves the server.
Four moments where store fraud shows up, and what the check returns
Checkout: card-testing runs
A script pushes stolen card numbers through small orders or a donation field to learn which ones still work, with a fresh IP for every attempt so per-IP limits never trip. When the device check recognises the script, it reports automation_detected, often with proxy_detected. Default: block, before you create the payment intent.
Checkout: stolen-card orders
A real card, the real billing address, and a residential proxy exit near it, so AVS and geolocation both agree. The browser is a new fake-browser profile. When the proxy exit and the fake browser are recognised, the check reports proxy_detected and antidetect_browser. Default: block. To send proxy-only orders to 3-D Secure instead, route them in your code (see the proxy section below), so the rest stay blocked.
Promo codes: one device, many first orders
Welcome codes and referral credit get claimed by one person under many new accounts. Send your customer ID, and when the device check resolves a device already seen with another of your accounts, the answer adds multi_account_device; send the email and a throwaway domain adds disposable_email. The usual action: refuse the discount, keep the order.
Login: account takeover
Leaked passwords are replayed against customer accounts for saved cards, loyalty points and gift card balances. Check the login once the password matches: a recognised script or proxy shows as automation_detected or proxy_detected, and a device signing into several of your accounts shows it in linked_accounts. Default: block the script; ask for a code on review.
Card testing: stop the run before the authorization
What it looks like. Bursts of small charges or donations, many different cards, the same cheap product, and a decline rate that climbs within minutes. The card numbers were bought in bulk; your checkout is simply the cheapest place to learn which ones are live.
Why IP rules miss it. Testing tools rotate the exit address on every attempt, often through residential proxies. The per-IP counter never reaches its limit, and each attempt arrives looking like a new shopper on a home connection.
What gives it away. Nobody types a thousand card numbers by hand. The run is scripted, and when the device check recognises the automation it reports device.automation: true with the reason automation_detected; a recognised proxy exit adds proxy_detected. Either one blocks by default. A device that comes back at an unusual rate adds high_activity_device, which raises the score without changing the decision.
The script that never loads your page. Many testing tools skip the page and post straight to your checkout route. They run no browser snippet, so they send no tokens: the answer carries degraded: true, no device block, and a decision that can read allow. Missing evidence is not a clean result, so in enforce mode treat it as review (3-D Secure or a hold), never as a pass.
The cloud-server caveat. A run from a rented cloud server that does not trip the automation check stays allow. The reason datacenter_asn is still listed, but company networks and some privacy tools use cloud addresses too, so it does not decide on its own. If your real customers never check out from one, set Datacenter server to Block on the console’s Rules tab, or to Review for a softer step. A scripted run from a cloud server, like the example below, still blocks either way, because a rule changes the decision only for the signal it names. Rules apply to every check, logins included; to act at checkout only, do it in code: when the decision is allow and the reasons include datacenter_asn, treat the order as review.
Shopping agents are automation too. Some headless checkouts are a customer’s AI assistant placing an order it was asked to place. automation_detected says the browser is automated, not why. If you accept agent orders, keep the default and route in code: when the decision is block and the reasons are automation_detected with nothing beyond datacenter_asn or high_activity_device, send the order to 3-D Secure instead of refusing it. Setting Bot / automation to Review on the Rules tab does much the same for every check on your account, logins included; a scripted run that also shows a proxy, a fake browser or an emulator still blocks. Separating AI agents from attackers covers the trade-off.
Where the check goes. In the server route that creates the payment intent: after the form posts, before you call your processor. A refusal there never reaches the card network, so the tester learns nothing about the card, and depending on your processor it can also save a per-attempt fee. Keep your processor’s velocity rules and 3-D Secure behind it. The card-testing playbook and card testing on Stripe go further.
Example response, selected fields: a headless checkout script on a cloud server.
{
"decision": "block",
"risk_score": 80,
"reasons": ["datacenter_asn", "automation_detected", "high_activity_device"],
"network": {
"vpn": false, "proxy": false, "datacenter": true,
"tor": false, "service": null
},
"device": {
"automation": true, "antidetect": false,
"high_activity": true, "tampering_score": 0
}
}Proxy detection for e-commerce: carding, payment fraud and the IP that looks clean
The setup. A carder buys the card details, rents an exit on a residential proxy network in the cardholder’s city, and opens a fresh fake-browser profile for the order. (Fake browsers, sold as antidetect browsers, give every profile its own believable device.) The billing address is genuine, so AVS passes. The IP belongs to a consumer ISP near that address, so geolocation agrees. Nothing on the order is false except the person placing it.
Why reputation lists say clean. A residential proxy exit is somebody’s home connection, resold. It has no abuse history of its own, and a cloud-range check passes it because it is not a cloud server. Proxy detection for payment fraud has to know the proxy networks, not the address’s past. Maskbreak’s network intelligence follows those networks and applies to a live visit; a bare IP lookup covers only Tor exits and published cloud ranges, which is why this check needs the browser snippet. When the exit is recognised, the response reads proxy: true with datacenter: false.
The browser is the second tell. A fake browser changes what the page can read about the device, and those changes are what the device check looks for. antidetect_browser blocks on its own, so when the device check flags the browser, the order stops even if the proxy exit was not recognised. If you forward the browser’s time zone, a zone that disagrees with the exit’s country on an otherwise clean network adds timezone_mismatch and moves an allow to review.
What to do with it. Refuse before authorization. If you prefer a challenge to a refusal for proxy-only visits, keep the default and route in code: when the decision is block and the only reason is proxy_detected, send the order through 3-D Secure. A customer completes it; a carder holding only the card details usually cannot. Setting Proxy to Review on the Rules tab does much the same for every check on your account, logins included. It softens the proxy only: the example below, a fake browser behind a proxy, still blocks, and so does a proxied card-testing script. A VPN is a different case. Plenty of real shoppers use one, so a VPN on its own is flagged for review (vpn_detected, with the service named when known), never blocked by default.
Example response, selected fields: a fake browser behind a residential proxy.
{
"decision": "block",
"risk_score": 93,
"reasons": ["proxy_detected", "antidetect_browser"],
"network": {
"vpn": false, "proxy": true, "datacenter": false,
"tor": false, "service": "<operator name when known>"
},
"device": {
"antidetect": true, "automation": false,
"tampering_score": 0.8
}
}give away a stolen-card order that every address check passes: the proxy exit and the fake browser. The playbook follows one such order from the carder’s setup to the refusal, with a worked cost model to fill in with your own numbers. Illustrative, not a customer result.
Read the playbookCoupon and promo abuse: one device, many new customers
The pattern. A welcome code, a referral credit or a free-shipping first order is worth the same to anyone who claims it, so one person claims it many times: a new email for each account, sometimes a disposable inbox, often the same laptop.
Linking the accounts. When a code is redeemed, send your own customer ID as accountId, taken from the session your server trusts, never from a form field. Maskbreak links it as a keyed hash, scoped to your account and never compared across customers, and counts how many of your accounts the device has been seen with. From the second one on, the response carries device.multi_account: true, the count in device.linked_accounts and the reason multi_account_device.
It changes nothing by default. Households share laptops, so a linked device is evidence, not a verdict. The decision stays as it was until you set Multi-accounting on the Rules tab or read the reason in your redemption code. The proportionate answer is usually to refuse the discount and let the order go through at full price.
When the accounts do not link. A farmer who opens a new fake-browser profile per account may break the device link; the fake browser is then the tell, and antidetect_browser blocks by default when the device check recognises it. Send the order email as well: a throwaway domain adds disposable_email and moves an allow to review. That is a domain check only, not mailbox verification or email reputation. Guest checkout has no customer ID to link, so if first-order codes cost you real money, requiring an account to redeem them is what makes linking possible. More in promo and bonus abuse and multi-accounting.
Account takeover at login: check the session, keep the password check
Why store accounts get stolen. A customer account holds a saved card, a delivery address, loyalty points and sometimes a gift card balance. Credential stuffing replays leaked email and password pairs against your login through residential proxies, a few attempts per address, so per-IP limits see ordinary traffic.
Where the check goes. Once the password matches and before you issue the session, with the customer ID as accountId. The ID then comes from an account the visitor has just proved, not from the email they typed. A recognised script or proxy stops there on automation_detected or proxy_detected even with the right password, and one device signing into several of your customers’ accounts shows it in linked_accounts. On review, a VPN for instance, ask for a one-time code or a passkey rather than refusing. Run the same check when an account changes where money or goods go: a new delivery address, a new saved card, a gift card redemption.
What stays yours. Passwords, passkeys, MFA, session handling and rate limits. Maskbreak adds evidence about the visit; it does not decide who owns the account. More in account takeover prevention that holds up, credential stuffing detection and the account-takeover playbook.
Fraud detection for marketplaces: check the seller side too
Where marketplace money leaks. Buyer checkout gets the same check as any store. The costlier fraud often sits with sellers: a removed seller back under a new name, a shop that exists to push stolen cards through its own listings, a seller account taken over so the next payout goes somewhere new. Each has a form your server handles, and that form is where the check goes.
Seller signup. Evaluate the signup with the new account’s ID as accountId. If a removed seller’s old account was checked from the same browser, the check on the new signup adds multi_account_device and linked_accounts counts both. Links expire after 90 days without a sighting, so a seller who waits long enough starts clean. A return in a fresh fake-browser profile shows up as antidetect_browser when the device check recognises it. None of this is identity verification: keep your KYC step for sellers who get paid.
Payout changes. After a seller account is taken over, the tell is quiet: new bank details, then the next payout. Run the check on the payout-details form with the seller’s ID. On block, refuse the change. On review, ask for a passkey or one-time code and hold the first payout to the new account until the seller confirms it through a channel you already trust.
Buyer and seller on one device. Self-purchases, whether to fake a sales history or to cash out stolen cards through a shop the fraudster controls, tend to come from one device on both sides. Send your user ID as accountId for buyers and sellers alike, and a device used for both counts both in linked_accounts. If buyers and sellers sit in separate tables with overlapping numbers, prefix them (buyer:1042, seller:1042) so two different people never share an ID. Links are scoped to your marketplace and never compared with other Maskbreak customers. More in marketplace fake accounts, multi-accounting and fake signups.
What it does not do: order scoring and chargeback guarantees
Maskbreak judges the visit, not the order. It does not read the basket, the card’s BIN, AVS or CVV results, the order value or the shipping choice. It has no transaction model, no shared network of other merchants’ outcomes, no manual review team and no chargeback guarantee. A clean visit is not a promise that the order is good, and there is no published detection rate to quote.
So pair it. Keep 3-D Secure and your processor’s fraud rules. If disputes are your main cost, an order-scoring or chargeback-guarantee service belongs in the stack as well. This check runs earlier, on the session, and can stop scripted and proxied traffic before that tool sees an order. How the two kinds of tool compare: Maskbreak vs Kount, Maskbreak vs Forter and Signifyd alternatives.
Where the check goes in your checkout code
The browser snippet, sentinel.js, adds two tokens to your checkout form. Your server forwards them to POST /v1/evaluate with the API key, which never leaves the server. Maskbreak never receives the card number, CVV or billing address; those go to your processor only. If your payment page falls under PCI DSS rules for page scripts, list sentinel.js in that inventory like any other script.
The example starts in watch mode, as the integration guide recommends: it logs each decision, lets every order through and fails open. After a few days, compare the log with the Events tab, then switch to enforce; the guide’s enforce handler also holds missing evidence and outages. On WooCommerce the same call sits in two hooks (guide). If your checkout is hosted and runs none of your code before payment, check the forms you do control: login, account creation and promo redemption (on Shopify, see Shopify bot detection). SDKs for Node, Python and PHP are on the integrations page.
// Checkout route: evaluate before you create the payment intent // Watch mode first: log the verdict, always continue, fail open const body = req.body || {}; // sentinel.js adds monocle + sentinel_fp to your form let risk = null; try { const verdictRes = await fetch('https://maskbreak.com/v1/evaluate', { method: 'POST', signal: AbortSignal.timeout(5000), headers: { 'Authorization': 'Bearer ' + process.env.MASKBREAK_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ token: body.token || body.monocle, // network evidence fingerprintEventId: body.fingerprintEventId || body.sentinel_fp, // device evidence tz: body.tz || body.sentinel_tz, email: body.email, // optional: adds disposable_email accountId: req.user?.id // optional: your customer ID, never a form field }) }); if (verdictRes.ok) risk = await verdictRes.json(); } catch {} // unreachable or timed out: checkout still runs console.log('[maskbreak]', JSON.stringify({ decision: risk?.decision ?? null, reasons: risk?.reasons ?? null, risk_score: risk?.risk_score ?? null, degraded: risk ? !!risk.degraded : null })); // Enforce later: route on risk?.decision // block -> refuse here, before the payment intent exists // review -> require 3-D Secure, or hold the order for a person // degraded, no device block or no answer -> same as review: // a script that never loaded the page sends no evidence, // and missing evidence is not a clean result // allow -> create the payment intent as usual
E-commerce fraud API questions
allow, review or block with the reasons behind it.allow unless you set Datacenter server to Review or Block on the Rules tab; a scripted run from a cloud server still blocks either way. A script that posts without loading your page sends no browser evidence, so treat a degraded answer as review, not as a clean allow. Keep your processor’s velocity rules and 3-D Secure behind it; no single check stops every run.linked_accounts, and it is never matched against other Maskbreak customers.Put one check in front of your checkout
Free plan: 10,000 visitor checks a month, every signal included, no card. Paid plans from €29 a month. Start in watch mode and read your own traffic in the Events tab first.