---
title: "Generated codes — Coupons for Laravel | Roundly"
description: "Control the length and alphabet of auto-generated codes — drawn from a CSPRNG, case-insensitive like every code, validated on every use."
url: https://roundly-consulting.com/open-source/docs/coupons-for-laravel/generated-codes
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Coupons for Laravel](https://roundly-consulting.com/open-source/docs/coupons-for-laravel.md)

# Generated codes

When you don’t pass a code, CreateCouponAction generates one: code.length symbols, each drawn uniformly from code.charset by PHP’s Random\\Randomizer, whose default engine is the CSPRNG. Leave out look-alike characters if customers type codes by hand:

```php
// config/coupons.php
'code' => [
    'length' => 8,
    'charset' => 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789', // no 0/O or 1/I look-alikes
],
```

```php
use RoundlyConsulting\Coupons\Enums\DiscountType;
use RoundlyConsulting\Coupons\Facades\Coupons;

$coupon = Coupons::generate(DiscountType::Percentage, value: 1000); // no code given

$coupon->code; // e.g. "K7QM2XWD"
```

## Uniqueness

A generated code is checked against every existing coupon, soft-deleted ones included — even though a pruned coupon’s code is free to reuse, a fresh code never collides with its redemption history. If 10 candidates in a row are taken, the code space is too small: the action throws InvalidCouponConfiguration telling you to widen it or pass an explicit code, rather than looping forever.

## Case-insensitive codes

Codes are case-insensitive. Every code is stored trimmed and upper-cased — through the action, a factory or straight onto the model — so ' summer ' is stored as SUMMER. Every lookup normalises the code the same way: find(), exists(), check(), preview(), redeem(), expireAll(), the validation rule, whereCode(), hasRedeemed() and {coupon} route binding. Matching and uniqueness never depend on your database’s collation:

```php
use RoundlyConsulting\Coupons\Enums\DiscountType;
use RoundlyConsulting\Coupons\Facades\Coupons;
use RoundlyConsulting\Coupons\Models\Coupon;

$coupon = Coupons::generate(DiscountType::Percentage, 1000, code: '  summer ');
$coupon->code;                                   // "SUMMER"

Coupons::find('Summer');                         // the same coupon
Coupons::exists(' SUMMER ');                     // true
Coupon::query()->whereCode('summer')->first();   // the same coupon
```

## Validation

Both keys are validated every time a code is generated, and the message names the key. A charset message never prints the alphabet — it is the key space every generated code is drawn from.

- code.length — an integer from 4 to 64; an integer env string such as “8” is accepted, while “eight” or “8.5” throws.
- code.charset — a string of at least 2 symbols, with no duplicates (case-insensitively), whitespace, control characters or invalid UTF-8. It’s upper-cased like every code, so “a” and “A” are one symbol; multibyte symbols are fine.
- A key that is not set — absent, null or blank, like COUPONS\_CODE\_LENGTH= — falls back to the default: 6 characters from A–Z and 0–9.

```php
use RoundlyConsulting\Coupons\Enums\DiscountType;
use RoundlyConsulting\Coupons\Exceptions\InvalidCouponConfiguration;
use RoundlyConsulting\Coupons\Facades\Coupons;

config()->set('coupons.code.charset', 'AaBb'); // "a" and "A" are one symbol

try {
    Coupons::generate(DiscountType::Percentage, value: 1000);
} catch (InvalidCouponConfiguration $e) {
    $e->getMessage();
    // "Configuration value [coupons.code.charset] must not contain duplicate symbols (case-insensitively)."
}
```

Explicit codes are never checked against the format — pass any code you like, such as LAUNCH20. They are still trimmed and upper-cased, and a blank one throws InvalidCouponDefinition.

## In the about command

php artisan about --only=coupons reports the format by size only, e.g. “8 chars from a 32-symbol alphabet”. An unusable value shows as INVALID: … instead of failing the command.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/coupons-for-laravel.md)
