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
POST

/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_here

Request 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_transfer and maximum_transfer for validation
  • Game info: Display game_name and currency_symbol in UI
  • IDs for sending: Use game_id in your existing /initiate-send calls

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 response

C++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 metadata

Migration 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.