Skip to content
Skip the menu

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.

View as Markdown

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.

POST/players/{player}/codes/redeem

Authentication: secret key. Idempotency: required (Idempotency-Key header). Limit: 10 attempts per 15 minutes per player.

POST/client/me/codes/redeem

Authentication: 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)

ParameterTypeDescription
playerstringA GameCoin player id, or ext:<your id> URL-encoded once. An unknown ext: player is created.

Body

FieldTypeRequiredRules
codestringyesThe 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.
Bash
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:

JavaScript
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 used

Response 200 OK.

FieldTypeDescription
grantsarrayOne line per currency credited: currency, amount (always added to the bonus bucket) and the balance afterwards (Balance).
itemsarrayThe items added to the inventory: sku and quantity.
skippedarrayThe 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.
JSON
{
  "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

StatusCodeWhenWhat to do
400VALIDATION_FAILEDdetails.fieldErrors.code is ["CODE_INVALID"]: the code is unknown, malformed, expired, used up, disabled, already used by this player, or not a gift codeTell the player the code is not valid. Nothing says which of these it is.
400VALIDATION_FAILEDAn unknown field, or code missing or too longRead details.fieldErrors.
400IDEMPOTENCY_KEY_REQUIREDThe Idempotency-Key header is missing or emptySend one.
401UNAUTHENTICATEDClient route: the player token is missing or expiredAsk for a new token.
403PLAYER_BLOCKEDThe player is blockedNothing can be redeemed for this player until they are unblocked.
404NOT_FOUNDA GameCoin player id that does not existCheck the id.
409LIMIT_REACHEDThe player already owns the most they can of every item of the code, and the code gives nothing else. The code is not used upTell the player they already have this reward.
409CONFLICTThe currencies and items of the code were archived since it was created. The code is not used upContact the studio of the game.
409IDEMPOTENCY_CONFLICTThe key was already used with a different codeUse a new key for a new redemption.
429RATE_LIMITEDToo many attempts, valid or not: Retry-After gives the seconds to waitSlow down.
JSON
{
  "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, I or L), 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 other POST routes.
  • 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.