PlayKit.ai

Payment

Implement player payments and credit management in your game

Payment

PlayKit SDK supports a player payment model where players purchase credits (Sparks) to use AI features. This page explains how to implement credit queries and payment flows in your game.

Developer Costs vs Player Payment

PlayKit provides two billing modes:

Developer Billing Mode (Development Phase)

  • Uses Developer Token
  • All AI call costs charged to developer account
  • Suitable for: Development, testing, prototyping

Player Billing Mode (Production)

  • Players purchase credits
  • Each AI call deducts from player credits
  • Suitable for: Released games

Query Player Credits

Use PlayKit_PlayerClient to query player's current credit balance:

using Cysharp.Threading.Tasks;
using PlayKit_SDK;
using UnityEngine;

public class PlayerCreditDisplay : MonoBehaviour
{
    async void Start()
    {
        // Ensure SDK is initialized
        if (!PlayKitSDK.IsReady())
        {
            await PlayKitSDK.InitializeAsync();
        }

        // Get player client
        var playerClient = PlayKitSDK.GetPlayerClient();

        // Query player info
        var playerInfo = await playerClient.GetPlayerInfoAsync(
            this.GetCancellationTokenOnDestroy()
        );

        if (playerInfo.Success)
        {
            Debug.Log($"Player ID: {playerInfo.Response.UserId}");
            Debug.Log($"Current credits: {playerInfo.Response.Credits}");

            // Update UI display
            UpdateCreditDisplay(playerInfo.Response.Credits);
        }
        else
        {
            Debug.LogError($"Failed to get player info: {playerInfo.ErrorMessage}");
        }
    }

    void UpdateCreditDisplay(int credits)
    {
        // Update credit display UI
    }
}

Handle Insufficient Credits

When player credits are insufficient, AI calls will fail. You need to detect this and guide players to recharge:

using Cysharp.Threading.Tasks;
using PlayKit_SDK;
using PlayKit_SDK.Public;
using System.Collections.Generic;
using UnityEngine;

public class CreditCheck : MonoBehaviour
{
    public async UniTask<bool> TryGenerateText(string message)
    {
        var chatClient = PlayKitSDK.Factory.CreateChatClient();

        var messages = new List<PlayKit_ChatMessage>
        {
            new PlayKit_ChatMessage { Role = "user", Content = message }
        };

        var config = new PlayKit_ChatConfig(messages);

        var result = await chatClient.TextGenerationAsync(
            config,
            this.GetCancellationTokenOnDestroy()
        );

        if (!result.Success)
        {
            // Check if insufficient credits error
            if (result.ErrorMessage.Contains("insufficient credits") ||
                result.ErrorMessage.Contains("Insufficient"))
            {
                Debug.LogWarning("Player has insufficient credits");

                // Show recharge prompt
                ShowRechargePrompt();

                return false;
            }
            else
            {
                Debug.LogError($"Request failed: {result.ErrorMessage}");
                return false;
            }
        }

        return true;
    }

    void ShowRechargePrompt()
    {
        // Show recharge UI or prompt
        Debug.Log("Please visit recharge page to purchase credits");
    }
}

Real-time Credit Monitoring

Monitor player credits in real-time and alert when balance falls below threshold:

using Cysharp.Threading.Tasks;
using PlayKit_SDK;
using UnityEngine;

public class CreditMonitor : MonoBehaviour
{
    [SerializeField] private int lowCreditThreshold = 100;
    [SerializeField] private float checkInterval = 60f; // Check every minute

    private int currentCredits;
    private bool isMonitoring = false;

    async void Start()
    {
        await StartMonitoring();
    }

    public async UniTask StartMonitoring()
    {
        if (isMonitoring) return;
        isMonitoring = true;

        while (isMonitoring)
        {
            await UpdateCredits();
            await UniTask.Delay((int)(checkInterval * 1000));
        }
    }

    public async UniTask UpdateCredits()
    {
        var playerClient = PlayKitSDK.GetPlayerClient();
        var result = await playerClient.GetPlayerInfoAsync(
            this.GetCancellationTokenOnDestroy()
        );

        if (result.Success)
        {
            int previousCredits = currentCredits;
            currentCredits = result.Response.Credits;

            // Credit change notification
            if (previousCredits != currentCredits)
            {
                OnCreditsChanged(previousCredits, currentCredits);
            }

            // Low credit warning
            if (currentCredits < lowCreditThreshold)
            {
                OnLowCredits(currentCredits);
            }
        }
    }

    void OnCreditsChanged(int oldValue, int newValue)
    {
        Debug.Log($"Credits changed: {oldValue} -> {newValue}");

        // Update UI
        // Trigger events
    }

    void OnLowCredits(int credits)
    {
        Debug.LogWarning($"Low credit warning: {credits} credits remaining");

        // Show low credit prompt
    }

    void OnDestroy()
    {
        isMonitoring = false;
    }
}

Recharge Flow Integration

Recharge functionality is implemented through the PlayKit platform's payment interface. See PlayKit Platform documentation for specific integration methods.

Basic Recharge Flow

  1. Player clicks recharge button
  2. Open PlayKit recharge page or use SDK's recharge interface
  3. Player completes payment
  4. Credits automatically added to player account
  5. Game detects credit change and updates display

Example: Open Recharge Page

using UnityEngine;

public class RechargeButton : MonoBehaviour
{
    [SerializeField] private string rechargeURL = "https://playkit.ai/recharge";

    public void OnRechargeClicked()
    {
        // Open recharge page in browser
        Application.OpenURL(rechargeURL);

        // Check credits when app resumes after recharge
        StartCoroutine(WaitForRecharge());
    }

    System.Collections.IEnumerator WaitForRecharge()
    {
        yield return new WaitForSeconds(2f);

        // Check if credits updated
        var monitor = FindObjectOfType<CreditMonitor>();
        if (monitor != null)
        {
            monitor.UpdateCredits().Forget();
        }
    }
}

Estimate Feature Costs

Different AI features consume different credits. You can show estimated costs to players before calling:

Text Generation Cost Estimation

public class CostEstimator
{
    // Rough estimation (actual costs depend on model and token count)
    public int EstimateTextGenerationCost(string prompt)
    {
        // Estimate input tokens (~4 chars/token for English, ~1 char/token for Chinese)
        int estimatedInputTokens = prompt.Length / 2;

        // Estimate output tokens (assume similar to input length)
        int estimatedOutputTokens = estimatedInputTokens;

        // GPT-4o-mini price example (check platform for actual prices)
        // Input: $0.150 / 1M tokens
        // Output: $0.600 / 1M tokens

        double inputCost = estimatedInputTokens * 0.00000015;
        double outputCost = estimatedOutputTokens * 0.00000060;

        // Convert to credits (assume 1 credit = $0.01)
        int credits = Mathf.CeilToInt((float)((inputCost + outputCost) * 100));

        return Mathf.Max(credits, 1); // Minimum 1 credit
    }

    public int EstimateImageGenerationCost(string size)
    {
        // DALL-E 3 price example
        switch (size)
        {
            case "1024x1024": return 4;  // $0.040
            case "1024x1792": return 8;  // $0.080
            case "1792x1024": return 8;  // $0.080
            default: return 2;
        }
    }
}

Show Cost Before Call

using UnityEngine;
using UnityEngine.UI;

public class AIFeatureButton : MonoBehaviour
{
    [SerializeField] private Text costText;
    [SerializeField] private Button executeButton;

    private CostEstimator estimator = new CostEstimator();
    private int estimatedCost;

    public void SetPrompt(string prompt)
    {
        estimatedCost = estimator.EstimateTextGenerationCost(prompt);
        costText.text = $"Estimated cost: {estimatedCost} credits";

        // Check if player can afford
        CheckCanAfford();
    }

    async void CheckCanAfford()
    {
        var playerClient = PlayKitSDK.GetPlayerClient();
        var result = await playerClient.GetPlayerInfoAsync(
            this.GetCancellationTokenOnDestroy()
        );

        if (result.Success)
        {
            bool canAfford = result.Response.Credits >= estimatedCost;
            executeButton.interactable = canAfford;

            if (!canAfford)
            {
                costText.text = $"Insufficient credits (need {estimatedCost}, have {result.Response.Credits})";
            }
        }
    }
}

Best Practices

  1. Display credits in real-time: Always show player's current credits in game UI
  2. Warn early: Alert players to recharge when credits fall below threshold
  3. Show estimated costs: Tell players approximately how many credits each AI feature costs
  4. Handle failures gracefully: When credits are insufficient, provide clear recharge guidance
  5. Cache player info: Avoid frequent queries, use event-driven updates
  6. Provide trial credits: Consider giving new players some free credits to experience features

Cost Optimization

Ways to help players save credits:

  1. Use cheaper models: Use gpt-4o-mini instead of gpt-4 for simple tasks
  2. Limit output length: Use maxTokens parameter to limit response length
  3. Reuse results: Cache answers to common questions
  4. Compress prompts: Simplify system prompts and user inputs
  5. Reasonable temperature settings: Lower temperature values may produce shorter responses
var config = new PlayKit_ChatConfig(messages) { Temperature = 0.5f, MaxTokens = 150 };

Next Steps