Get Player Balance

Retrieve real-time player currency balances using a player ID or email address. Essential for purchase validation, balance displays, and currency management in your game.

By Email Lookup

Most common method for game integration

GET /api/player-balances/player/by-email/{email}

By Player ID

Direct lookup when you have the player ID

GET /api/player-balances/player/{player_id}

Batch Queries

Multiple players in a single request

POST /api/player-balances/batch

Get Balance by Email

GET

Player Balance by Email

https://invo.network/api/player-balances/player/by-email/{email}

🎯 Most Common Method

This is the primary method used by games since email addresses are the standard user identifier. Email addresses are automatically URL-encoded by the API.

Request Headers

X-Game-Secret-Key: your_game_secret_key_here
Content-Type: application/json

⚠️ Use X-Game-Secret-Key header, NOT Authorization Bearer

URL Parameters

email (string, required)

Player's email address - automatically URL encoded

UnityUnity C# Example

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class InvoPlayerBalance : MonoBehaviour
{
    private const string API_BASE = "https://invo.network/api";
    private const string GAME_SECRET_KEY = "your_game_secret_key_here";

    // Corresponds to the full JSON response structure
    [System.Serializable]
    public class PlayerBalanceResponse { /* See full structure in 'Response Structure' section */ }

    public IEnumerator GetPlayerBalanceByEmail(string playerEmail, System.Action<PlayerBalanceResponse> onSuccess, System.Action<string> onError)
    {
        string encodedEmail = UnityWebRequest.EscapeURL(playerEmail);
        string url = 
quot;{API_BASE}/player-balances/player/by-email/{encodedEmail}"; using (UnityWebRequest request = UnityWebRequest.Get(url)) { request.SetRequestHeader("X-Game-Secret-Key", GAME_SECRET_KEY); request.SetRequestHeader("Content-Type", "application/json"); yield return request.SendWebRequest(); if (request.result == UnityWebRequest.Result.Success) { PlayerBalanceResponse response = JsonUtility.FromJson<PlayerBalanceResponse>(request.downloadHandler.text); onSuccess?.Invoke(response); } else { onError?.Invoke(
quot;HTTP Error {request.responseCode}: {request.error}"); } } } }

UnrealUnreal Engine C++ Example

// In your .h file
#include "Http.h"
// ... other includes

USTRUCT(BlueprintType)
struct FPlayerBalanceResponse { /* Add UPROPERTY fields for player, balances, summary */ };

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnBalanceResponse, const FPlayerBalanceResponse&, Response);

// In your component/actor class
public:
    UPROPERTY(BlueprintAssignable)
    FOnBalanceResponse OnBalanceReceived;

    UFUNCTION(BlueprintCallable)
    void GetPlayerBalanceByEmail(const FString& PlayerEmail);

private:
    void OnHttpResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);

// In your .cpp file
void AYourActor::GetPlayerBalanceByEmail(const FString& PlayerEmail)
{
    FHttpModule& HttpModule = FHttpModule::Get();
    TSharedRef<IHttpRequest> Request = HttpModule.CreateRequest();

    FString Url = FString::Printf(TEXT("https://invo.network/api/player-balances/player/by-email/%s"), *FGenericPlatformHttp::UrlEncode(PlayerEmail));

    Request->SetURL(Url);
    Request->SetVerb("GET");
    Request->SetHeader("X-Game-Secret-Key", "your_game_secret_key_here");
    Request->OnProcessRequestComplete().BindUObject(this, &AYourActor::OnHttpResponse);
    Request->ProcessRequest();
}

void AYourActor::OnHttpResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
    if (bWasSuccessful && Response.IsValid() && Response->GetResponseCode() == 200)
    {
        FPlayerBalanceResponse ResponseData;
        FJsonObjectConverter::JsonObjectStringToUStruct(Response->GetContentAsString(), &ResponseData, 0, 0);
        OnBalanceReceived.Broadcast(ResponseData);
    }
    else
    {
        // Handle error
    }
}

GodotGodot GDScript Example

# InvoAPI.gd
extends Node

const API_BASE = "https://invo.network/api"
const GAME_SECRET_KEY = "your_game_secret_key_here"

signal balance_received(success, data)

var http_request = HTTPRequest.new()

func _ready():
    add_child(http_request)
    http_request.request_completed.connect(self._on_request_completed)

func get_player_balance(email: String):
    var encoded_email = email.uri_encode()
    var url = "%s/player-balances/player/by-email/%s" % [API_BASE, encoded_email]
    var headers = [
        "X-Game-Secret-Key: %s" % GAME_SECRET_KEY,
        "Content-Type: application/json"
    ]
    http_request.request(url, headers, HTTPClient.METHOD_GET)

func _on_request_completed(result, response_code, headers, body):
    if response_code == 200:
        var json = JSON.new()
        json.parse(body.get_string_from_utf8())
        balance_received.emit(true, json.get_data())
    else:
        balance_received.emit(false, {"error": response_code})

Response Structure

Both email and ID lookups return the same comprehensive balance structure:

✅ Success Response (200)

{
  "player": {
    "player_id": 12345,
    "player_name": "John Doe",
    "player_email": "john.doe@example.com",
    "date_joined": "2024-01-15T10:30:00Z",
    "last_active": "2024-12-09T12:34:56Z"
  },
  "balances": [
    {
      "currency_id": 1,
      "currency_name": "Gold Coins",
      "currency_symbol": "GC",
      "available_balance": "1500.00",
      "reserved_balance": "50.00",
      "total_balance": "1550.00",
      "last_transaction": "2024-12-09T11:45:30Z"
    }
  ],
  "summary": {
    "total_currencies": 1,
    "total_value_usd": "15.50",
    "has_funds": true,
    "last_updated": "2024-12-09T12:34:56Z"
  }
}

❌ Error Response (404)

{
  "error": "Player not found",
  "message": "No player found with email: invalid@example.com",
  "code": "PLAYER_NOT_FOUND",
  "timestamp": "2024-12-09T12:34:56Z"
}

Batch Balance Queries

POST

Multiple Player Balances

https://invo.network/api/player-balances/batch

🚀 Efficient Bulk Queries

Retrieve balances for up to 100 players in a single API call. Perfect for leaderboards, tournament displays, or analytics dashboards.

Real-world Integration Examples

💰 Purchase Validation

Always validate a player's balance on your server before allowing purchases or transactions to prevent client-side manipulation.

// Server-side Node.js example
async function validatePurchase(playerEmail, itemCost, currencyId) {
    try {
        const balanceData = await getPlayerBalanceByEmail(playerEmail);
        const currency = balanceData.balances.find(b => b.currency_id === currencyId);
        
        if (!currency || parseFloat(currency.available_balance) < itemCost) {
            console.error("Insufficient funds for player:", playerEmail);
            return { success: false, error: "Insufficient funds" };
        }
        
        // If funds are sufficient, proceed with the transaction logic
        // (e.g., call another API to deduct the amount)
        console.log("Validation successful for player:", playerEmail);
        return { success: true, balance: currency.available_balance };

    } catch (error) {
        console.error("Error during purchase validation:", error);
        return { success: false, error: "API error" };
    }
}

📊 In-Game Balance Display

Create a component in your game engine to periodically refresh and display player currencies.

// Unity C# Example for a UI display
public class PlayerBalanceUI : MonoBehaviour {
    public TextMeshProUGUI goldText;
    public TextMeshProUGUI gemsText;
    private InvoPlayerBalance balanceAPI;

    void Start() {
        balanceAPI = gameObject.AddComponent<InvoPlayerBalance>();
        InvokeRepeating(nameof(RefreshBalance), 1f, 30f); // Refresh every 30 seconds
    }

    void RefreshBalance() {
        StartCoroutine(balanceAPI.GetPlayerBalanceByEmail("player@example.com", OnBalanceUpdated, OnError));
    }

    void OnBalanceUpdated(PlayerBalanceResponse response) {
        var gold = response.balances.FirstOrDefault(b => b.currency_name == "Gold Coins");
        if(gold != null) goldText.text = 
quot;Gold: {gold.available_balance}"; var gems = response.balances.FirstOrDefault(b => b.currency_name == "Premium Gems"); if(gems != null) gemsText.text =
quot;Gems: {gems.available_balance}"; } void OnError(string error) { Debug.LogError("Could not refresh balance: " + error); } }

Performance & Caching

Optimization Strategies

Implement these strategies on your server to minimize API calls and improve player experience:

Server-Side Caching

  • • Use Redis or Memcached to cache balance data for 30-60 seconds.
  • • Invalidate the cache immediately after a player completes a transaction.
  • • Serve cached data to reduce latency on repeated requests.

Smart Refresh Patterns

  • • Refresh data from the API only when the cache expires or is invalidated.
  • • Use batch requests for leaderboards instead of individual lookups.
  • • Implement exponential backoff for retries on server errors.

Rate Limits & Error Handling

API Rate Limits

  • Email/ID Lookups: 1,500 requests/minute per game
  • Batch Queries: 100 requests/minute per game
  • • Exceeding limits will result in a 429 error.

Common Error Codes

  • 400 Bad Request: Invalid email format or player ID.
  • 401 Unauthorized: Invalid or missing SDK key.
  • 404 Not Found: The requested player does not exist.
  • 429 Too Many Requests: Rate limit exceeded. Check `Retry-After` header.
  • 500 Internal Server Error: A server-side issue occurred. Retry with backoff.