Currency Send Destinations API
New API endpoint to get available currency send destinations. This supplements your existing currency send system by providing the list of games players can send currency to. No changes to existing APIs.
Addition to Existing System
- • New API:
/api/currency-sends/available-destinations - • Existing APIs unchanged:
/initiate-send,/verify-sms,/claim-currency - • Optional integration: Use to improve UX, not required for sends to work
- • Backward compatible: Your current send implementation continues working
/api/currency-sends/available-destinations
Get games that players can send currency to
Same Authentication
Uses the same authentication as your existing currency send endpoints:
X-Game-Secret-Key: your_game_secret_key_hereRequest Body
{
"source_game_id": "123456789012"
}Response
{
"status": "success",
"available_games": [...],
"total_destinations": 5
}Integration Patterns
Pattern 1: Add to Existing UI (Recommended)
Call this API to populate your existing game selection dropdown. Your current send flow remains unchanged.
Before: Hard-coded game list or manual game ID entry
After: Dynamic game list from API, same send process
Pattern 2: Pre-Send Validation
Use the API response to validate send amounts against min/max limits before calling /initiate-send.
Benefit: Prevent failed sends due to amount limits, better user feedback
Pattern 3: Optional Caching (Performance)
Cache the response for better performance. Call once daily and store locally.
Optional: Only implement if you want instant UI loading
Complete Response Example
{
"status": "success",
"source_game_id": "123456789012",
"source_game_name": "Adventure Quest",
"universal_transfers": "yes",
"transfer_mode": "universal",
"available_games": [
{
"game_id": "123456789012",
"game_name": "Adventure Quest",
"developer_name": "Your Studio",
"genre": "RPG",
"currency_name": "Gold",
"currency_symbol": "G",
"minimum_transfer": "1.00",
"maximum_transfer": null
},
{
"game_id": "987654321098",
"game_name": "Space Warriors",
"developer_name": "Other Studio",
"genre": "Action",
"currency_name": "Energy Credits",
"currency_symbol": "EC",
"minimum_transfer": "5.00",
"maximum_transfer": "1000.00"
}
],
"total_destinations": 2
}Key Points
- • Same game included: Your own game appears for peer-to-peer sends
- • Transfer limits: Use
minimum_transferandmaximum_transferfor validation - • Game info: Display
game_nameandcurrency_symbolin UI - • IDs for sending: Use
game_idin your existing/initiate-sendcalls
Minimal Integration Examples
UnityAdd to Your Existing Unity Code
// Add this new function to your existing currency send system
public IEnumerator GetAvailableDestinations(Action<string> onSuccess, Action<string> onError)
{
string url = "https://invo.network/api/currency-sends/available-destinations";
var requestData = new {
source_game_id = "123456789012" // Your game ID
};
string jsonBody = JsonUtility.ToJson(requestData);
using (UnityWebRequest request = new UnityWebRequest(url, "POST"))
{
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonBody);
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
// Use your existing secret key
request.SetRequestHeader("X-Game-Secret-Key", "your_game_secret_key_here");
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
onSuccess?.Invoke(request.downloadHandler.text);
}
else
{
onError?.Invoke(request.error + ": " + request.downloadHandler.text);
}
}
}
// Your existing InitiateCurrencySend function stays exactly the same!
// Just use the game IDs from the destinations responseC++Add to Your Existing C++ Code
// Add this new function to your existing currency send system
#include <curl/curl.h>
#include <json/json.h>
struct APIResponse {
std::string data;
};
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, APIResponse *response) {
size_t totalSize = size * nmemb;
response->data.append((char*)contents, totalSize);
return totalSize;
}
bool GetAvailableDestinations(const std::string& source_game_id, const std::string& secret_key, std::string& response) {
CURL *curl;
CURLcode res;
APIResponse apiResponse;
curl = curl_easy_init();
if(curl) {
// Set URL
curl_easy_setopt(curl, CURLOPT_URL, "https://invo.network/api/currency-sends/available-destinations");
// Create JSON request body
Json::Value requestData;
requestData["source_game_id"] = source_game_id;
Json::StreamWriterBuilder builder;
std::string jsonString = Json::writeString(builder, requestData);
// Set headers
struct curl_slist *headers = NULL;
std::string authHeader = "X-Game-Secret-Key: " + secret_key;
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, authHeader.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// Set POST data
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonString.c_str());
// Set callback for response
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &apiResponse);
// Perform request
res = curl_easy_perform(curl);
// Cleanup
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
if(res == CURLE_OK) {
response = apiResponse.data;
return true;
}
}
return false;
}
// Usage example:
void PopulateGameDropdown() {
std::string response;
if(GetAvailableDestinations("123456789012", "your_game_secret_key_here", response)) {
Json::Value root;
Json::Reader reader;
if(reader.parse(response, root)) {
const Json::Value& available_games = root["available_games"];
for(const auto& game : available_games) {
std::string game_id = game["game_id"].asString();
std::string game_name = game["game_name"].asString();
std::string currency_symbol = game["currency_symbol"].asString();
// Add to your existing dropdown/UI
AddGameToDropdown(game_id, game_name + " (" + currency_symbol + ")");
}
}
}
}
// Your existing InitiateCurrencySend function stays exactly the same!GodotAdd to Your Existing Godot Code
# Add this new function to your existing currency send system
extends Node
var http_request: HTTPRequest
func _ready():
http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(_on_destinations_response)
func get_available_destinations(source_game_id: String, secret_key: String):
var url = "https://invo.network/api/currency-sends/available-destinations"
var headers = [
"Content-Type: application/json",
"X-Game-Secret-Key: " + secret_key
]
var request_data = {
"source_game_id": source_game_id
}
var json_string = JSON.stringify(request_data)
http_request.request(url, headers, HTTPClient.METHOD_POST, json_string)
func _on_destinations_response(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray):
if response_code == 200:
var json = JSON.new()
var parse_result = json.parse(body.get_string_from_utf8())
if parse_result == OK:
var response_data = json.data
if response_data.status == "success":
populate_game_dropdown(response_data.available_games)
else:
print("API Error: ", response_data.message)
else:
print("JSON Parse Error")
else:
print("HTTP Error: ", response_code)
func populate_game_dropdown(available_games: Array):
var dropdown = get_node("GameDropdown") # Your existing dropdown
dropdown.clear()
for game in available_games:
var game_id = game.game_id
var game_name = game.game_name
var currency_symbol = game.currency_symbol
var display_text = game_name + " (" + currency_symbol + ")"
dropdown.add_item(display_text)
dropdown.set_item_metadata(dropdown.get_item_count() - 1, game_id)
# Usage example:
func _on_refresh_games_pressed():
get_available_destinations("123456789012", "your_game_secret_key_here")
# Your existing initiate_currency_send function stays exactly the same!
# Just use the game IDs from the dropdown metadataMigration Strategy
Phase 1: Add Destinations API (Optional)
- • Add the new destinations endpoint call
- • Use response to populate existing game selection UI
- • Keep all existing send logic unchanged
Phase 2: Add Validation (Optional)
- • Use min/max amounts from destinations response
- • Validate amounts before calling your existing send APIs
- • Provide better user feedback
Phase 3: Add Caching (Optional)
- • Cache destinations response for 24 hours
- • Improve performance by avoiding repeated API calls
- • Add manual refresh option
Benefits of Integration
User Experience
- • Dynamic game list instead of hard-coded options
- • Real-time transfer limits and validation
- • Clear game names and currency info
- • Reduced failed sends due to invalid destinations
Developer Benefits
- • No manual game list maintenance
- • Automatic new game discovery
- • Centralized transfer policy management
- • Better error prevention
Performance
- • Optional caching for instant UI loading
- • Reduced failed API calls
- • Better network efficiency
- • Graceful fallback options
Ecosystem
- • Automatic support for new games
- • Respect for universal vs linked transfer modes
- • Same-game peer-to-peer support
- • Future-proof implementation
Frequently Asked Questions
Do I need to change my existing send APIs?
No. Your existing /initiate-send, /verify-sms, and /claim-currency endpoints work exactly the same. This is just an additional API to get destination information.
Is this API required for sends to work?
No, it's optional. Your current currency sends will continue working. This API just helps improve the user experience by providing dynamic game lists and validation data.
How often should I call this API?
Once per day is sufficient. Game lists don't change frequently. You can cache the response and refresh daily, or call it each time a player opens the send UI (but caching is more efficient).
Will my own game appear in the destinations list?
Yes, your own game appears in the list to support peer-to-peer currency sends within the same game. Use the same receiving_game_id as your source game for same-game sends.
What happens if the destinations API is unavailable?
Your existing send functionality continues working. You can implement fallback logic (cached data, default game list, or manual game ID entry) while the destinations API is unavailable.