> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shoppex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Serials & license keys

> Sell single-use codes like license keys, game codes, or gift cards.

Shoppex has two related but distinct systems for selling codes: Serials, for simple single-use codes, and Licenses, for software that needs status tracking and activation control.

## Serials (simple)

Use Serials fulfillment mode for Steam keys, gift codes, beta access codes, and other one-time codes buyers paste elsewhere.

### Uploading

Add codes from the product's **Serials** tab, either paste one per line or upload a CSV. Shoppex stores them as an unlocked pool. When a buyer pays, one code locks to their order and is removed from the pool.

The product lists as "out of stock" once the pool is empty. Top it up at any time.

### Replacements

If a buyer reports an invalid or already-used code, issue a replacement from the order detail page under **Replace**. The replacement comes from the remaining pool, and the bad code is marked burned so it will not be issued again.

## Licenses (advanced)

The Licenses system goes far beyond serials. Each license is its own object with:

* **Status**: `ACTIVE`, `SUSPENDED`, `REVOKED`, or `EXPIRED`. Change it at any time.
* **HWID binding**: bind a license to the first machine that activates it. Activations from other machines fail unless you reset the HWID.
* **IP locks**: restrict a license to a single IP or range.
* **Expiration**: licenses can be perpetual or expire on a date.
* **Event audit trail**: every license validation (successful or failed), HWID change, IP lock change, status change, and expiration extension is logged.

### Where to find it

The full licensing UI lives at `/licenses` in the dashboard, separate from regular products.

### Hardware-locked licenses

When a buyer activates a license through your software, your client sends the HWID to `POST /dev/v1/licenses/validate`. Shoppex either:

* accepts and binds the HWID if the license is unbound, or
* accepts if the HWID matches the bound one, or
* rejects if the HWID does not match.

When a buyer needs a new machine, they (or you) call **reset HWID** to unbind. Configure this flow from the license detail page or through the [API](/developers/quickstart).

### Status changes

Suspending a license blocks future validations without deleting it. Revoking a license is permanent and triggers a license event. Expired licenses stop validating but stay in the system for reference.
