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/batchGet Balance by Email
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
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
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
429error.
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.