---
title: "Limit each coupon per customer instead of · Agent Wranglers"
url: https://agentwranglers.se/playbook/ecommerce/promotions-and-fraud/coupon-limits
id: ECM-37
level: Recommended
updated: 2026-10-22
tokens: 860
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Limit each coupon per customer instead of per account

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Promotions and fraud](https://agentwranglers.se/playbook/ecommerce/promotions-and-fraud.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: ECM-37
- Level: Recommended
- Chapter: [Promotions and fraud](https://agentwranglers.se/playbook/ecommerce/promotions-and-fraud.md)
- Rule: Enforce each coupon's limits on the server, with a unique constraint on its use per customer. Count a customer by normalised email, payment card fingerprint and delivery address, not by account alone.
- Check: A test uses a one-per-customer coupon from two new accounts with the same card and delivery address. The second order is refused the coupon. Ten parallel requests with one single-use code produce one discounted order.
- How: A first-order coupon that checks only the account is used once per new email address. Mark the coupon used in the same transaction that places the order. Then ten parallel requests cannot all use it, as [Make each change happen exactly once](https://agentwranglers.se/playbook/adversarial-testing/abuse-and-limits/race-conditions.md) explains. Normalise the email as [Compare email addresses and usernames in one canonical form](https://agentwranglers.se/playbook/accounts/sign-up/identifier-normalisation.md) shows. Store keyed hashes of the identifiers, as [Spot banned people who sign up again](https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse/ban-evasion.md) does. Release the use when the order is cancelled before it ships.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### SQL example

```sql
CREATE TABLE coupon_use (
  coupon_id     uuid NOT NULL,
  customer_hash bytea NOT NULL,   -- keyed hash of email, card fingerprint or address
  order_id      uuid NOT NULL,
  PRIMARY KEY (coupon_id, customer_hash)
);
```

## Related rules

- SEC-60 [Make each change happen exactly once](https://agentwranglers.se/playbook/adversarial-testing/abuse-and-limits/race-conditions.md) in Adversarial testing
- ACC-4 [Compare email addresses and usernames in one canonical form](https://agentwranglers.se/playbook/accounts/sign-up/identifier-normalisation.md) in Accounts and identity
- TNS-13 [Spot banned people who sign up again](https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse/ban-evasion.md) in Trust and safety

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/ecommerce/promotions-and-fraud/coupon-limits">Agent Wranglers e-commerce and fulfilment playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Apply discounts on the server in one fixed order](https://agentwranglers.se/playbook/ecommerce/promotions-and-fraud/discount-order.md)
- Next: [Fake urgency and scarcity](https://agentwranglers.se/playbook/ecommerce/promotions-and-fraud/fake-urgency.md)
- [Promotions and fraud](https://agentwranglers.se/playbook/ecommerce/promotions-and-fraud.md)
