# User

### [User API](https://docs.idosgames.com/api/api-v2/user) — Configuration & Logic

***

### 1. Overview

The User system provides core account-level operations for every player. It serves as the central hub for managing player data, inventory, virtual currencies, custom preferences, and account lifecycle.

The system supports the following features:

* **Client State** — single-call bootstrap that returns the full player state (profile, inventory, currencies, configuration, characters, quests, premium, etc.)
* **Inventory** — reading the player's items and virtual currency balances
* **Custom User Data** — storing and retrieving arbitrary key-value pairs per player (preferences, tutorial progress, UI state)
* **Currency Transfer** — converting one virtual currency into another based on configured allowed pairs
* **Currency Subtraction** — burning (spending) virtual currency from the player's balance
* **Item Consumption** — consuming/removing items from inventory by instance or by item type
* **Usage Time Tracking** — recording and retrieving player session time statistics
* **Account Deletion** — permanently removing a player's account and all associated data

<https://platform.idosgames.com/TitleID/liveops/user>

***

### 2. Configuration Structure

The User system relies on several sections within the title's `TitlePublicConfiguration`. Unlike the Character system, the User system has fewer dedicated configuration blocks — most of its behavior is determined by virtual currency definitions and inventory catalog settings configured elsewhere.

The key configurable element specific to the User API is:

| Field                          | Type                        | Description                                                     |
| ------------------------------ | --------------------------- | --------------------------------------------------------------- |
| `AllowedCurrencyTransferPairs` | List\<CurrencyTransferPair> | Whitelist of permitted currency-to-currency transfer directions |

***

#### 2.1. Allowed Currency Transfer Pairs

This section defines which virtual currency conversions are permitted via the `TransferVirtualCurrency` action. Each pair specifies a one-way direction — from one currency to another.

| Field            | Type   | Description                     |
| ---------------- | ------ | ------------------------------- |
| `FromCurrencyID` | string | Source virtual currency ID      |
| `ToCurrencyID`   | string | Destination virtual currency ID |

**Key Rules:**

* Transfer direction matters: configuring `DICE → CO` does **not** automatically allow `CO → DICE`. Each direction must be added separately if both are needed.
* System currencies (Coin, CoinLimit, Token, TokenLimit) are **always forbidden** regardless of configuration. The server enforces this hard block.
* The transfer is a 1:1 exchange by amount — the server subtracts `N` from the source and adds `N` to the destination.
* If `AllowedCurrencyTransferPairs` is empty or not configured, all transfer attempts will be rejected.

**How to add:** In the admin panel, enter the `FromCurrencyID` and `ToCurrencyID` for each allowed pair and click **+ Add**.

> 💡 This is useful for games where players can exchange one earned resource for another, such as converting dice/energy tokens into soft currency.
>
> 💡 Or, for example, you can create a "LIMIT" currency that is restored, for example, 10,000 per day, and use it to control the rewards of the "COIN" currency.

***

#### 2.2. Custom User Data

Custom User Data is a key-value store attached to each player. The client can read and write to it freely, with the following constraints:

* **System keys are reserved.** Any key that matches a value in the `SystemCustomUserDataKey` enum will be rejected. These keys are managed by the server internally.
* **Values are stored as strings.** Even if the client sends a number or object, the server serializes `Value` via `.ToString()`.

**Common Use Cases:**

* Tutorial/onboarding progress (`tutorial_step: "5"`)
* Player preferences (`language: "en"`, `music_volume: "0.8"`)
* UI state (`last_tab: "inventory"`, `seen_promo: "true"`)
* Feature flags or A/B test assignments (read-only from server, but client reads via `GetCustomUserData`)

> ⚠️ Do not store sensitive or game-critical data in Custom User Data, as it is client-writable. Use server-side systems (Leaderboards, Characters, Quests) for progression and economy.

***

#### 2.3. Virtual Currencies

Virtual currencies are defined in the title's economy configuration (not in the User-specific config). The User API provides two operations for spending currencies:

**SubtractVirtualCurrency** — directly removes a specified amount from the player's balance. The server checks:

1. `CurrencyID` and `SubtractAmount` are provided
2. Amount meets the minimum threshold (`IGSData.MIN_AMOUNT`)
3. Player has sufficient balance (no negative balances allowed)

**TransferVirtualCurrency** — moves an amount from one currency to another (1:1 ratio). Additional checks:

1. Source and destination currencies are different
2. Neither currency is a system currency
3. The pair is in the `AllowedCurrencyTransferPairs` whitelist
4. Player has sufficient balance in the source currency

> 💡 For purchase-related currency deductions (shop, upgrades, level-ups), use the dedicated systems (Store, Character, etc.) which handle the full transaction atomically. `SubtractVirtualCurrency` is intended for standalone burns (e.g., skipping a timer, unlocking cosmetics via client logic).

***

#### 2.4. Item Consumption

The `ConsumeItem` action allows the client to reduce item quantities in the player's inventory. Two modes are supported:

**By ItemInstanceID:** Targets a specific item instance. Useful when the player selects an exact item from their inventory.

**By ItemID (+ CatalogVersion):** Targets all instances of a given item type and consumes across them. Useful for fungible items like potions or resources where the specific instance doesn't matter.

**Equipped item protection:** An equipped item cannot be reduced to 0 quantity. The player must unequip it first (via the Character system) before fully consuming it.

> ⚠️ `CatalogVersion` defaults to `"Item"` if not provided. Ensure this matches your catalog setup to avoid consuming from the wrong catalog.

***

#### 2.5. Usage Time Tracking

The Usage Time system allows the client to periodically report how long the player has been active, and to retrieve aggregated statistics.

**AddUsageTime** — records a time increment for the current session. Call this periodically (e.g., every 60 seconds) from the client.

**GetUsageTime** — returns aggregated stats broken down by:

| Field          | Type                 | Description                            |
| -------------- | -------------------- | -------------------------------------- |
| `Today`        | int                  | Total usage time for today             |
| `Yesterday`    | int                  | Total usage time for yesterday         |
| `CurrentWeek`  | int                  | Total usage time for the current week  |
| `CurrentMonth` | int                  | Total usage time for the current month |
| `Total`        | long                 | All-time total usage time              |
| `History`      | Dict\<DateTime, int> | Raw daily history (date → time value)  |

> 💡 This data can be used for retention analytics, rewarding active players, or displaying play time in the player's profile.

***

### 3. API Logic

#### 3.1. GetClientState (Bootstrap)

`GetClientState` is the primary entry point when a player opens the game. It returns everything the client needs in a single call:

1. Loads the player's `UserData`
2. Refreshes authentication tokens if they are about to expire
3. Aggregates all player data (inventory, currencies, characters, quests, premium, social, leaderboard data, title configuration, etc.) into a `ClientStateResponse`

#### 3.2. Inventory Access

`GetUserInventory` returns the latest snapshot of the player's inventory, including:

* All owned item instances (with `ItemInstanceId`, `ItemId`, `CatalogVersion`, `RemainingUses`, `IsEquipped` status)
* Virtual currency balances (key-value dictionary of currency IDs to amounts)
* Virtual currency recharge times (if auto-recharge is configured)

#### 3.3. Rate Limiting & Locking

The User API enforces rate limiting and optimistic locking to prevent abuse:

* **Rate limit:** 1 request per 1 second per user

If a request arrives while the user is rate-limited or locked, it will be rejected. This applies to all User actions.

#### 3.4. Account Deletion

`DeleteUserAccount` permanently removes all player data. This action:

* Is irreversible
* Removes the player's database document entirely
* Should be gated behind a client-side confirmation dialog

> ⚠️ Consider implementing a soft-delete or cooldown period in your client UI before calling this endpoint. The server performs immediate permanent deletion.

***

### 4. Step-by-Step Configuration Guide

#### Step 1: Configure Virtual Currencies

Before using the User API's currency operations, ensure your virtual currencies are defined in the title's economy configuration. Common currencies include soft currency (Gold/Coins), hard currency (Gems/Crystals), and special currencies (Energy, Dice, Shards).

#### Step 2: Configure Currency Transfer Pairs (Optional)

If your game needs currency-to-currency conversion:

1. Navigate to the **AllowedCurrencyTransferPairs** section in the admin panel
2. For each permitted conversion, enter the **FromCurrencyID** and **ToCurrencyID**
3. Click **+ Add** for each pair
4. Remember: each pair is one-directional. Add both directions if bidirectional transfer is needed.

**Example pairs:**

| FromCurrencyID | ToCurrencyID | Description                |
| -------------- | ------------ | -------------------------- |
| DICE           | CO           | Convert dice into coins    |
| SH             | CO           | Convert shields into coins |

#### Step 3: Configure Item Catalogs

Ensure your item catalog is set up with the correct `CatalogVersion` (typically `"Item"`). The `ConsumeItem` action will default to this catalog if the client doesn't specify one.

#### Step 4: Save

After completing all settings, click **Save All (server)**. Changes are stored locally until saved to the server. The **Refresh** button allows you to discard local changes and reload current data from the server.

***

### 5. Player Data Structure

The `UserData` is the central storage model for each player. The User API reads from and writes to various fields within this document.

#### Key Fields Relevant to the User API

| Field             | Type                            | Description                                                   |
| ----------------- | ------------------------------- | ------------------------------------------------------------- |
| `UserID`          | string                          | Unique player identifier (database primary key)               |
| `TitleID`         | string                          | Title this player belongs to                                  |
| `Platform`        | string                          | Registration platform                                         |
| `Inventory`       | List\<ItemInstance>             | Player's item instances                                       |
| `VirtualCurrency` | Dict\<string, long>             | Currency balances (CurrencyID → amount)                       |
| `CustomUserData`  | GetCustomUserDataResult         | Key-value custom data store                                   |
| `Characters`      | Dict\<string, CharacterModel>   | Player's characters (see Character API)                       |
| `GameLoops`       | GameLoopsState                  | Board/game loop state                                         |
| `Premium`         | UserPremiumState                | Active premium subscriptions                                  |
| `Quests`          | UserQuestState                  | Quest progress and cycle state                                |
| `Social`          | UserSocialState                 | Friends lists (accepted, incoming, outgoing requests)         |
| `PublicData`      | UserPublicDataModel             | Public profile data (username, country, avatar, level, power) |
| `UsageTime`       | Dict\<DateTime, int>            | Daily usage time history                                      |
| `DailyRewards`    | Dict\<string, DailyRewardState> | Daily reward claim progress per calendar                      |
| `IsBanned`        | bool                            | Whether the player is banned                                  |
| `BanReason`       | string                          | Reason for the ban (if applicable)                            |

#### UserPublicDataModel

Public profile data visible to other players.

| Field       | Type   | Description                       |
| ----------- | ------ | --------------------------------- |
| `Username`  | string | Display name                      |
| `Country`   | string | Player's country                  |
| `AvatarUrl` | string | URL to avatar image               |
| `Vip`       | bool   | Whether the player has VIP status |
| `Level`     | int    | Player level                      |
| `Power`     | long   | Total power rating                |
| `NetWorth`  | long   | Net worth value                   |

***

### 6. API Actions

| Action                    | Description                                                                                              |
| ------------------------- | -------------------------------------------------------------------------------------------------------- |
| `GetClientState`          | Returns the full client state (profile, inventory, config, characters, quests, premium, etc.)            |
| `GetUserInventory`        | Returns the player's items and virtual currency balances                                                 |
| `GetCustomUserData`       | Returns the player's custom key-value data (excluding system keys)                                       |
| `UpdateCustomUserData`    | Sets a single key-value pair in custom data. Requires `Key` and `Value`                                  |
| `TransferVirtualCurrency` | Transfers currency between two types. Requires `FromCurrencyID`, `ToCurrencyID`, `TransferAmount`        |
| `SubtractVirtualCurrency` | Burns currency from the player's balance. Requires `CurrencyID`, `SubtractAmount`                        |
| `ConsumeItem`             | Consumes item uses/quantity. Requires `ItemInstanceID` or `ItemID` (+`CatalogVersion`), `SubtractAmount` |
| `DeleteUserAccount`       | Permanently deletes the player's account                                                                 |
| `GetUsageTime`            | Returns aggregated usage time statistics                                                                 |
| `AddUsageTime`            | Records additional usage time. Requires `UsageTime`                                                      |

***

### 7. Usage Examples

#### Example 1: Casual Game with Soft Currency

* **Currencies:** CO (Coins)
* **AllowedCurrencyTransferPairs:** empty (no conversions needed)
* **Custom User Data:** tutorial progress, sound settings, last level played
* **ConsumeItem:** used for single-use power-ups

#### Example 2: Idle/Tycoon Game with Multiple Currencies

* **Currencies:** CO (Coins), DICE (Dice/Energy), SH (Shields), IG (Gems)
* **AllowedCurrencyTransferPairs:**
  * DICE → CO (convert unused dice to coins)
  * SH → CO (convert shields to coins)
* **SubtractVirtualCurrency:** used for cosmetic purchases managed by client logic
* **Usage Time:** tracked for daily login rewards and session-based bonuses

#### Example 3: RPG with Inventory Management

* **Currencies:** CO (Gold), IG (Crystals)
* **ConsumeItem by ItemInstanceID:** player uses a specific health potion from inventory
* **ConsumeItem by ItemID:** batch-consume crafting materials (e.g., 10 iron ore)
* **Custom User Data:** class selection, keybindings, chat preferences

***

### 8. FAQ

**Q: What is the difference between `GetClientState` and `GetUserInventory`?** A: `GetClientState` returns everything — the full player profile, all configuration, inventory, characters, quests, premium state, etc. It's designed to be called once at app launch. `GetUserInventory` returns only the inventory and currency balances, and is cheaper to call for refreshing after a purchase or action.

**Q: Can the client write any key to Custom User Data?** A: Almost any key. The only restriction is that keys matching the `SystemCustomUserDataKey` enum values are reserved by the server and will be rejected. Use descriptive, prefixed keys (e.g., `ui_theme`, `pref_language`) to avoid collisions.

**Q: Is currency transfer a 1:1 exchange rate?** A: Yes. The server subtracts `TransferAmount` from the source and adds the same `TransferAmount` to the destination. If you need exchange rates (e.g., 10 Dice = 1 Coin), implement the ratio on the client side by adjusting `TransferAmount` accordingly, or use a different mechanism (e.g., Store offers).

**Q: Can I undo `DeleteUserAccount`?** A: No. Account deletion is permanent and irreversible. Always gate this behind a client-side confirmation dialog (ideally with a typed confirmation like "DELETE" to prevent accidental taps).

**Q: What happens if I call `ConsumeItem` on an equipped item?** A: If consuming would reduce the item's quantity to 0, the operation will be rejected. The player must unequip the item first via the Character API's `UnequipItems` action.
