PlaySuper LogoPlaySuper
Unity SDK

Touchpoints & Curated Lists

Fetch and display reward widgets, product collections, and promotional content in your Unity game

Beyond the built-in store, you can render reward widgets and product collections directly in your game UI using touchpoints and curated lists.

Touchpoints 2.0

Requires PlaySuper Unity SDK 4.5.0 or later. TouchpointV2Manager does not exist in earlier versions, so calling it will not compile rather than fail at runtime.

Upgrade with:

openupm add com.playsuper.unity@4.5.0

Check what you are on in Packages/manifest.json, or in Window > Package Manager > PlaySuper.

Staying on an older SDK for now? Call GET /v2/touchpoints/serve directly — it is the same endpoint this method wraps, and the response below is exactly what it returns. You lose the typed model and OpenCta's attribution handling, nothing else.

TouchpointV2Manager and TouchpointManager are different systems, despite the similar names. The TouchpointManager methods further down are the older node-based touchpoints: they take a coinId and return a different shape. Upgrading to 4.5.0 changes nothing about them, and nothing migrates on its own — an existing integration keeps working untouched until you port it deliberately.

A touchpoint is an offer the studio places on one of their game's screens from the PlaySuper console. The game names the screen it is about to show; the server returns the artwork the studio chose and one concrete offer already composed into it — priced for this player, with the coin maths done. Your game draws two images and opens a URL.

Fetching a touchpoint

using PlaySuperUnity;

async void ShowHome()
{
    var tp = await TouchpointV2Manager.Serve(TouchpointV2Manager.Screens.Home);

    if (tp != null && tp.HasTouchpoint)
    {
        // tp.FrameImageUrl  — the frame the studio picked
        // tp.OfferImageUrl  — the offer art, drawn in its centre
        // tp.item.cta.label — the button copy
        ShowTouchpoint(tp);
    }
}

"Nothing to show" is not an error. A non-null result with HasTouchpoint false means the studio has not configured this screen, or has but no catalogue item is available right now. Both are ordinary states and the call succeeded. Only null means the request itself failed. Treat an unconfigured screen as normal and render without a touchpoint.

asset and item are always both present or both absent — a frame with an empty centre reads as a broken build — so HasTouchpoint is a single check rather than two.

Opening the offer

TouchpointV2Manager.OpenCta(tp);

Pass the response rather than building a URL. The server has already appended campaign attribution to cta.url, and OpenStore reads it back off — a hand-built URL silently loses attribution for every touchpoint your game opens.

Parameters

ParameterTypeDescription
screenstringWhich screen is about to be shown. See TouchpointV2Manager.Screens. Only home is live today; an unrecognised screen returns a 400 naming the valid ones.
typestringOptional. product, coupon or gift-card. Needed only when the screen has more than one placement — an ambiguous call is rejected rather than picked for you.
utmSource / utmMedium / utmCampaignstringOptional. Appended to the CTA URL.
await TouchpointV2Manager.Serve(
    TouchpointV2Manager.Screens.Home,
    TouchpointV2Manager.ItemType.Product,
    utmSource: "level_end");

Response

public class TouchpointV2Response
{
    public string screen;
    public string placementId;          // null when no placement is configured
    public TouchpointV2Asset asset;     // the frame
    public TouchpointV2Item item;       // the offer inside it
    public string servedAt;

    public bool HasTouchpoint { get; }  // asset != null && item != null
    public string FrameImageUrl { get; }
    public string OfferImageUrl { get; }
    public bool IsPortrait { get; }
}
FieldNotes
asset.imageUrlThe frame you draw. Not assetUrl.
asset.orientationPORTRAIT or LANDSCAPE.
item.imageUrlThe offer art, drawn in the frame's centre.
item.pricingcurrency, mrp, price, priceAfterCoins, discountPct. Null for coupons — prices are nested here, not on item itself.
item.offerTextPre-formatted coupon line, e.g. "Flat 40% off up to ₹200". Display as given.
item.coinscoinsRequired and coinDiscount. Null when this game's coin cannot be spent on the item.
item.ctalabel and url. Hand the response to OpenCta rather than using the URL directly.

Every figure is computed server-side for this player and this game's coin. The game does no pricing arithmetic.

Touchpoints

Touchpoints are visual widget configurations that control how rewards and promotions appear in your game. Use the TouchpointManager to fetch touchpoint data and render custom widgets.

This is the original node-based API, and it is still supported. New integrations should prefer Touchpoints 2.0 above, where the server composes the widget for you instead of returning a node tree to walk.

Fetching touchpoints

// Fetch by name (recommended for most use cases)
TouchpointResponse store = await TouchpointManager.GetTouchpointByName("flash-sale-card", "coin-uuid-abcd");

// Fetch by ID
TouchpointResponse offer = await TouchpointManager.GetTouchpointById(
    "6f9a5737-0247-4a71-89eb-b5d02212f179",
    "coin-uuid-abcd"
);

// List all active touchpoints
TouchpointListResponse list = await TouchpointManager.ListTouchpoints("coin-uuid-abcd");

Processing touchpoint data

if (store?.nodes?.Length > 0)
{
    TouchpointNode node = store.nodes[0];

    Debug.Log($"Layout: {node.layoutHint}");

    string bgImage = node.background?.images?[0];
    string titleText = node.title?[0]?.text;
    string titleColor = node.title?[0]?.color;
    string ctaAction = node.cta?.action;
    string ctaText = node.cta?.text;

    bool timerEnabled = node.GetStyleHint<bool>("timerEnabled", false);

    if (node.HasReward)
    {
        HydratedReward reward = node.GetReward();
        string brandName = reward?.brandName;
    }
}

For the full touchpoint data model, example responses, and all available node fields, see the Touchpoints API Reference.

Curated lists

Curated lists are pre-configured collections of products or rewards set up by PlaySuper. Fetch them by name and display them in your game's UI.

Fetching a curated list

// Products
var products = await PlaySuperUnitySDK.Instance.GetCuratedList(
    CuratedListType.Products,
    "homepage_featured",
    "your-coin-id"
);

// Rewards
var rewards = await PlaySuperUnitySDK.Instance.GetCuratedList(
    CuratedListType.Rewards,
    "daily_deals",
    "your-coin-id"
);
ParameterTypeRequiredDescription
typeCuratedListTypeYesCuratedListType.Products or .Rewards
listNamestringYesName of the curated list (provided by PlaySuper)
coinIdstringYesYour game's coin ID
versionstringNoAPI version for rewards (e.g., "2.0.0")

Working with products

public async void LoadFeaturedProducts()
{
    try
    {
        var response = await PlaySuperUnitySDK.Instance.GetCuratedList(
            CuratedListType.Products,
            "homepage_featured",
            "your-coin-id"
        );

        foreach (var product in response.products)
        {
            Debug.Log($"Product: {product.name}");
            Debug.Log($"Brand: {product.brandName}");
            Debug.Log($"Image: {product.imageUrl}");

            var sku = product.skus[0];
            if (sku.playSuperPrice != null)
            {
                Debug.Log($"Price: {sku.playSuperPrice.discountedListingPrice}");
            }
        }
    }
    catch (Exception ex)
    {
        Debug.LogError($"Failed to load products: {ex.Message}");
    }
}

Key product fields:

FieldDescription
nameProduct display name
brandNameBrand name
imageUrlPrimary product image
imagesAdditional product images
descriptionHTML description
plainTextDescriptionPlain text description
skusAvailable variants with pricing
optionTypesProduct options (size, color, etc.)
ctaUrlDeep link to view/purchase in store

SKU pricing (sku.playSuperPrice):

FieldDescription
listingPriceOriginal price
discountedListingPriceFinal price after discount
discountPercentDiscount percentage

Working with rewards

public async void LoadRewards()
{
    try
    {
        var response = await PlaySuperUnitySDK.Instance.GetCuratedList(
            CuratedListType.Rewards,
            "gift_cards",
            "your-coin-id"
        );

        foreach (var reward in response.rewards)
        {
            Debug.Log($"Title: {reward.metadata.campaignTitle}");
            Debug.Log($"Brand: {reward.brandName}");
            Debug.Log($"Image: {reward.metadata.campaignCoverImage}");

            if (reward.price.Count > 0)
            {
                Debug.Log($"Price: {reward.price[0].amount} coins");
            }

            Debug.Log($"Available: {reward.inventory.availableQuantity}");
        }
    }
    catch (Exception ex)
    {
        Debug.LogError($"Failed to load rewards: {ex.Message}");
    }
}

Key reward fields:

FieldDescription
brandNameBrand name
metadata.campaignTitleReward title
metadata.campaignSubTitleReward subtitle
metadata.campaignCoverImageCover image URL
metadata.brandLogoImageBrand logo URL
metadata.termsAndConditionsTerms and conditions
metadata.howToRedeemRedemption instructions
price[0].amountPrice in coins
inventory.availableQuantityStock remaining
ctaUrlDeep link to store page

Deep-linking to a product or reward

Both products and rewards include a ctaUrl that opens the store directly to that item:

PlaySuperUnitySDK.Instance.OpenStore(product.ctaUrl);
PlaySuperUnitySDK.Instance.OpenStore(reward.ctaUrl);

// With UTM tracking
PlaySuperUnitySDK.Instance.OpenStore(product.ctaUrl, "featured_banner");

Contact your PlaySuper integration team to get curated list names and configure custom lists for your game.

Next, see the Complete Example for a full integration script, offline support, user properties, and troubleshooting.