API reference
Inventory API
List what a player owns, give them items and consume them from your backend with the server API.
On this page
The inventory is what a player owns: the quantity of each item of your catalog. An item is either consumable (used up, like a potion) or durable (kept, like a sword, often limited to one). This page lists an inventory, grants items for free and consumes them. To sell an item for coins, use Purchases. The examples on this page continue from the setup.
List the inventory
Returns the items a player owns. Use it to show an inventory screen, or to check that a player owns an item before you let them use it.
/players/{player}/inventoryAuthentication: secret key. Idempotency: not needed.
Path parameters
| Parameter | Type | Description |
|---|---|---|
player | string | A GameCoin player id, or ext:<your id> URL-encoded once. |
curl "https://gamecoin.apilow.com/api/v1/players/ext%3Auser-42/inventory" \
-H "Authorization: Bearer $GAMECOIN_SECRET_KEY"const items = await gamecoin.inventory.list(player);
for (const item of items) console.log(item.sku, item.quantity);for item in gamecoin.inventory.list(player):
print(item.sku, item.quantity)foreach ($gamecoin->inventory->list($player) as $item) {
echo $item->sku, ' ', $item->quantity, "\n";
}owned, err := client.Inventory.List(ctx, player)
check(err)
for _, item := range owned {
fmt.Println(item.SKU, item.Quantity)
}foreach (var item in await gamecoin.Inventory.ListAsync(player))
{
Console.WriteLine($"{item.Sku} {item.Quantity}");
}Response 200 OK: the owned items.
| Field | Type | Description |
|---|---|---|
items | array of InventoryItem | The items with a quantity above 0. Empty when the player owns nothing. |
{
"items": [{ "sku": "potion", "quantity": 3, "updatedAt": "2026-10-05T22:14:37.251Z" }]
}Errors
| Status | Code | When | What to do |
|---|---|---|---|
| 400 | VALIDATION_FAILED | The player reference is malformed (PLAYER_REF_INVALID) | Encode the ext: reference exactly once. |
| 404 | NOT_FOUND | The player does not exist | An ext: player exists after its first write; before that, treat the inventory as empty. |
Notes
- The list holds owned items only: an item the player has used up (quantity 0) is not listed. The SDKs return the array of items directly (
inventory.list), without theitemswrapper. skuis the key of the item in your catalog: see Get the catalog for its name, type, price and limit.
Grant an item
Gives items to a player for free: a reward, a gift, a compensation. Nothing is debited. It is for your backend only: the client API can never give an item.
/players/{player}/inventory/grantAuthentication: secret key. Idempotency: required (Idempotency-Key header).
Path parameters
| 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 |
|---|---|---|---|
sku | string | yes | The sku of an active item of the catalog: 1 to 48 characters. |
quantity | integer | no | A whole number from 1 to 1,000,000,000,000. Default 1. |
curl -X POST "https://gamecoin.apilow.com/api/v1/players/ext%3Auser-42/inventory/grant" \
-H "Authorization: Bearer $GAMECOIN_SECRET_KEY" \
-H "Idempotency-Key: grant-potions-user-42" \
-H "Content-Type: application/json" \
-d '{"sku": "potion", "quantity": 3}'const item = await gamecoin.inventory.grant(player, { sku: "potion", quantity: 3 }, { idempotencyKey: "grant-potions-user-42" });
console.log(item.sku, item.quantity, item.replayed);item = gamecoin.inventory.grant(player, sku="potion", quantity=3, idempotency_key="grant-potions-user-42")
print(item.sku, item.quantity, item.replayed)$item = $gamecoin->inventory->grant($player, ['sku' => 'potion', 'quantity' => 3], ['idempotency_key' => 'grant-potions-user-42']);
echo $item->sku, ' ', $item->quantity, ' ', var_export($item->replayed, true), "\n";item, err := client.Inventory.Grant(ctx, player, gamecoin.InventoryParams{SKU: "potion", Quantity: 3},
gamecoin.WithIdempotencyKey("grant-potions-user-42"))
check(err)
fmt.Println(item.SKU, item.Quantity, item.Replayed)var item = await gamecoin.Inventory.GrantAsync(
player,
new InventoryGrantRequest { Sku = "potion", Quantity = 3 },
new RequestOptions { IdempotencyKey = "grant-potions-user-42" });
Console.WriteLine($"{item.Sku} {item.Quantity} {item.Replayed}");Response 200 OK: the item with its new quantity.
| Field | Type | Description |
|---|---|---|
item | InventoryItem | The item and the quantity the player owns after the grant. |
{ "item": { "sku": "potion", "quantity": 3, "updatedAt": "2026-10-05T22:14:37.251Z" } }Errors
| Status | Code | When | What to do |
|---|---|---|---|
| 400 | IDEMPOTENCY_KEY_REQUIRED | The Idempotency-Key header is missing or empty | Send one: see Idempotency. |
| 400 | VALIDATION_FAILED | An unknown field; sku empty or longer than 48 characters; quantity not an integer between 1 and 10¹²; a key that is not 1 to 100 printable ASCII characters | Read details.fieldErrors. |
| 403 | PLAYER_BLOCKED | The player is blocked | Nothing can be written for this player until the player is unblocked. |
| 404 | NOT_FOUND | The item is not in the catalog (or is archived), or a GameCoin id does not exist | Check the sku against Get the catalog. |
| 409 | LIMIT_REACHED | The grant would take the player over the item's maxOwned: details.maxOwned and details.owned | Nothing was granted. Grant less, or nothing: the player already has the item. |
| 409 | IDEMPOTENCY_CONFLICT | The key was already used with a different request | Use a new key for a new grant. |
{
"error": {
"code": "LIMIT_REACHED",
"message": "Item ownership limit exceeded",
"details": { "maxOwned": 1, "owned": 1 }
}
}Notes
- Replay. The same key with the same request returns the original response again, with the header
Idempotent-Replayed: true, and changes nothing. - A grant adds to what the player owns; it never replaces it. Granting 3 potions to a player who owns 2 leaves them with 5.
- A limit is all or nothing: a grant that would pass
maxOwnedis refused entirely, not cut down to fit. For an item withmaxOwned: 1, grant it once. - The SDKs return the inventory item with a
replayedflag (Replayedin Go and C#) that istruewhen the answer is the replay of an earlier request with the same key. - The first write on an unknown
ext:player creates it.
Consume an item
Removes units of a consumable item: the player drinks a potion, you take a ticket. Use it when your game confirms the use of an item, so that the inventory stays the source of truth.
/players/{player}/inventory/consumeAuthentication: secret key. Idempotency: required (Idempotency-Key header).
Path parameters
| Parameter | Type | Description |
|---|---|---|
player | string | A GameCoin player id, or ext:<your id> URL-encoded once. An unknown ext: player is created, with an empty inventory. |
Body
| Field | Type | Required | Rules |
|---|---|---|---|
sku | string | yes | The sku of an active item of the catalog: 1 to 48 characters. |
quantity | integer | no | A whole number from 1 to 1,000,000,000,000. Default 1. |
curl -X POST "https://gamecoin.apilow.com/api/v1/players/ext%3Auser-42/inventory/consume" \
-H "Authorization: Bearer $GAMECOIN_SECRET_KEY" \
-H "Idempotency-Key: use-potion-user-42-1" \
-H "Content-Type: application/json" \
-d '{"sku": "potion"}'const item = await gamecoin.inventory.consume(player, { sku: "potion" }, { idempotencyKey: "use-potion-user-42-1" });
console.log(item.sku, item.quantity, item.replayed);item = gamecoin.inventory.consume(player, sku="potion", idempotency_key="use-potion-user-42-1")
print(item.sku, item.quantity, item.replayed)$item = $gamecoin->inventory->consume($player, ['sku' => 'potion'], ['idempotency_key' => 'use-potion-user-42-1']);
echo $item->sku, ' ', $item->quantity, ' ', var_export($item->replayed, true), "\n";item, err := client.Inventory.Consume(ctx, player, gamecoin.InventoryParams{SKU: "potion"},
gamecoin.WithIdempotencyKey("use-potion-user-42-1"))
check(err)
fmt.Println(item.SKU, item.Quantity, item.Replayed)var item = await gamecoin.Inventory.ConsumeAsync(
player,
new InventoryConsumeRequest { Sku = "potion" },
new RequestOptions { IdempotencyKey = "use-potion-user-42-1" });
Console.WriteLine($"{item.Sku} {item.Quantity} {item.Replayed}");Response 200 OK: the item with its remaining quantity.
| Field | Type | Description |
|---|---|---|
item | InventoryItem | The item and the quantity the player owns after the consumption. It is returned even when the quantity reaches 0. |
{ "item": { "sku": "potion", "quantity": 2, "updatedAt": "2026-10-05T22:14:37.830Z" } }Errors
| Status | Code | When | What to do |
|---|---|---|---|
| 400 | IDEMPOTENCY_KEY_REQUIRED | The Idempotency-Key header is missing or empty | Send one: see Idempotency. |
| 400 | VALIDATION_FAILED | An unknown field; sku empty or longer than 48 characters; quantity not an integer between 1 and 10¹²; a key that is not 1 to 100 printable ASCII characters | Read details.fieldErrors. |
| 403 | PLAYER_BLOCKED | The player is blocked | Nothing can be written for this player until the player is unblocked. |
| 404 | NOT_FOUND | The item is not in the catalog, or a GameCoin id does not exist | Check the sku against Get the catalog. |
| 409 | INSUFFICIENT_FUNDS | The player owns fewer units than quantity: details.required and details.available | Nothing was consumed. Refuse the action in your game. |
| 409 | CONFLICT | The item is durable: a durable item cannot be consumed | Only consume items of type consumable. |
| 409 | IDEMPOTENCY_CONFLICT | The key was already used with a different request | Use a new key for a new consumption. |
{
"error": {
"code": "INSUFFICIENT_FUNDS",
"message": "Not enough items",
"details": { "required": 100, "available": 3 }
}
}Notes
- Replay. The same key with the same request returns the original response again, with the header
Idempotent-Replayed: true, and changes nothing. - Not owning the item at all is the same as owning 0: it answers
INSUFFICIENT_FUNDSwithavailable: 0. The code is the one of the wallet, here applied to a quantity of items. - A consumption is all or nothing: asking for more than the player owns consumes nothing.
- An item that reaches 0 stays out of List the inventory, but its last quantity is in the response so that your game can show it.
- The browser can consume too, with the player's own token: Consume an item in the client API.