🔧 Architettura Universale

Tutte le piattaforme si connettono al backend Joomla di ZoneCoin tramite un unico gateway API REST.

Platform SDKs
🌐OpenSimC# .NET
🔵Second LifeLSL
UnityC#
🔷UnrealC++
🔹GodotGDScript
🟫MinecraftJava
🔴RobloxLuau
🟣VRChatUdonSharp
🏙️DecentralandTypeScript
🏖️The SandboxTypeScript
API Gateway
REST API (HTTPS + HMAC-SHA256) /api/index.php/v1/zonecoin/*
Core Engine
Joomla + ZoneCoin Component Wallets · Ledger · Exchange · NFTs · Staking · Governance

⚡ Avvio Rapido

Quattro passaggi per integrare ZoneCoin in qualsiasi piattaforma.

1
Registra il Grid
Registrati e registra il tuo grid/server per ricevere le credenziali API.
2
Ottieni le Chiavi API
Genera la tua chiave API, il secret e l'ID merchant dalla dashboard.
3
Installa l'SDK
Scarica l'SDK o il modulo DLL per la piattaforma di destinazione.
4
Vai Live
Testa in sandbox, poi passa a produzione — sei pronto!

🌐 OpenSimulator

ZoneCoin fornisce un modulo nativo C# .NET che si integra direttamente in qualsiasi griglia OpenSimulator, abilitando gestione wallet in tempo reale, trasferimenti tra avatar, acquisto terreni e transazioni marketplace — tutto verificato tramite la blockchain PoA ZoneCoin.

💰
Interrogazione SaldoSaldo wallet in tempo reale via REST API con supporto multi-valuta.
🔄
Trasferimento P2PTrasferimenti istantanei tra avatar con verifica crittografica.
🏠
Pagamento TerreniAcquisto e affitto terreni automatizzato con supporto escrow.
🛒
MarketplaceAcquisto oggetti in-world con settlement merchant e ricevute.

📥 Scarica Modulo OpenSim (DLL)

🔵 Second Life

Integra ZoneCoin in Second Life usando script LSL. Crea terminali di pagamento, verificatori di saldo e vendor automatici connessi alle API REST ZoneCoin tramite richieste HTTP.

Terminale di Pagamento

LSL// ZoneCoin Payment Terminal — Second Life // Drop this script into any prim to create a payment terminal string API_URL = "https://zonecoin.zonenations.com/api/index.php/v1/zonecoin"; string API_KEY = "YOUR_API_KEY"; string MERCHANT = "your-merchant-id"; key httpReq; default { state_entry() { llSetText("ZoneCoin Payment Terminal\nTouch to pay", <0.4, 0.9, 1.0>, 1.0); llSetTimerEvent(300.0); // Heartbeat every 5 min } touch_start(integer n) { key buyer = llDetectedKey(0); string name = llDetectedName(0); llTextBox(buyer, "Enter amount in ZC:", 1); } listen(integer ch, string name, key id, string msg) { float amount = (float)msg; if (amount <= 0) { llInstantMessage(id, "Invalid amount."); return; } string body = llList2Json(JSON_OBJECT, [ "action", "pay", "amount", (string)amount, "ref", "SL-" + (string)llGetUnixTime(), "buyer", (string)id, "merchant", MERCHANT ]); httpReq = llHTTPRequest(API_URL + "/pay", [ HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/json", HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + API_KEY, HTTP_CUSTOM_HEADER, "X-ZoneCoin-Timestamp", (string)llGetUnixTime() ], body); } http_response(key req, integer status, list meta, string body) { if (req != httpReq) return; if (status == 200) { string txId = llJsonGetValue(body, ["txId"]); llSay(0, "✅ Payment confirmed! TX: " + txId); } else { llSay(0, "❌ Payment failed: " + body); } } timer() { llHTTPRequest(API_URL + "/heartbeat", [ HTTP_METHOD, "GET", HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + API_KEY ], ""); } }

Verifica Saldo

LSL// ZoneCoin Balance Checker — Second Life // Touch to check your ZoneCoin wallet balance string API_URL = "https://zonecoin.zonenations.com/api/index.php/v1/zonecoin"; string API_KEY = "YOUR_API_KEY"; key httpReq; key requester; default { state_entry() { llSetText("ZoneCoin Balance\nTouch to check", <0.2, 0.8, 0.6>, 1.0); } touch_start(integer n) { requester = llDetectedKey(0); httpReq = llHTTPRequest(API_URL + "/balance/" + (string)requester, [ HTTP_METHOD, "GET", HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + API_KEY ], ""); } http_response(key req, integer status, list meta, string body) { if (req != httpReq) return; if (status == 200) { string bal = llJsonGetValue(body, ["balance"]); string cur = llJsonGetValue(body, ["currency"]); llInstantMessage(requester, "💰 Your ZoneCoin balance: " + bal + " " + cur); } else { llInstantMessage(requester, "❌ Could not retrieve balance."); } } }

⬛ Unity

L'SDK Unity di ZoneCoin fornisce un singleton basato su MonoBehaviour con supporto completo async/coroutine. Gestisci pagamenti, query saldo e trasferimenti peer con firma automatica HMAC-SHA256.

ZoneCoinSDK.cs

C#using System; using System.Collections; using System.Security.Cryptography; using System.Text; using UnityEngine; using UnityEngine.Networking; namespace ZoneCoin.SDK { /// <summary> /// ZoneCoin SDK for Unity — handles payments, balance queries /// and webhook verification via the ZoneCoin REST API. /// </summary> public class ZoneCoinSDK : MonoBehaviour { [Header("Configuration")] [SerializeField] private string apiUrl = "https://zonecoin.zonenations.com/api/index.php/v1/zonecoin"; [SerializeField] private string apiKey = ""; [SerializeField] private string secret = ""; [SerializeField] private string merchant = ""; public static ZoneCoinSDK Instance { get; private set; } private void Awake() { if (Instance != null) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); } // ── Balance ─────────────────────────────────────────── public void GetBalance(string wallet, Action<decimal> onSuccess, Action<string> onError = null) { StartCoroutine(GetRequest($"{apiUrl}/balance/{wallet}", json => { var balance = decimal.Parse(JsonUtility.FromJson<BalanceResponse>(json).balance); onSuccess?.Invoke(balance); }, onError)); } // ── Pay ─────────────────────────────────────────────── public void Pay(decimal amount, string reference, bool isFiat, Action<PayResult> onSuccess, Action<string> onError = null) { var body = JsonUtility.ToJson(new PayRequest { amount = amount.ToString("F2"), ref_id = reference, merchant = merchant, isFiat = isFiat }); StartCoroutine(PostRequest($"{apiUrl}/pay", body, json => { onSuccess?.Invoke(JsonUtility.FromJson<PayResult>(json)); }, onError)); } // ── Transfer ────────────────────────────────────────── public void Transfer(string toWallet, decimal amount, Action<string> onSuccess, Action<string> onError = null) { var body = JsonUtility.ToJson(new TransferRequest { to = toWallet, amount = amount.ToString("F2") }); StartCoroutine(PostRequest($"{apiUrl}/transfer", body, json => { onSuccess?.Invoke(JsonUtility.FromJson<TxResponse>(json).txId); }, onError)); } // ── HMAC Signing ────────────────────────────────────── private string Sign(string timestamp, string nonce, string body) { var payload = timestamp + nonce + body; using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)); var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload)); return BitConverter.ToString(hash).Replace("-", "").ToLower(); } // ── HTTP Helpers ────────────────────────────────────── private IEnumerator GetRequest(string url, Action<string> onOk, Action<string> onErr) { using var req = UnityWebRequest.Get(url); AddHeaders(req, ""); yield return req.SendWebRequest(); if (req.result == UnityWebRequest.Result.Success) onOk(req.downloadHandler.text); else onErr?.Invoke(req.error); } private IEnumerator PostRequest(string url, string json, Action<string> onOk, Action<string> onErr) { using var req = new UnityWebRequest(url, "POST"); req.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json)); req.downloadHandler = new DownloadHandlerBuffer(); req.SetRequestHeader("Content-Type", "application/json"); AddHeaders(req, json); yield return req.SendWebRequest(); if (req.result == UnityWebRequest.Result.Success) onOk(req.downloadHandler.text); else onErr?.Invoke(req.error); } private void AddHeaders(UnityWebRequest req, string body) { var ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); var nonce = Guid.NewGuid().ToString("N").Substring(0, 12); req.SetRequestHeader("Authorization", "Bearer " + apiKey); req.SetRequestHeader("X-ZoneCoin-Timestamp", ts); req.SetRequestHeader("X-ZoneCoin-Nonce", nonce); req.SetRequestHeader("X-ZoneCoin-Signature", Sign(ts, nonce, body)); } // ── DTOs ────────────────────────────────────────────── [Serializable] public class BalanceResponse { public string balance; public string currency; } [Serializable] public class PayRequest { public string amount, ref_id, merchant; public bool isFiat; } [Serializable] public class PayResult { public string txId; public string amount; } [Serializable] public class TransferRequest { public string to, amount; } [Serializable] public class TxResponse { public string txId; } } }

Esempio d'Uso

C#// Example: In-game shop purchase using ZoneCoin.SDK; public class ShopUI : MonoBehaviour { public void OnBuyItem(string itemId, decimal price) { ZoneCoinSDK.Instance.Pay(price, $"GAME-{itemId}", isFiat: false, onSuccess: result => { Debug.Log($"Payment OK! TX: {result.txId}"); InventoryManager.Instance.AddItem(itemId); UIManager.Instance.ShowToast("Purchase complete! ⚡"); }, onError: err => { Debug.LogError($"Payment failed: {err}"); UIManager.Instance.ShowToast("Payment failed. Try again."); } ); } }

🔷 Unreal Engine

L'integrazione Unreal Engine usa un GameInstanceSubsystem che espone funzioni BlueprintCallable per pagamenti, query saldo e trasferimenti. Tutte le richieste sono firmate HMAC e processate asincronamente.

ZoneCoinSubsystem.h

C++#pragma once #include "CoreMinimal.h" #include "Subsystems/GameInstanceSubsystem.h" #include "Http.h" #include "ZoneCoinSubsystem.generated.h" DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnZCPayResult, bool, bSuccess, const FString&, TxId); DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnZCBalance, bool, bSuccess, float, Balance); UCLASS() class YOURPROJECT_API UZoneCoinSubsystem : public UGameInstanceSubsystem { GENERATED_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ZoneCoin") FString ApiUrl = TEXT("https://zonecoin.zonenations.com/api/index.php/v1/zonecoin"); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ZoneCoin") FString ApiKey; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ZoneCoin") FString Secret; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ZoneCoin") FString MerchantId; UFUNCTION(BlueprintCallable, Category = "ZoneCoin") void Pay(float Amount, const FString& Reference, bool bIsFiat, FOnZCPayResult OnResult); UFUNCTION(BlueprintCallable, Category = "ZoneCoin") void GetBalance(const FString& Wallet, FOnZCBalance OnResult); UFUNCTION(BlueprintCallable, Category = "ZoneCoin") void Transfer(const FString& ToWallet, float Amount, FOnZCPayResult OnResult); private: TSharedRef<IHttpRequest> CreateRequest(const FString& Verb, const FString& Endpoint, const FString& Body = TEXT("")); FString SignRequest(const FString& Timestamp, const FString& Nonce, const FString& Body); };

ZoneCoinSubsystem.cpp

C++#include "ZoneCoinSubsystem.h" #include "Serialization/JsonSerializer.h" #include "Misc/SecureHash.h" void UZoneCoinSubsystem::Pay(float Amount, const FString& Reference, bool bIsFiat, FOnZCPayResult OnResult) { TSharedPtr<FJsonObject> Json = MakeShareable(new FJsonObject); Json->SetNumberField(TEXT("amount"), Amount); Json->SetStringField(TEXT("ref"), Reference); Json->SetStringField(TEXT("merchant"), MerchantId); Json->SetBoolField(TEXT("isFiat"), bIsFiat); FString Body; auto Writer = TJsonWriterFactory<>::Create(&Body); FJsonSerializer::Serialize(Json.ToSharedRef(), Writer); auto Request = CreateRequest(TEXT("POST"), TEXT("/pay"), Body); Request->OnProcessRequestComplete().BindLambda( [OnResult](FHttpRequestPtr Req, FHttpResponsePtr Res, bool bOk) { if (bOk && Res->GetResponseCode() == 200) { TSharedPtr<FJsonObject> R; auto Reader = TJsonReaderFactory<>::Create(Res->GetContentAsString()); FJsonSerializer::Deserialize(Reader, R); OnResult.ExecuteIfBound(true, R->GetStringField(TEXT("txId"))); } else { OnResult.ExecuteIfBound(false, TEXT("")); } }); Request->ProcessRequest(); } void UZoneCoinSubsystem::GetBalance(const FString& Wallet, FOnZCBalance OnResult) { auto Request = CreateRequest(TEXT("GET"), FString::Printf(TEXT("/balance/%s"), *Wallet)); Request->OnProcessRequestComplete().BindLambda( [OnResult](FHttpRequestPtr Req, FHttpResponsePtr Res, bool bOk) { if (bOk && Res->GetResponseCode() == 200) { TSharedPtr<FJsonObject> R; auto Reader = TJsonReaderFactory<>::Create(Res->GetContentAsString()); FJsonSerializer::Deserialize(Reader, R); OnResult.ExecuteIfBound(true, R->GetNumberField(TEXT("balance"))); } else { OnResult.ExecuteIfBound(false, 0.f); } }); Request->ProcessRequest(); }

🔹 Godot

L'SDK ZoneCoin per Godot 4 e' un singleton autoload GDScript che usa segnali per la comunicazione asincrona. Supporta pagamenti, query saldo e trasferimenti con firma HMAC-SHA256 integrata tramite HMACContext.

zonecoin_sdk.gd

GDScriptextends Node class_name ZoneCoinSDK ## ZoneCoin SDK for Godot 4 — REST API integration ## Add this as an autoload singleton: Project → Settings → Autoload @export var api_url : String = "https://zonecoin.zonenations.com/api/index.php/v1/zonecoin" @export var api_key : String = "" @export var secret : String = "" @export var merchant : String = "" signal payment_completed(tx_id: String, amount: float) signal payment_failed(error: String) signal balance_received(balance: float, currency: String) var _http : HTTPRequest func _ready(): _http = HTTPRequest.new() add_child(_http) # ── Pay ──────────────────────────────────────────────────── func pay(amount: float, reference: String, is_fiat: bool = false) -> void: var body = JSON.stringify({ "amount": amount, "ref": reference, "merchant": merchant, "isFiat": is_fiat }) var headers = _build_headers(body) _http.request_completed.connect(_on_pay_response, CONNECT_ONE_SHOT) _http.request(api_url + "/pay", headers, HTTPClient.METHOD_POST, body) func _on_pay_response(result, code, headers, body): var json = JSON.parse_string(body.get_string_from_utf8()) if code == 200: payment_completed.emit(json.txId, float(json.amount)) else: payment_failed.emit(json.get("error", "Unknown error")) # ── Balance ──────────────────────────────────────────────── func get_balance(wallet: String) -> void: var headers = _build_headers("") _http.request_completed.connect(_on_balance_response, CONNECT_ONE_SHOT) _http.request(api_url + "/balance/" + wallet, headers, HTTPClient.METHOD_GET) func _on_balance_response(result, code, headers, body): var json = JSON.parse_string(body.get_string_from_utf8()) if code == 200: balance_received.emit(float(json.balance), json.currency) # ── Transfer ─────────────────────────────────────────────── func transfer(to_wallet: String, amount: float) -> void: var body = JSON.stringify({"to": to_wallet, "amount": amount}) var headers = _build_headers(body) _http.request(api_url + "/transfer", headers, HTTPClient.METHOD_POST, body) # ── HMAC Signing ─────────────────────────────────────────── func _build_headers(body: String) -> PackedStringArray: var ts = str(int(Time.get_unix_time_from_system())) var nonce = _rand_hex(12) var sig = _hmac_sha256(ts + nonce + body) return PackedStringArray([ "Content-Type: application/json", "Authorization: Bearer " + api_key, "X-ZoneCoin-Timestamp: " + ts, "X-ZoneCoin-Nonce: " + nonce, "X-ZoneCoin-Signature: " + sig ]) func _hmac_sha256(message: String) -> String: var ctx = HMACContext.new() ctx.start(HashingContext.HASH_SHA256, secret.to_utf8_buffer()) ctx.update(message.to_utf8_buffer()) return ctx.finish().hex_encode() func _rand_hex(length: int) -> String: var bytes = Crypto.new().generate_random_bytes(length) return bytes.hex_encode().substr(0, length)

🟫 Minecraft

Il plugin ZoneCoin per Minecraft si integra con server Spigot e Paper. I giocatori usano /zcbalance e /zcpay per gestire i wallet. Supporta chiamate HTTP asincrone e autenticazione HMAC.

plugin.yml

YAMLname: ZoneCoinPlugin version: 1.0.0 main: com.zonenations.zonecoin.ZoneCoinPlugin api-version: '1.20' description: ZoneCoin virtual currency for Minecraft servers authors: [ZoneNations] commands: zcbalance: description: Check your ZoneCoin balance usage: /zcbalance permission: zonecoin.balance zcpay: description: Send ZoneCoin to a player usage: /zcpay <player> <amount> permission: zonecoin.pay zcshop: description: Open the ZoneCoin shop usage: /zcshop permission: zonecoin.shop permissions: zonecoin.balance: default: true zonecoin.pay: default: true zonecoin.shop: default: true zonecoin.admin: default: op

ZoneCoinPlugin.java

Javapackage com.zonenations.zonecoin; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.command.*; import org.bukkit.entity.Player; import com.google.gson.*; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.net.http.*; import java.net.URI; import java.time.Instant; import java.util.UUID; public class ZoneCoinPlugin extends JavaPlugin { private String apiUrl, apiKey, secret, merchant; private final HttpClient http = HttpClient.newHttpClient(); private final Gson gson = new Gson(); @Override public void onEnable() { saveDefaultConfig(); apiUrl = getConfig().getString("api-url", "https://zonecoin.zonenations.com/api/index.php/v1/zonecoin"); apiKey = getConfig().getString("api-key", ""); secret = getConfig().getString("secret", ""); merchant = getConfig().getString("merchant", ""); getCommand("zcbalance").setExecutor(this::onBalance); getCommand("zcpay").setExecutor(this::onPay); getLogger().info("ZoneCoin plugin enabled ⚡"); } private boolean onBalance(CommandSender s, Command c, String l, String[] a) { if (!(s instanceof Player p)) { s.sendMessage("§cPlayers only."); return true; } getServer().getScheduler().runTaskAsynchronously(this, () -> { try { var res = apiGet("/balance/" + p.getUniqueId()); var json = JsonParser.parseString(res).getAsJsonObject(); var bal = json.get("balance").getAsString(); p.sendMessage("§6§l💰 ZoneCoin Balance: §f" + bal + " ZC"); } catch (Exception e) { p.sendMessage("§c❌ Could not retrieve balance."); getLogger().warning("Balance error: " + e.getMessage()); } }); return true; } private boolean onPay(CommandSender s, Command c, String l, String[] a) { if (!(s instanceof Player p)) return false; if (a.length < 2) { p.sendMessage("§cUsage: /zcpay <player> <amount>"); return true; } Player target = getServer().getPlayer(a[0]); if (target == null) { p.sendMessage("§cPlayer not found."); return true; } double amount; try { amount = Double.parseDouble(a[1]); } catch (Exception e) { p.sendMessage("§cInvalid amount."); return true; } getServer().getScheduler().runTaskAsynchronously(this, () -> { try { var body = gson.toJson(new PayReq(amount, "MC-" + UUID.randomUUID().toString().substring(0, 8), p.getUniqueId().toString(), target.getUniqueId().toString())); var res = apiPost("/transfer", body); var txId = JsonParser.parseString(res).getAsJsonObject().get("txId").getAsString(); p.sendMessage("§a§l✅ Sent " + amount + " ZC to " + target.getName() + " (TX: " + txId + ")"); target.sendMessage("§a§l💰 Received " + amount + " ZC from " + p.getName()); } catch (Exception e) { p.sendMessage("§c❌ Transfer failed: " + e.getMessage()); } }); return true; } // ── HTTP Helpers with HMAC ───────────────────────────────── private String apiGet(String endpoint) throws Exception { var ts = String.valueOf(Instant.now().getEpochSecond()); var nonce = UUID.randomUUID().toString().substring(0, 12); var sig = hmacSha256(ts + nonce); var req = HttpRequest.newBuilder(URI.create(apiUrl + endpoint)) .header("Authorization", "Bearer " + apiKey) .header("X-ZoneCoin-Timestamp", ts) .header("X-ZoneCoin-Nonce", nonce) .header("X-ZoneCoin-Signature", sig) .GET().build(); return http.send(req, HttpResponse.BodyHandlers.ofString()).body(); } private String apiPost(String endpoint, String body) throws Exception { var ts = String.valueOf(Instant.now().getEpochSecond()); var nonce = UUID.randomUUID().toString().substring(0, 12); var sig = hmacSha256(ts + nonce + body); var req = HttpRequest.newBuilder(URI.create(apiUrl + endpoint)) .header("Authorization", "Bearer " + apiKey) .header("Content-Type", "application/json") .header("X-ZoneCoin-Timestamp", ts) .header("X-ZoneCoin-Nonce", nonce) .header("X-ZoneCoin-Signature", sig) .POST(HttpRequest.BodyPublishers.ofString(body)).build(); return http.send(req, HttpResponse.BodyHandlers.ofString()).body(); } private String hmacSha256(String data) throws Exception { var mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes(), "HmacSHA256")); var hex = new StringBuilder(); for (byte b : mac.doFinal(data.getBytes())) hex.append(String.format("%02x", b)); return hex.toString(); } record PayReq(double amount, String ref, String from, String to) {} }

🔴 Roblox

L'SDK ZoneCoin per Roblox e' un ModuleScript lato server che usa HttpService per la comunicazione API. Supporta query saldo, pagamenti e trasferimenti peer con gestione errori pcall.

ZoneCoinSDK (ModuleScript)

Luau-- ZoneCoin SDK for Roblox — Server-side ModuleScript -- Place in ServerScriptService/ZoneCoinSDK local HttpService = game:GetService("HttpService") local ZoneCoin = {} ZoneCoin.__index = ZoneCoin local API_URL = "https://zonecoin.zonenations.com/api/index.php/v1/zonecoin" local API_KEY = "" -- Set in config local SECRET = "" local MERCHANT = "" function ZoneCoin.Init(config) API_URL = config.apiUrl or API_URL API_KEY = config.apiKey or API_KEY SECRET = config.secret or SECRET MERCHANT = config.merchant or MERCHANT end function ZoneCoin.GetBalance(playerId) local ok, res = pcall(function() return HttpService:RequestAsync({ Url = API_URL .. "/balance/" .. tostring(playerId), Method = "GET", Headers = ZoneCoin._Headers("") }) end) if ok and res.StatusCode == 200 then local data = HttpService:JSONDecode(res.Body) return tonumber(data.balance), data.currency end return nil, "Request failed" end function ZoneCoin.Pay(amount, reference, isFiat) local body = HttpService:JSONEncode({ amount = amount, ref = reference, merchant = MERCHANT, isFiat = isFiat or false }) local ok, res = pcall(function() return HttpService:RequestAsync({ Url = API_URL .. "/pay", Method = "POST", Headers = ZoneCoin._Headers(body), Body = body }) end) if ok and res.StatusCode == 200 then local data = HttpService:JSONDecode(res.Body) return data.txId end return nil end function ZoneCoin.Transfer(toPlayer, amount) local body = HttpService:JSONEncode({to = tostring(toPlayer), amount = amount}) local ok, res = pcall(function() return HttpService:RequestAsync({ Url = API_URL .. "/transfer", Method = "POST", Headers = ZoneCoin._Headers(body), Body = body }) end) if ok and res.StatusCode == 200 then return HttpService:JSONDecode(res.Body).txId end return nil end function ZoneCoin._Headers(body) local ts = tostring(os.time()) local nonce = HttpService:GenerateGUID(false):sub(1, 12) return { ["Content-Type"] = "application/json", ["Authorization"] = "Bearer " .. API_KEY, ["X-ZoneCoin-Timestamp"] = ts, ["X-ZoneCoin-Nonce"] = nonce, } end return ZoneCoin

Script Server — Gestore Shop

Luau-- Server Script — Shop handler local ZoneCoin = require(game.ServerScriptService.ZoneCoinSDK) local ReplicatedStorage = game:GetService("ReplicatedStorage") ZoneCoin.Init({ apiUrl = "https://zonecoin.zonenations.com/api/index.php/v1/zonecoin", apiKey = "YOUR_API_KEY", secret = "YOUR_SECRET", merchant = "your-merchant" }) -- Remote event for purchase requests local BuyEvent = ReplicatedStorage:WaitForChild("BuyItem") BuyEvent.OnServerEvent:Connect(function(player, itemId, price) local txId = ZoneCoin.Pay(price, "RBLX-" .. itemId .. "-" .. player.UserId, false) if txId then -- Grant item to player player:FindFirstChild("Inventory"):FindFirstChild(itemId).Value = true BuyEvent:FireClient(player, true, txId) else BuyEvent:FireClient(player, false, "Payment failed") end end)

🟣 VRChat

L'integrazione VRChat usa UdonSharp per creare terminali di pagamento interattivi nei mondi VRChat. Sfrutta VRCStringDownloader per la comunicazione API e sync manuale per lo stato multi-utente.

ZoneCoinTerminal.cs (UdonSharp)

C# (UdonSharp)using UdonSharp; using UnityEngine; using VRC.SDKBase; using VRC.SDK3.StringLoading; using VRC.Udon.Common.Interfaces; /// <summary> /// ZoneCoin Payment Terminal for VRChat worlds. /// Attach to a UI Canvas with display and button references. /// </summary> [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class ZoneCoinTerminal : UdonSharpBehaviour { [Header("ZoneCoin Config")] public string apiUrl = "https://zonecoin.zonenations.com/api/index.php/v1/zonecoin"; public string apiKey = ""; public string merchant = ""; [Header("UI References")] public UnityEngine.UI.Text balanceText; public UnityEngine.UI.Text statusText; [UdonSynced] private string lastTxId = ""; public override void Interact() { // Check balance on interact VRCStringDownloader.LoadUrl( new VRCUrl($"{apiUrl}/balance/{Networking.LocalPlayer.displayName}"), (IUdonEventReceiver)this ); statusText.text = "⏳ Checking balance..."; } public override void OnStringLoadSuccess(IVRCStringDownload result) { // Parse simple JSON response string body = result.Result; // Basic JSON extraction (VRChat limitation: no full JSON parser) string balance = ExtractJsonValue(body, "balance"); string currency = ExtractJsonValue(body, "currency"); balanceText.text = $"💰 {balance} {currency}"; statusText.text = "✅ Balance loaded"; } public override void OnStringLoadError(IVRCStringDownload result) { statusText.text = "❌ Connection error"; } private string ExtractJsonValue(string json, string key) { int start = json.IndexOf($"\"{key}\":\"") + key.Length + 4; int end = json.IndexOf("\"", start); return (start > 0 && end > start) ? json.Substring(start, end - start) : "?"; } }

🏙️ Decentraland

Integra ZoneCoin nelle scene Decentraland usando SDK 7. I terminali di pagamento sono creati come entita' interattive usando PointerEvents e signedFetch per chiamate API autenticate.

ZoneCoinScene.ts

TypeScript (SDK 7)import { engine, Transform, TextShape, PointerEvents, InputAction, pointerEventsSystem } from '@dcl/sdk/ecs' import { signedFetch } from '~system/SignedFetch' const API_URL = 'https://zonecoin.zonenations.com/api/index.php/v1/zonecoin' const API_KEY = 'YOUR_API_KEY' const MERCHANT = 'your-merchant-id' // ── Payment Terminal Entity ─────────────────────────────── const terminal = engine.addEntity() Transform.create(terminal, { position: { x: 8, y: 1.5, z: 8 } }) TextShape.create(terminal, { text: '⚡ ZoneCoin Terminal\nClick to interact', fontSize: 3, textColor: { r: 0.4, g: 0.9, b: 1.0, a: 1 } }) PointerEvents.create(terminal, { pointerEvents: [{ eventType: 1, eventInfo: { button: InputAction.IA_POINTER, hoverText: 'Pay with ZoneCoin' } }] }) // ── Click Handler ───────────────────────────────────────── pointerEventsSystem.onPointerDown({ entity: terminal, opts: { button: InputAction.IA_POINTER } }, async () => { try { const res = await signedFetch({ url: `${API_URL}/pay`, init: { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` }, body: JSON.stringify({ amount: 10, ref: `DCL-${Date.now()}`, merchant: MERCHANT, isFiat: false }) } }) const data = JSON.parse(res.body || '{}') const ts = TextShape.getMutable(terminal) ts.text = data.txId ? `✅ Paid! TX: ${data.txId}` : '❌ Payment failed' } catch (e) { const ts = TextShape.getMutable(terminal) ts.text = '❌ Network error' } } )

🏖️ The Sandbox

L'integrazione The Sandbox Game Maker fornisce un ScriptComponent per acquisti in-game. Usa HTTPRequest per le chiamate API e supporta flussi di pagamento attivati dal click con feedback visivo.

Componente Shop In-Game

TypeScript (Game Maker)// ZoneCoin Integration for The Sandbox Game Maker // Add this as a custom script component import { ScriptComponent, Trigger, HTTPRequest } from '@sandbox/core' const API_URL = 'https://zonecoin.zonenations.com/api/index.php/v1/zonecoin' const API_KEY = 'YOUR_API_KEY' export default class ZoneCoinShop extends ScriptComponent { private apiUrl = API_URL private apiKey = API_KEY onInit() { this.entity.on(Trigger.OnClick, () => this.purchaseItem()) } async purchaseItem() { const request = new HTTPRequest(`${this.apiUrl}/pay`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` }, body: JSON.stringify({ amount: 50, ref: `SAND-${Date.now()}`, merchant: 'your-merchant', isFiat: false }) }) const res = await request.send() if (res.status === 200) { const data = JSON.parse(res.body) this.showNotification(`✅ Payment OK! TX: ${data.txId}`) this.grantReward() } else { this.showNotification('❌ Payment failed') } } showNotification(msg: string) { // Use The Sandbox notification system this.entity.getComponent('TextRenderer').text = msg } grantReward() { // Grant in-game item/reward to player } }

🔌 Riferimento Rapido API REST

Tutte le piattaforme usano la stessa API REST. Autenticazione con HMAC-SHA256.

📊
GET /rate — Tasso di cambio ZC/EUR corrente e dati di mercato
💰
GET /balance/{id} — Recupera saldo wallet e info valuta
💳
POST /pay — Elabora pagamento con settlement merchant
🔄
POST /transfer — Trasferimento ZoneCoin peer-to-peer tra wallet
🔍
GET /tx/{id} — Stato transazione e dettagli di conferma
🔔
POST /webhook/register — Registra endpoint notifica pagamento lato server

Pronto per integrare?

Scegli la tua piattaforma, scarica l'SDK e inizia ad accettare ZoneCoin in pochi minuti.

📥 Modulo DLL Documentazione API E-Commerce