---
title: "Hand out each licence key once · Agent Wranglers"
url: https://agentwranglers.se/playbook/ecommerce/orders-and-fulfilment/licence-keys-once
id: ECM-23
level: Recommended
updated: 2026-10-22
tokens: 674
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Hand out each licence key once

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

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

- ID: ECM-23
- Level: Recommended
- Chapter: [Orders and fulfilment](https://agentwranglers.se/playbook/ecommerce/orders-and-fulfilment.md)
- Rule: Assign licence keys, gift card codes and other single-use codes to an order line with one conditional update. Revoke the key when the line is refunded.
- Check: A test sends 50 orders at once against a pool of 50 keys. Every order gets one key and no key goes to two orders. Refunding one order marks its key revoked.
- How: Two orders that read the same free key both send it, and two customers share one licence. Claim a key with an update that sets the order line only where it is still empty. Skip locked rows so buyers do not wait on each other. Alert when unused keys fall below a set number, such as 50. Store keys encrypted or hashed where you only need to check them. On refund or withdrawal, mark the key revoked, so it stops working. The race is the one in [Make each change happen exactly once](https://agentwranglers.se/playbook/adversarial-testing/abuse-and-limits/race-conditions.md).

## 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
UPDATE licence_key SET order_line_id = $1, assigned_at = now()
WHERE id = (
  SELECT id FROM licence_key WHERE product_id = $2 AND order_line_id IS NULL
  ORDER BY id LIMIT 1 FOR UPDATE SKIP LOCKED
)
RETURNING code;
```

## 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

**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/orders-and-fulfilment/licence-keys-once">Agent Wranglers e-commerce and fulfilment playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Deliver downloads through short-lived links tied to the order](https://agentwranglers.se/playbook/ecommerce/orders-and-fulfilment/digital-downloads.md)
- [Orders and fulfilment](https://agentwranglers.se/playbook/ecommerce/orders-and-fulfilment.md)
