Basic Setup
This guide explains how to set up the basic environment for using the PlayNANOO REST API in Unity C#.
1. Prerequisites
You must obtain the following information from the PlayNANOO console in advance.
Obtaining API Authentication Information
Access the PlayNANOO console and check the following information.
Path: Console > Channel > Settings > API & Platform Management
Information you need to obtain:
- Game ID: Channel unique identifier
- Service Key: Service key used for API requests
- Secret Key: Secret key used for generating security signatures
The Secret Key must never be exposed. Manage it through environment variables or a separate configuration file.
2. Unity C# Implementation
Implement an HTTP client for calling PlayNANOO APIs in Unity.
2.1 Basic Configuration
First, configure the authentication information you obtained.
public static class HttpClient
{
// Authentication information obtained from the console
private static string ServiceKey = "YOUR_SERVICE_KEY";
private static string GameId = "YOUR_GAME_ID";
private static string SecretKey = "YOUR_SECRET_KEY";
public static string GetGameId
{
get { return GameId; }
}
}
2.2 How to Write Request Classes
All API request classes must inherit from DeviceInfo.
[Serializable]
public class Req : DeviceInfo
{
public string my_param; // API-specific parameter
}
DeviceInfo automatically includes the following information:
- uuid, nickname: Player information (automatically included after login)
- device_id, version, platform: Device information
- device_model, device_os, device_language: Detailed device information
- device_country, device_timeoffset: Region/timezone information
For the complete implementation of the DeviceInfo class and Utils helper functions, refer to Section 3. Complete Example Code.
2.3 HTTP Request Function Implementation
Implement a generic Send function for API requests.
using System;
using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
public static IEnumerator Send<TReq, TRes>(
string method, // HTTP method (GET, POST, PUT, DELETE)
string url, // Full API URL
bool requireToken, // Whether authentication token is required
TReq body, // Request body (except GET)
Action<TRes> onSuccess, // Success callback
Action<BaseResponse> onError, // Failure callback
int timeoutSec = 10) // Timeout (default 10 seconds)
{
UnityWebRequest www;
// GET request
if (method == UnityWebRequest.kHttpVerbGET)
{
www = UnityWebRequest.Get(url);
}
// POST, PUT, DELETE, etc.
else
{
string json = body != null ? JsonUtility.ToJson(body) : "{}";
www = new UnityWebRequest(url, method);
www.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json));
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
}
if (www.downloadHandler == null)
www.downloadHandler = new DownloadHandlerBuffer();
// Common header settings
www.SetRequestHeader("Accept", "application/json");
www.SetRequestHeader("X-Playnanoo-Key", ServiceKey);
www.SetRequestHeader("X-Playnanoo-Id", GameId);
// Add Authorization header if authentication token is required
if (requireToken && DataManager.Instance.AccessToken != null)
{
www.SetRequestHeader("Authorization", $"Bearer {DataManager.Instance.AccessToken}");
}
www.timeout = timeoutSec;
yield return www.SendWebRequest();
// Response handling
if (www.result == UnityWebRequest.Result.Success &&
www.responseCode >= 200 && www.responseCode < 300)
{
var text = www.downloadHandler.text;
var data = string.IsNullOrWhiteSpace(text)
? default
: JsonUtility.FromJson<TRes>(text);
onSuccess?.Invoke(data);
}
else
{
var text = www.downloadHandler.text;
BaseResponse data;
if (string.IsNullOrWhiteSpace(text))
{
// Create BaseResponse with HTTP status code and error message if response body is empty
data = new BaseResponse
{
ErrorCode = www.responseCode.ToString(),
Message = www.error ?? "Unknown error"
};
}
else
{
data = JsonUtility.FromJson<BaseResponse>(text);
}
onError?.Invoke(data);
}
www.Dispose();
}
2.4 Utility Methods
Utility methods needed for API calls.
GenerateAuthKey()
Generates an AuthKey for Help Desk authentication.
public static string GenerateAuthKey(string userId)
{
string data = $"{GameId}{userId}";
return Convert.ToBase64String(Encoding.UTF8.GetBytes(data));
}
Usage example:
string userId = DataManager.Instance.UUID;
string authKey = HttpClient.GenerateAuthKey(userId);
// Include in Help Desk URL
string url = $"https://help.playnanoo.com/{HttpClient.GetGameId}?userId={userId}&authKey={authKey}";
3. Complete Example Code
Here is the complete code including all the above content. DeviceInfo and HttpClient are managed as separate files.
DeviceInfo.cs
A base class that automatically collects device information.
using System;
using UnityEngine;
// Device information base class
[Serializable]
public class DeviceInfo
{
public string uuid;
public string nickname;
public string device_id;
public string version;
public string platform;
public string device_model;
public string device_os;
public string device_language;
public string device_country;
public string device_timeoffset;
public DeviceInfo()
{
uuid = DataManager.Instance.UUID;
nickname = DataManager.Instance.Nickname;
device_id = SystemInfo.deviceUniqueIdentifier;
version = DataManager.Instance.VersionNumber.ToString();
platform = DataManager.Instance.Platform;
device_model = SystemInfo.deviceModel;
device_os = SystemInfo.operatingSystem;
device_language = GetDeviceLanguage();
device_country = GetCountryCode();
device_timeoffset = GetTimeOffset().ToString();
}
private string GetDeviceLanguage()
{
switch (Application.systemLanguage)
{
case SystemLanguage.Afrikaans: return "AF";
case SystemLanguage.Arabic: return "AR";
case SystemLanguage.Basque: return "EU";
case SystemLanguage.Belarusian: return "BE";
case SystemLanguage.Bulgarian: return "BG";
case SystemLanguage.Catalan: return "CA";
case SystemLanguage.Chinese:
case SystemLanguage.ChineseSimplified: return "zh-CN";
case SystemLanguage.ChineseTraditional: return "zh-TW";
case SystemLanguage.Czech: return "CS";
case SystemLanguage.Danish: return "DA";
case SystemLanguage.Dutch: return "NL";
case SystemLanguage.English: return "EN";
case SystemLanguage.Estonian: return "ET";
case SystemLanguage.Faroese: return "FO";
case SystemLanguage.Finnish: return "FI";
case SystemLanguage.French: return "FR";
case SystemLanguage.German: return "DE";
case SystemLanguage.Greek: return "EL";
case SystemLanguage.Hebrew: return "IW";
case SystemLanguage.Hungarian: return "HU";
case SystemLanguage.Icelandic: return "IS";
case SystemLanguage.Indonesian: return "IN";
case SystemLanguage.Italian: return "IT";
case SystemLanguage.Japanese: return "JA";
case SystemLanguage.Korean: return "KO";
case SystemLanguage.Latvian: return "LV";
case SystemLanguage.Lithuanian: return "LT";
case SystemLanguage.Norwegian: return "NO";
case SystemLanguage.Polish: return "PL";
case SystemLanguage.Portuguese: return "PT";
case SystemLanguage.Romanian: return "RO";
case SystemLanguage.Russian: return "RU";
case SystemLanguage.SerboCroatian: return "SH";
case SystemLanguage.Slovak: return "SK";
case SystemLanguage.Slovenian: return "SL";
case SystemLanguage.Spanish: return "ES";
case SystemLanguage.Swedish: return "SV";
case SystemLanguage.Thai: return "TH";
case SystemLanguage.Turkish: return "TR";
case SystemLanguage.Ukrainian: return "UK";
case SystemLanguage.Vietnamese: return "VI";
default: return "unknown";
}
}
private string GetCountryCode()
{
switch (Application.systemLanguage)
{
case SystemLanguage.Afrikaans: return "ZA";
case SystemLanguage.Arabic: return "SA";
case SystemLanguage.Basque: return "EU";
case SystemLanguage.Belarusian: return "BY";
case SystemLanguage.Bulgarian: return "BE";
case SystemLanguage.Catalan: return "EU";
case SystemLanguage.Chinese:
case SystemLanguage.ChineseSimplified: return "CN";
case SystemLanguage.ChineseTraditional: return "TW";
case SystemLanguage.Czech: return "CZ";
case SystemLanguage.Danish: return "DK";
case SystemLanguage.Dutch: return "NL";
case SystemLanguage.English: return "US";
case SystemLanguage.Estonian: return "EE";
case SystemLanguage.Faroese: return "FO";
case SystemLanguage.Finnish: return "FI";
case SystemLanguage.French: return "FR";
case SystemLanguage.German: return "DE";
case SystemLanguage.Greek: return "GR";
case SystemLanguage.Hebrew: return "IL";
case SystemLanguage.Hungarian: return "HU";
case SystemLanguage.Icelandic: return "IS";
case SystemLanguage.Indonesian: return "ID";
case SystemLanguage.Italian: return "IT";
case SystemLanguage.Japanese: return "JP";
case SystemLanguage.Korean: return "KR";
case SystemLanguage.Latvian: return "LV";
case SystemLanguage.Lithuanian: return "LT";
case SystemLanguage.Norwegian: return "NO";
case SystemLanguage.Polish: return "PL";
case SystemLanguage.Portuguese: return "PT";
case SystemLanguage.Romanian: return "RO";
case SystemLanguage.Russian: return "RU";
case SystemLanguage.SerboCroatian: return "HR";
case SystemLanguage.Slovak: return "SK";
case SystemLanguage.Slovenian: return "SI";
case SystemLanguage.Spanish: return "ES";
case SystemLanguage.Swedish: return "SE";
case SystemLanguage.Thai: return "TH";
case SystemLanguage.Turkish: return "TR";
case SystemLanguage.Ukrainian: return "UA";
case SystemLanguage.Vietnamese: return "VN";
default: return "US";
}
}
private double GetTimeOffset()
{
DateTime now = DateTime.Now;
DateTime utc = DateTime.UtcNow;
TimeSpan timeSpan = now.Subtract(utc);
return Math.Round(timeSpan.TotalSeconds);
}
}
HttpClient.cs
HTTP client for PlayNANOO API calls.
using System;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
public static class HttpClient
{
private static string ServiceKey = "YOUR_SERVICE_KEY";
private static string GameId = "YOUR_GAME_ID";
private static string SecretKey = "YOUR_SECRET_KEY";
public static string GetGameId
{
get { return GameId; }
}
public static IEnumerator Send<TReq, TRes>(
string method,
string url,
bool requireToken,
TReq body,
Action<TRes> onSuccess,
Action<BaseResponse> onError,
int timeoutSec = 10)
{
UnityWebRequest www;
// GET request
if (method == UnityWebRequest.kHttpVerbGET)
{
www = UnityWebRequest.Get(url);
}
// POST, PUT, DELETE, etc.
else
{
string json = body != null ? JsonUtility.ToJson(body) : "{}";
www = new UnityWebRequest(url, method);
www.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json));
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
}
if (www.downloadHandler == null)
www.downloadHandler = new DownloadHandlerBuffer();
// Common header settings
www.SetRequestHeader("Accept", "application/json");
www.SetRequestHeader("X-Playnanoo-Key", ServiceKey);
www.SetRequestHeader("X-Playnanoo-Id", GameId);
// Add Authorization header if authentication token is required
if (requireToken && DataManager.Instance.AccessToken != null)
{
www.SetRequestHeader("Authorization", $"Bearer {DataManager.Instance.AccessToken}");
}
www.timeout = timeoutSec;
yield return www.SendWebRequest();
// Response handling
if (www.result == UnityWebRequest.Result.Success &&
www.responseCode >= 200 && www.responseCode < 300)
{
var text = www.downloadHandler.text;
var data = string.IsNullOrWhiteSpace(text)
? default
: JsonUtility.FromJson<TRes>(text);
onSuccess?.Invoke(data);
}
else
{
var text = www.downloadHandler.text;
BaseResponse data;
if (string.IsNullOrWhiteSpace(text))
{
// Create BaseResponse with HTTP status code and error message if response body is empty
data = new BaseResponse
{
ErrorCode = www.responseCode.ToString(),
Message = www.error ?? "Unknown error"
};
}
else
{
data = JsonUtility.FromJson<BaseResponse>(text);
}
onError?.Invoke(data);
}
www.Dispose();
}
public static string GenerateAuthKey(string userId)
{
string data = $"{GameId}{userId}";
return Convert.ToBase64String(Encoding.UTF8.GetBytes(data));
}
}