Store

Integration Guide

The users can buy Virtual Items either individually or in packs. After a virtual item is purchased it will be added to the user's inventory. You can use the developer dashboard to create new store offers and virtual items.

Each store offer can contain one or more virtual items to sell. Price info data is also part of the store offer. It is also possible to sell virtual items without creating store offers (you need to provide the price info).

Store Offer structure
using RGN.Modules.VirtualItems;
using System;
using System.Collections.Generic;

namespace RGN.Modules.Store
{
    [Serializable]
    public class StoreOffer
    {
        /// <summary>
        /// Unique id of the store offer
        /// </summary>
        public string id;
        /// <summary>
        /// Store offer name
        /// Is used also to store localization key for the name
        /// </summary>
        public string name;
        /// <summary>
        /// Store offer description
        /// Is used also to store localization key for the name
        /// </summary>
        public string description;
        /// <summary>
        /// List of application ids where this item is used
        /// </summary>
        public List<string> appIds;
        /// <summary>
        /// List of tags to filter the offers
        /// You can place multiple store offers into one category tag
        /// For example in a shooter game: "guns", "rifles"
        /// Or you can also have one store offer for every category
        /// with multiple virtual items
        /// </summary>
        public List<string> tags;
        /// <summary>
        /// Store offer image url
        /// </summary>
        public string imageUrl;
        /// <summary>
        /// Date and time when the store offer was created
        /// In milliseconds since midnight, January 1, 1970 UTC.
        /// This field is automatically populated by the backend
        /// </summary>
        public long createdAt;
        /// <summary>
        /// Date and time when the store offer data was last time updated
        /// In milliseconds since midnight, January 1, 1970 UTC.
        /// This field is automatically populated by the backend
        /// </summary>
        public long updatedAt;
        /// <summary>
        /// User Id who created the store offer
        /// This field is automatically populated by the backend
        /// </summary>
        public string createdBy;
        /// <summary>
        /// User Id who last time updated the store offer
        /// This field is automatically populated by the backend
        /// </summary>
        public string updatedBy;
        /// <summary>
        /// The time when the store offer is available
        /// This is used for limited time offers (LTO)
        /// </summary>
        public TimeInfo time;
        /// <summary>
        /// List of store offer custom json. It is used to store
        /// game specific json in json format.
        /// For example: you can attach some json like
        /// "additiona_description", "in_app_products" to this offer
        /// </summary>
        public List<Properties> properties;
        /// <summary>
        /// Virtual items ids list
        /// It contains the virtual items available to sell
        /// </summary>
        public List<string> itemIds;
        /// <summary>
        /// Price information for the store offer virtual items
        /// It is very powerful: you can sell the same virtual item for different
        /// currencies and prices in the same store offer.
        /// You can also combine two and more {currency, price} to sell one item
        /// by using the group field. To "group" currencies and prices together.
        /// </summary>
        public List<PriceInfo> prices;
        /// <summary>
        /// The Virtual Items data
        /// This is populated only when the
        /// GetWithVirtualItemsDataByAppIdsAsync method is used.
        /// </summary>
        public List<VirtualItem> GetItems();
    }
}

Buy Virtual Items and Store offers:

In case the virtual item contains prices information, you can let the user purchase virtual items by using the following example:

using System.Collections.Generic;
using RGN.Modules.Store;
using RGN.Modules.VirtualItems;

namespace SomeNamespace
{
    internal sealed class PurchaseVirtualItems
    {
        public async void BuyVirtualItemAsync(VirtualItem virtualItem)
        {
            List<string> itemsToPurchase =
                new List<string>() { virtualItem.id };
            var purchaseResult =
                await StoreModule.I.BuyVirtualItemsAsync(itemsToPurchase);
        }
    }
}

The example above shows the purchase of a single virtual item. If you provide more than one item in the request, the purchase process will try to buy all items. In the case that the user does not have enough coins an exception will be thrown.

In case you want to sell virtual items as a pack, you can create a store offer containing those virtual item ids. Later you can use the store offer id to purchase the virtual items pack:

using RGN.Modules.Store;

namespace SomeNamespace
{
    internal sealed class PurchaseStoreOffer
    {
        public async void BuyStoreOfferAsync(string storeOfferId)
        {
            var purchaseResult =
                await StoreModule.I.BuyStoreOfferAsync(storeOfferId);
        }
    }
}

Retrieve Store offers data:

Get for the current app:

using RGN.Modules.Store;

namespace SomeNamespace
{
    internal sealed class SomeClass
    {
        public async void GetStoreOffersForCurrentAppAsync()
        {
            var storeOffers = await StoreModule.I.GetForCurrentAppAsync(limit: 20);
        }
    }
}

As you can see above the GetForCurrentAppAsync has a limit parameter. It is used to support pagination in case you have a lot of store offers and don't want to load them all at once.

The flow for pagination is following:

  1. Make the GetForCurrentAppAsync(limit: itemsToRetrieveInt); and cache the result

  2. Show the result in the UI

  3. When the User scrolls down and it is time to load new items, make a second call GetForCurrentAppAsync(limit: itemsToRetrieveInt, startAfter: "last_loaded_offer_id"); but this time provide the startAfter parameter. This parameter takes the store offer id.

Get by tags:

using System.Collections.Generic;
using RGN.Modules.Store;

namespace SomeNamespace
{
    internal sealed class SomeClass
    {
        public async void GetStoreOffersAsync()
        {
            var tags = new List<string> { "guns", "rifles" };
            var storeOffers = await StoreModule.I.GetByTagsAsync(tags);
        }
    }
}

You can also provide an optional parameter appId to the GetByTagsAsync method call. This parameter is working in combination with the method SetTagsAsync. The SetTagsAsync method has also an optional appId parameter. When this parameter is provided, we automatically attach appId to every tag in thetagsarray and query the database. This is specifically done to let the app developers have unique tags for virtual items per app id.

Get by timestamp:

It is possible to set store offers to be available for a limited time. After you add a new store offer in the developer dashboard you can later set the TimeInfo for the store offer. The time info has the following format:

[Serializable]
public class TimeInfo : IEquatable<TimeInfo>
{
    public bool hasStart;
    public long start;
    public bool hasEnd;
    public long end;
    public bool hasInterval;
    public long intervalDuration;
    public long intervalDelay;
}

The hasStart parameter specifies if the store offer has a starting date. If it is set to true, then the start parameter should have an appropriate Unix timestamp value. The same applies to the hasEnd and end parameters. The hasInterval parameter specifies if the store offer will be unavailable in between the start and end time. For example, a store offer can be available 2 hours every day for 2 weeks starting from now. In this case the TimeInfo values will be:

{
    "hasStart": true,
    "start": unix_time_stamp_now_milliseconds_long,
    "hasEnd": true,
    "end": unix_time_stamp_now_plus_2_weeks_milliseconds_long,
    "hasInterval": true,
    "intervalDuration": two_hours_in_milliseconds_long,
    "intervalDelay": 24_hours_in_milliseconds_long,
}

After you have added such offers, you can query it from the app like this:

using RGN;
using RGN.Modules.Store;
using System;
using System.Collections.Generic;

namespace SomeNamespace
{
    internal sealed class GetStoreOffersByTimestamp
    {
        public async void GetStoreOffersForCurrentAppAsync()
        {
            List<StoreOffer> storeOffers = await StoreModule.I.GetByTimestampAsync(
                RGNCore.I.AppIDForRequests, DateTimeOffset.UtcNow.ToUnixTimeSeconds());
        }
    }
}

Get Store offers with Virtual Item data:

Often it is convenient to get the store offers with the virtual items data to display in the UI. By default, the store offers contain only virtual item ids and you need to query the virtual items separately by ids (VirtualItemsModule.I.GetVirtualItemsByIdsAsync()) The StoreModule has a method to retrieve the StoreOffer data with the VirtualItem data included:

using RGN.Modules.Store;
using RGN.Modules.VirtualItems;
using System;
using System.Collections.Generic;

namespace SomeNamespace
{
    internal sealed class GetStoreOffersWithVirtualItemsData
    {
        public async void GetStoreOffersForCurrentAppAsync()
        {
            DateTime dateTime = DateTime.Now;
            List<StoreOffer> storeOffers =
                await StoreModule.I.GetWithVirtualItemsDataForCurrentAppAsync(20);
            for (int i = 0; i < storeOffers.Count; ++i)
            {
                StoreOffer storeOffer = storeOffers[i];
                var storeOfferItems = storeOffer.GetVirtualItems();
                for (int j = 0; j < storeOfferItems.Count; ++j)
                {
                    VirtualItem virtualItem = storeOfferItems[j];
                    UnityEngine.Debug.Log(virtualItem.name);
                }
            }
        }
    }
}