OXXO Pay lets customers in Mexico buy online and pay in cash. Checkout produces a voucher with a payment reference; the customer takes it to an OXXO store, pays at the counter, and the merchant gets confirmation once the payment is processed. For shoppers without a card, or who don’t want to use one online, it’s often the way they pay.
That’s good for conversion and changes your fraud profile. With no card in the transaction, card signals disappear: no BIN, no AVS, no 3-D Secure, no card fingerprint to dedupe on. The classic stolen-card problem mostly goes away too. What replaces it are patterns that exploit the gap between “order placed” and “order paid.”
The patterns
Unpaid-order hoarding
When checkout ends with a voucher, you have to decide what happens to the stock while you wait. If you reserve it, every unpaid voucher holds inventory until it expires. If you don’t, a customer who walks to the store and pays may find the item is gone.
Most merchants reserve, and that’s the opening. Someone generates vouchers for limited items with no intention of paying, or with the intention of paying for only the ones they can resell. Stock sits locked until expiry, real customers see “sold out,” and the hoarder pays for whichever items turn out to be worth flipping.
Inventory denial during drops
The same mechanism, scripted. During a launch or a limited drop, bots place many orders that end in vouchers, locking most of the stock in minutes. It’s the cash-payment version of denial-of-inventory bots, and it’s harder to spot because the orders look like normal pending payments, not failed card attempts.
Multi-account promo abuse
First-order discounts, welcome coupons and referral credit are usually limited per account. With card payments, a reused card is at least a weak link between accounts. With cash, there’s nothing: each new email gets a new first-order discount, and the person pays each voucher with the same bills at the same store. Resellers do this at volume. Promo abuse prevention covers the general mechanics; cash just removes one of the usual safeguards.
Voucher testing and junk orders
Less costly but noisy: scripts placing orders to test checkout flows, coupons, or price errors, abandoning every voucher. They inflate your pending-order count and confuse forecasting.
What doesn’t work
- Card rules. There’s no card.
- Email or phone uniqueness. Both are cheap to rotate, and many shoppers legitimately share a family phone number.
- Blocking by IP. Mobile carriers put large numbers of real customers behind shared IPs, so IP limits catch households, not hoarders.
- Requiring an account. Accounts are free; that just moves the abuse to signup.
What works: limits keyed on the device
The person behind ten unpaid vouchers usually places them from one or two phones or laptops. A device identifier that survives cleared cookies and private browsing ties those orders together even across different accounts and emails.
Identify at checkout and send the requestId with the order. On the server, fetch the event and look at what this device already has pending:
import { PryntServer } from '@prynt/node';
const prynt = new PryntServer({ secretKey: process.env.PRYNT_SECRET_KEY });
async function oxxoCheckoutPolicy(requestId) {
const event = await prynt.getEvent(requestId);
if (event.decision === 'block') return { allowOxxo: false, reason: 'blocked' };
const visitorId = event.visitorId;
const pending = await db.orders.count({ visitorId, method: 'oxxo', status: 'pending' });
const expired90d = await db.orders.count({ visitorId, method: 'oxxo', status: 'expired', days: 90 });
if (pending >= 2) return { allowOxxo: false, reason: 'too_many_pending_vouchers' };
if (expired90d >= 3) return { allowOxxo: true, reserveStock: false, reason: 'expiry_history' };
return { allowOxxo: true, reserveStock: true, visitorId };
}
Store visitorId on every order. The order table is yours; Prynt supplies the device identity, and your policy decides what to do with it. The thresholds above are placeholders. Set them from your own data: look at how many pending vouchers your real repeat customers typically hold at once, and set the cap above that.
Tiered responses instead of a refusal
Taking cash away entirely punishes the customers who need it. A gentler ladder:
- Normal: reserve stock for the voucher’s lifetime.
- Watch: the device has a history of expired vouchers. Accept the order but don’t reserve stock, and say so on the confirmation page.
- Limit: the device already holds the maximum pending vouchers. Ask them to pay one before generating another, or offer a card or bank transfer for this order.
- Block: Prynt’s decision is
block(automation, tampering, a device flagged before), or many fresh accounts on one device during a drop.
Promotions: one per device, not per account
For welcome discounts and referral credit, apply the limit on the device. If you link accounts at signup with updateEvent(requestId, { linkedId }), the event’s accountsOnDevice shows how many accounts that device has opened, and a new account on a device with several others shouldn’t get a first-order discount automatically. The multiAccount signal (two or more accounts on a device in 30 days) is a ready-made flag for this.
Drops: limit before the stock locks
For limited releases, the check has to happen before the voucher exists, because the voucher is what locks the stock. During a drop:
- Cap pending OXXO orders for a limited item at one per device.
- Challenge traffic that Prynt marks
challenge; the agent’schallenge()runs a proof-of-work step instead of a CAPTCHA. - Watch for many accounts created minutes before checkout on the same device.
Bots tend to show themselves through automation and datacenter or proxy signals, while hoarders show up as one device with many pending orders. Both are visible without a card.
Keep cash checkout open
The goal isn’t to make OXXO Pay harder. For most customers, it’s how they pay. The goal is to stop a small number of devices from locking stock and collecting first-order discounts they aren’t entitled to. Store the device on every order, cap pending vouchers per device, and apply promo limits per device rather than per account.
For more context, see ecommerce fraud prevention and the ecommerce solutions page. Start by adding visitorId to your order table this week; the next time stock disappears into unpaid vouchers, you’ll be able to see whether it was a hundred customers or three phones.
Try it free
Prynt is device intelligence with a free tier — visitor IDs, bot & fraud Smart Signals, and behavioral biometrics, powered by a cross-site network. Start free.