Orishare
Recipes

Unity

One prompt: XP, levels, coins, streaks, badges, quests, leaderboards, leagues and referrals in a Unity game, with UnityWebRequest and a customer session.

A Unity game talks to Orishare as the signed-in player: the publishable key plus a customer session. The session comes from one of two places:

  • Your game server (any backend, a serverless function is enough) mints it with the secret key. Choose this when you have player accounts on your server, or when match results must be trusted (competitive play, prizes): the server reports them.
  • Firebase Authentication or Supabase Auth in the game: the client exchanges the player's ID or access token for a session, with no server of yours.

Never ship a secret key (osk_) or the agent token in a build: anything in a build is public.

The prompt

Paste this into your coding agent from the root of the Unity project.

Add a reward system to this Unity game with Orishare: XP and levels, coins, a daily streak with
repair, badges, a starter quest, a weekly XP leaderboard, a weekly league and friend referrals.
Follow https://docs.orishare.com/docs/recipes/unity.md and the pages it links, step by step:
sign up for Orishare yourself (no human needed), apply the game starter configuration in the
test environment, add the C# client (and the small session endpoint if the game has a server), test every
HTTP call the client makes against the test environment, then give me the claim link and a short list of
what you built. Never put a secret key (osk_) or agent token (opat_) in the Unity project.

Steps

  1. Sign up with Start here for AI agents, then apply the game starter in the test environment: Game setup.

  2. Get a session for the player.

    • With a server: the endpoint in Web game, step 5 (a key with customer_sessions:write, then POST /v1/customer_sessions with grant_type: "secret_key"). The game calls it after your login and gets { token }.
    • With Firebase or Supabase: create the identity connection (Game setup, identity), then exchange the player's token in the client (grant_type: "identity_token"), as below.
  3. The client (Assets/Scripts/Orishare.cs):

    using System;
    using System.Collections;
    using System.Text;
    using UnityEngine;
    using UnityEngine.Networking;
    
    public class Orishare : MonoBehaviour
    {
        const string Api = "https://api.orishare.com";
        [SerializeField] string publishableKey = "opk_..."; // public, safe in the build
        [SerializeField] string connectionId = "";          // ic_... when you use Firebase or Supabase
        string token;                                      // memory only, never PlayerPrefs
    
        public IEnumerator ExchangeIdentityToken(string providerToken, Action<bool> done)
        {
            var body = "{\"grant_type\":\"identity_token\",\"connection_id\":\"" + connectionId +
                       "\",\"provider_token\":\"" + providerToken + "\"}";
            yield return Send("POST", "/v1/customer_sessions", body, false, json =>
            {
                token = JsonUtility.FromJson<Session>(json).customer_token;
                done(token != null);
            });
        }
    
        public void UseServerSession(string serverToken) => token = serverToken;
    
        // A player read, for example "levels" for GET /v1/customer/levels, or "balances", "streaks".
        public IEnumerator Read(string path, Action<string> done) =>
            Send("GET", "/v1/customer/" + path, null, true, done);
    
        // A player event, for example "session.started" or "level.completed".
        public IEnumerator Track(string name, string propertiesJson, string id, Action<string> done)
        {
            var body = "{\"events\":[{\"id\":\"" + id + "\",\"name\":\"" + name +
                       "\",\"properties\":" + (propertiesJson ?? "{}") + "}]}";
            yield return Send("POST", "/v1/customer/events", body, true, done);
        }
    
        IEnumerator Send(string method, string path, string body, bool asCustomer, Action<string> done)
        {
            using var req = new UnityWebRequest(Api + path, method);
            req.downloadHandler = new DownloadHandlerBuffer();
            if (body != null) req.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(body));
            req.SetRequestHeader("Authorization", "Bearer " + publishableKey);
            req.SetRequestHeader("Content-Type", "application/json");
            if (method != "GET") req.SetRequestHeader("Idempotency-Key", Guid.NewGuid().ToString());
            if (asCustomer) req.SetRequestHeader("X-Orishare-Customer-Token", token);
            yield return req.SendWebRequest();
            if (req.responseCode == 401) token = null; // expired: get a new session
            done(req.result == UnityWebRequest.Result.Success ? req.downloadHandler.text : null);
        }
    
        [Serializable] class Session { public string customer_token; public string expires_at; }
    }

    Event ids are per player: another player's identical id is a separate event, so no prefix is needed. Targets Unity 2020.2 or later (C# 8). A retry of the same intent must reuse its Idempotency-Key and event id: keep them in a field until the call succeeds. Parse the reads with JsonUtility classes that mirror the fields in Game setup, player screens (or Newtonsoft JSON, which handles nested lists more easily). Declare the field types exactly: amounts and streak current and best are strings, freezes is a number, and an object that can be null (repair, a league entry) parses as an empty instance under JsonUtility, so check a field inside it before you show it.

  4. What the client sends. session.started once a day when the game opens. If the game has no server, also match.completed ({"score":n,"won":true}) and level.completed ({"level":n}); they count up to the per-day caps. With a server, the server reports matches with the secret key instead (Web game, step 4) and the client sends only session.started.

  5. Player actions (streak repair, referral code, quest claim, push device): Game setup, player screens. They are customer calls like Read, with POST and a JSON body.

  6. Test. Run the same calls the client makes from a terminal (curl or a small script) against the test environment: Game setup, test. Then play in the Editor. A native build sends no Origin header, so it needs no allowed origin; a WebGL build runs in a browser and does (Web game, step 7).

  7. Go live: Game setup, go live. Swap the publishable key for the live one in the build.

On this page