API reference
Codes API
Let a player redeem a gift code for free coins and items, with the server API or the client API, and read the creator code of an order.
On this page
A gift code is a code that your studio creates in the dashboard (« Codes », in French for now) and hands out: at a convention, in a contest, to a partner. A player who types it receives free coins (the bonus bucket) and items, once. A creator code is different: the buyer types it at checkout, and it is covered in Checkouts and in the guide. The examples on this page continue from the setup.
Redeem a gift code
Credits the free coins and items of a gift code to a player. A code works once per player and up to its own limit of uses. The coins are always free: a code never gives paid coins, and it cannot be passed from one player to another.
/players/{player}/codes/redeemAuthentication: secret key. Idempotency: required (Idempotency-Key header). Limit: 10 attempts per 15 minutes per player.
/client/me/codes/redeemAuthentication: publishable key and player token. Idempotency: required. CORS: open. Limit: 10 attempts per 15 minutes per player and 30 per IP address. This is the only client route that adds coins, and only free ones, from a code that your studio issued.
Path parameters (server route)
| Parameter | Type | Description |
|---|---|---|
player | string | A GameCoin player id, or ext:<your id> URL-encoded once. An unknown ext: player is created. |
Body
| Field | Type | Required | Rules |
|---|---|---|---|
code | string | yes | The code as the player types it: 1 to 64 characters. Upper or lower case, spaces and dashes are ignored, so summer-k7m2q-xh4np and SUMMERK7M2QXH4NP are the same code. |
curl -X POST "https://gamecoin.apilow.com/api/v1/players/ext%3Auser-42/codes/redeem" \
-H "Authorization: Bearer $GAMECOIN_SECRET_KEY" \
-H "Idempotency-Key: redeem-user-42-summer" \
-H "Content-Type: application/json" \
-d '{"code": "SUMMER-K7M2Q-XH4NP"}'From a browser, with the publishable key and the token of the player:
const response = await fetch("https://gamecoin.apilow.com/api/v1/client/me/codes/redeem", {
method: "POST",
headers: {
"X-GameCoin-Key": publishableKey,
Authorization: `Bearer ${playerToken}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({ code: typedByThePlayer }),
});
if (response.status === 400) showMessage("This code is not valid."); // unknown, expired, used up, disabled or already usedResponse 200 OK.
| Field | Type | Description |
|---|---|---|
grants | array | One line per currency credited: currency, amount (always added to the bonus bucket) and the balance afterwards (Balance). |
items | array | The items added to the inventory: sku and quantity. |
skipped | array | The items the player could not receive, because they already own the most they can of a durable item. The rest of the code is still given. |
{
"grants": [{ "currency": "gems", "amount": 100, "balance": { "currency": "gems", "paid": 0, "bonus": 100, "total": 100 } }],
"items": [{ "sku": "potion", "quantity": 2 }],
"skipped": []
}Send the same request again with the same key and you get the same answer with Idempotent-Replayed: true, and nothing is credited twice. The ledger entry has the type gift_code, and its metadata.code is the code.
Errors
| Status | Code | When | What to do |
|---|---|---|---|
| 400 | VALIDATION_FAILED | details.fieldErrors.code is ["CODE_INVALID"]: the code is unknown, malformed, expired, used up, disabled, already used by this player, or not a gift code | Tell the player the code is not valid. Nothing says which of these it is. |
| 400 | VALIDATION_FAILED | An unknown field, or code missing or too long | Read details.fieldErrors. |
| 400 | IDEMPOTENCY_KEY_REQUIRED | The Idempotency-Key header is missing or empty | Send one. |
| 401 | UNAUTHENTICATED | Client route: the player token is missing or expired | Ask for a new token. |
| 403 | PLAYER_BLOCKED | The player is blocked | Nothing can be redeemed for this player until they are unblocked. |
| 404 | NOT_FOUND | A GameCoin player id that does not exist | Check the id. |
| 409 | LIMIT_REACHED | The player already owns the most they can of every item of the code, and the code gives nothing else. The code is not used up | Tell the player they already have this reward. |
| 409 | CONFLICT | The currencies and items of the code were archived since it was created. The code is not used up | Contact the studio of the game. |
| 409 | IDEMPOTENCY_CONFLICT | The key was already used with a different code | Use a new key for a new redemption. |
| 429 | RATE_LIMITED | Too many attempts, valid or not: Retry-After gives the seconds to wait | Slow down. |
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Invalid or expired code",
"details": { "fieldErrors": { "code": ["CODE_INVALID"] } }
}
}Notes
- Every refusal looks the same. An answer that told "expired" from "unknown" would let anyone find real codes by trying. Codes have ten random characters from an alphabet without look-alikes (no
0,O,1,IorL), and the attempts are limited, so guessing a code is not realistic. Do not try to tell the cases apart in your game: show one friendly message. - The attempts are counted whether the code is right or wrong. A player who types 10 wrong codes must wait for the next quarter of an hour; the server route has no limit per IP address, because the address would be your backend's.
- A code redeemed through the server API for an unknown
ext:player creates that player, like the otherPOSTroutes. - A creator code is not a gift code: typing one here gives the same
CODE_INVALID. - The server API and the client API do the same thing. Use the client route when the player types the code in a game without a backend; use the server route when your backend checks the player first.