Account

API documentation / Recipes

Welcome coupons: a first-order discount for first orders only

A coupon like WELCOME10 is checked against the email, and a new email is free. At checkout, ask SpoofLens whether this browser has already ordered under other emails, and keep the order while you refuse the discount.

The problem

Coupon farming looks like many small first orders: new emails, the same delivery area, the same few browsers. Each one costs you the discount, and often a delivery subsidy too.

Blocking the order loses a sale. This recipe refuses only the welcome discount and says so before payment, so a returning customer can still buy at the regular price.

What the API gives you

seen.accounts_on_device_30dHow many of your customer accounts (here: billing emails) used this device in the last 30 days, this one included.
device.idStore it with every order. Your own orders table then answers a second question: has this device already used a welcome coupon, even more than 30 days ago?
decision.actionWhat your rules say. An automated browser at checkout is rarely a customer.

The code

It calls the helper (sl_check_visitor and sl_user_ref), which sends the browser data from the form, the IP address, the headers and a hash of the email.

PHP

<?php
// checkout handler, only when a welcome coupon is applied
$welcome = ['WELCOME10'];                         // your first-order coupon codes
$couponRefused = false;
$deviceId = '';
if (in_array(strtoupper($coupon), $welcome, true)) {
    $r = sl_check_visitor(sl_user_ref($_POST['email']));
    if ($r) {
        $deviceId = $r['device']['id'];           // save it with the order
        $accounts = $r['seen']['accounts_on_device_30d'] ?? 1;
        // your orders table: SELECT 1 FROM orders WHERE device_id = ? AND coupon IN ('WELCOME10') LIMIT 1
        $usedBefore = welcomeCouponUsedOnDevice($deviceId);
        $couponRefused = $accounts >= 2 || $usedBefore || ($r['decision']['action'] ?? '') === 'block';
    }
}
if ($couponRefused) {
    // back to the checkout before payment, never a silent change of the total:
    // "The welcome discount is for a first order. You can still order at the regular price."
}

Node.js

// checkout handler (Express), only when a welcome coupon is applied
const welcome = ['WELCOME10'];                    // your first-order coupon codes
let couponRefused = false;
let deviceId = '';
if (welcome.includes(String(coupon).toUpperCase())) {
  const r = await slCheckVisitor(req, slUserRef(req.body.email));
  if (r) {
    deviceId = r.device.id;                       // save it with the order
    const accounts = (r.seen && r.seen.accounts_on_device_30d) || 1;
    // your orders table: SELECT 1 FROM orders WHERE device_id = ? AND coupon IN ('WELCOME10') LIMIT 1
    const usedBefore = await welcomeCouponUsedOnDevice(deviceId);
    couponRefused = accounts >= 2 || usedBefore || (r.decision && r.decision.action) === 'block';
  }
}
if (couponRefused) {
  // back to the checkout before payment, never a silent change of the total:
  // "The welcome discount is for a first order. You can still order at the regular price."
}

Python

# checkout handler (Flask), only when a welcome coupon is applied
welcome = {'WELCOME10'}                           # your first-order coupon codes
coupon_refused = False
device_id = ''
if coupon.upper() in welcome:
    r = sl_check_visitor(request, sl_user_ref(request.form['email']))
    if r:
        device_id = r['device']['id']             # save it with the order
        accounts = (r.get('seen') or {}).get('accounts_on_device_30d', 1)
        # your orders table: SELECT 1 FROM orders WHERE device_id = ? AND coupon IN ('WELCOME10') LIMIT 1
        used_before = welcome_coupon_used_on_device(device_id)
        coupon_refused = accounts >= 2 or used_before or (r.get('decision') or {}).get('action') == 'block'
if coupon_refused:
    # back to the checkout before payment, never a silent change of the total:
    # "The welcome discount is for a first order. You can still order at the regular price."
    pass

Check only orders that carry a welcome coupon: an ordinary order does not need it, and every check counts toward your monthly quota.

Soft steps instead of a ban

Rules in your account

Set them in Rules and alerts: the result comes back as decision in every answer, so your code does not change when the rules do.

Where it can be wrong

One line for your privacy policy

To prevent abuse of discounts, we check technical characteristics of your browser with SpoofLens (spooflens.com) when you place an order with a coupon.

Limits

Other recipes

Get a free key 1,000 checks a month free, no card.