Skip to main content
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

Keys have their own page, not a tab on the product. Open the product, go to Delivery & Stock, and choose Manage keys. That takes you to /products/:id/serials, where the whole pool lives. On that page:
  • Add keys opens a box that takes one key per line.
  • Import reads a .txt or .csv file and loads it into the same box, again one key per line.
While you are first creating the product, you can paste the opening batch straight into the form instead. Every place that adds keys uses the same rule: one key per line. Commas and semicolons stay part of the key, so [email protected]:pass,2fa is one key.
  • Repeated lines in one paste are added once. The box shows how many repeat before you add them. If identical lines are your stock units (for example a placeholder you deliver by hand), tick Keep repeated lines as separate units.
  • Keys you already have (in stock or already delivered) are skipped and counted.
  • Long keys: a key can have up to 10,000 characters. A longer line stops the whole paste, and the message names the line. This usually means several keys ended up on one line.
The Developer API uses the same rules when it sends keys, whether in POST /dev/v1/products, PATCH /dev/v1/products/{id} or POST /dev/v1/products/{id}/serials. To keep repeated keys as separate units, send allow_duplicates_in_batch: true. The response counts dropped repeats in duplicates_in_batch. stock_delimiter only accepts newline. A PATCH with serials replaces only keys that are still for sale: keys reserved by an open checkout, delivered or taken out stay, and a key the product still holds is not added again. Shoppex stores the keys as an unlocked pool. When a buyer pays, one key locks to their order and leaves the pool.

Keys without a variant

On a product with more than one variant, every key belongs to a variant. Keys without one are never sold. Pick Unassigned in the Variant filter, select the keys and choose Move Keys. Keys that an open checkout holds stay where they are.

Taking keys out and exporting

  • Take Out Keys is for keys you sell or hand out somewhere else, for example on Discord or to a reseller. The keys leave your stock in your hand-out order and show as Used. Shoppex records who took them out and when.
  • Export CSV downloads the keys of the current view (search, stock view, variant). The keys stay in stock. Exports are logged and limited to 10 per 10 minutes per team member. Exporting needs the Export Data permission as well. A key that starts with =, +, - or @ gets an apostrophe in front in the file, so a spreadsheet does not run it as a formula. Import reads such a file back by its key column and removes that apostrophe again. In the file, used means taken out or claimed through the API, and also keys removed before removal deleted them for good.
A key that is reserved by an open checkout cannot be edited, moved or taken out until the checkout completes or expires. The product lists as “out of stock” once the pool is empty. Top it up at any time.

Hand-out order

By default the pool goes out oldest key first: the first key you added is the first one a buyer gets. Key Hand-Out Order on the product’s Delivery & Stock tab changes this: The setting governs both ways a key leaves the pool: the automatic hand-out when a payment completes, and a key you claim yourself. On the API the field is serial_delivery_order, with the values FIRST, LAST, and RANDOM.

Replacements

If a buyer reports an invalid or already-used code, open the order and choose Issue Replacement from its actions menu. You can add a reason, which is kept with the order. The action is offered only when all three are true:
  • the order is COMPLETED,
  • it holds exactly one product,
  • and that product’s mode is Serials.
A cart with two products, or an order still waiting on payment, does not get the action. It also needs the orders_replacement permission on your account. The replacement key comes from the remaining pool. The key it replaces is marked superseded: it stays on the order so you can still see what the buyer was given, the customer portal shows it struck through, and delivery emails list only the keys that are still good. There is no “burned” state, and a superseded key does not go back into the pool. If the pool is empty, or the key you owe the buyer is not in Shoppex at all, type the replacement in yourself instead: put one key per line in Replacement Keys in the same dialog. Leave that box empty and the replacement comes from the pool as usual. A hand-typed key is delivered exactly like a pooled one and is marked as entered by hand on the order, so the audit trail says where it came from. It is never counted as stock, because it never was.

Taking a replacement back

Issued the wrong key, or issued one twice? For 30 minutes after issuing it, the delivered keys on the order carry an Undo Replacement button that takes it off the order again. It is refused once the buyer has actually seen the delivery — opened the keys on their order page, or downloaded them — because by then the undo would take back something the buyer already has. What the buyer has read is theirs. A key that came from the pool goes back into the pool, so it sells again. Two exceptions keep their distance from your stock:
  • A key that already went out in an email is removed from the order but not restocked. The email carries it verbatim and cannot be recalled.
  • A hand-typed key is removed and nothing is restocked, because it never came from the pool.
Every undo is recorded on the order next to the replacement it reverses.

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.

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.