# Founder packs

> Sell packs before your game launches, during a window and in limited quantity, and read the stock left from the catalog.

## What you will do

A **founder pack** is an ordinary [pack](/docs/guides/selling-packs) with three extras: a **sale window**, a **total stock**, and a **founder** flag. You use it to sell before your game launches ("the first 500 players get a golden sword"), or to run a limited offer.

When a player buys one, the coins and items are delivered **right away** to the wallet of the player. There is no "pending" currency: the game reads the wallet when it launches, like any other balance. To let a player in a game without a backend keep that wallet, ask for an e-mail first: see [Sign in with e-mail](/docs/guides/player-email-sign-in).

The three options are independent. A pack can have only a window, only a stock, or only the flag. A pack with none of them is always on sale, without limit, as before.

## Set up a founder pack

In the dashboard (in French for now), open your game, then « Packs »:

1. Create or edit a pack. Open the section « Disponibilité et pack fondateur ».
2. Tick « Pack fondateur » to show the founder badge and a public counter.
3. Fill « Début de la vente » and « Fin de la vente » to set the window, and « Stock total » to limit the quantity. Leave a field empty for no limit. Dates are in Paris time.
4. Publish the pack. Each pack in the list shows its state (« Programmé », « En vente », « Épuisé », « Terminé »), the founder badge and the counter « vendus sur stock ».

To announce the launch, open « Réglages » and fill the section « Lancement »: tick « Le jeu n'est pas encore lancé (précommande) » and give the launch date. A shop then shows pre-orders, and the receipts mention the date.

Rules to know:

- The window starts at `startsAt` (included) and ends at `endsAt` (excluded).
- The total stock cannot be set below the number of units already sold.
- The sold counter of the dashboard counts the live environment.

## Read the availability

The [catalog](/docs/api/catalog#get-the-catalog) carries it, for the server and for the browser:

```bash
curl "https://gamecoin.apilow.com/api/v1/client/catalog" \
  -H "X-GameCoin-Key: $GAMECOIN_PUBLISHABLE_KEY"
```

```json title="One pack of the answer"
{
  "sku": "founder-pack",
  "name": "Founder pack",
  "priceCents": 1999,
  "maxPerPlayer": 1,
  "availability": {
    "startsAt": "2026-10-01T00:00:00.000Z",
    "endsAt": "2026-12-01T00:00:00.000Z",
    "remaining": 312,
    "founder": true
  }
}
```

The answer also has `prelaunch` and `launchAt` for the whole game.

- `remaining` is the number of units that can still be bought, or `null` for an unlimited stock. Use it for the public counter: "312 left".
- The catalog also lists packs that are scheduled, ended or sold out. Show them as "coming soon", "ended" or "sold out" instead of hiding them. Compare `startsAt` and `endsAt` with the clock of the player.
- A pack that is not limited has `availability: null`.

## What happens when a player buys

An order for a limited pack **holds one unit of the stock** from the moment it is created. That is how GameCoin never sells more than the stock, even when thousands of players click at the same time.

| Moment | The unit is |
|---|---|
| The order is created (`pending`) | Held for the player, for up to one hour |
| The order is paid and delivered (`fulfilled`) | Sold |
| The order fails, expires or is canceled | Released: someone else can buy it |
| The order is refunded, or the buyer disputes the payment | Given back to the stock |

So `remaining` can go **up** again: when a pending order expires, or when you refund a sale. A second request by the same player for the same pack returns the order that is already pending and holds nothing more.

The window is checked when the order is created. A player who started before the end can still pay after it, within the hour.

## Errors

A checkout for a pack that cannot be sold answers `409`:

| Code | Meaning | What to show |
|---|---|---|
| `PACK_NOT_AVAILABLE` | Outside the window. `details.startsAt` and `details.endsAt` hold the dates. | "Coming soon" with the date, or "Ended" |
| `PACK_SOLD_OUT` | No unit left | "Sold out" |

```json
{ "error": { "code": "PACK_NOT_AVAILABLE", "message": "The pack is not on sale", "details": { "startsAt": "2026-11-01T09:00:00.000Z", "endsAt": null } } }
```

See [Errors](/docs/concepts/errors) for the full list.

## Test it

The test and live environments have **separate stocks**: a purchase made with a test key never uses a unit of the live stock. In the test environment you can run out of stock, wait for the orders to expire, and try the refunds, with simulated payments. See [Testing](/docs/guides/testing).

## Where next

- [Selling packs](/docs/guides/selling-packs): checkouts, VAT and the life of an order.
- [PackAvailability](/docs/api/objects#packavailability): the object in detail.
- [Refunds](/docs/guides/refunds): give a unit back to the stock.
