# Keys and environments

> The three credentials of GameCoin, where each one may live, and how the test and live environments are kept apart.

## Three credentials

| Credential | Looks like | Sent as | Lives |
|---|---|---|---|
| **Secret key** | `gc_sk_test_…` or `gc_sk_live_…` | `Authorization: Bearer gc_sk_…` | On your server only |
| **Publishable key** | `gc_pk_test_…` or `gc_pk_live_…` | `X-GameCoin-Key: gc_pk_…` | In your game, in the browser. It is safe to be seen. |
| **Player token** | `gc_pt_…` | `Authorization: Bearer gc_pt_…`, next to the publishable key | In the browser, for one hour |

The secret key opens the **server API**: every player, every wallet, every refund of your game. The publishable key opens the **client API** (`/api/v1/client/**`), and only to read the catalog and to create an anonymous player. With a player token added, the client API also lets that one player act for themselves. The exact rights of each are in the [Security model](/docs/concepts/security-model).

Using the wrong kind of key on a route answers `403 FORBIDDEN`:

```json title="A publishable key on a server route"
{ "error": { "code": "FORBIDDEN", "message": "This endpoint requires a secret API key" } }
```

An unknown, revoked or missing key answers `401 UNAUTHENTICATED`.

## What a key decides

A key belongs to one game and one environment. **That is the only thing that picks the game and the environment**: nothing in a path, a header or a body can change them. A body that tries, with a field such as `gameId`, is refused as a `400 VALIDATION_FAILED`: request bodies are strict, and a field GameCoin does not know is an error.

The environment is also written in the key: `test` in `gc_sk_test_…`, `live` in `gc_sk_live_…`. Moving from test to live means changing the key your server reads, and your code stays the same.

## Create and look after keys

Keys are made in the dashboard, which is in French for now: open your game, then « Clés d'API ». Your two **test** keys are created together with the game.

- A secret key is shown **once**, when you create it. GameCoin keeps only a fingerprint of it, so nobody can show it to you again.
- A publishable key stays visible in the dashboard.
- To replace a key, create a new one, deploy it, then revoke the old one. A revoked key stops working at once.
- Archiving a game switches off all its keys.

Keep the secret key out of your code and out of your repository. Read it from an environment variable or a secret manager:

```bash title="A secret key in the environment"
export GAMECOIN_SECRET_KEY="gc_sk_test_…"
```

If a secret key leaks, create another one and revoke the leaked one without waiting. The browser SDK refuses a secret key on its own, so a `gc_sk_…` pasted into game code fails at startup, which is better than shipping it.

## Test and live

| | `test` | `live` |
|---|---|---|
| Who can use it | Every studio | Studios verified by Apilow only |
| Payments | **Simulated**: the payment page offers "pay" and "decline" and no money moves | Real payments |
| Data | Disposable | Your real players |
| Keys | Created with the game | Created after verification |

The **catalog** (currencies, items, packs) is shared by the two environments: you define it once. **Players, balances, the ledger, the inventory and orders are separate** in each. A player of `test` does not exist in `live`, and a balance never crosses over.

A studio that is not verified cannot create live keys. A live key presented by an unverified studio answers `403 ENV_NOT_ENABLED`.

> [!NOTE]
> The test environment is the only one you can use today. Real payments are not available yet, so `live` is not open. Because the key picks the environment, what you build now needs no change when `live` opens.

In the dashboard, a switch at the top of the Players and Orders pages (« Environnement ») chooses which environment you are looking at.

## Where next

- [Players and tokens](/docs/concepts/players-and-tokens): how a browser gets a token.
- [Testing](/docs/guides/testing): what to try in the test environment.
