Marketplace

Overview

Creators can use the Marketplace to sell world products like in-game currency (Gold, Crystals, etc.) or items (guns, ammo, healing potions, etc.) to players.

Seller Responsibilities

Creators are responsible for ensuring proper delivery of purchased items to buyers. In cases where missing deliveries, misleading product descriptions, damage to the value of purchased items, or other issues arise, creators must take appropriate action to resolve them. Creators who fail to fulfill delivery obligations or repeatedly receive related reports may be subject to penalties, such as payout holds, world sanctions, or even account deactivation.

Learn More

World Product Guidelines

Item Type

Item Type
Purpose
Example

World Product

One-time delivery of currency, items, etc.

Currency (Gold, Crystals, etc.) Items (swords, axes, healing potions, etc.) Consumables (Revives, Instant Building Passes, etc.)

Manage Products

Products are set up per world and can be configured individually.

To register and manage products, you must first publish your world. If you assign a group as the Owner group when publishing the world, you can manage products and share revenue with group members.

Features by Permission Level

Permission Level
View/Register Product
Edit Product
Share Revenue

World Creator (Personal World)

O

O

O

Group Owner (Group World)

O

O

O

Group Member (Group World)

O

X

X

View Product List

From the World tab on the Dashboard, click on your world. On the world's page, click the World Product tab to view your registered products.

Register Product

Click the + Create World Product button to add a new product.

Copy Product ID

Click the ... button next to each product's name, then click Copy Product ID to copy the product's ID.

Edit Product

Click the product image or name to change its image, name, or price.

Scripting for Product Sales

Since purchasing products through the Marketplace involves spending user currency, it is essential to implement strict error handling and debugging using methods like pcall. This helps maintain system stability during runtime errors or network delays, and prevents critical issues such as missing item deliveries.

Feature List

Feature
Description

GetProductInfo(productId, productType)

Request information on a specific product

GetWorldProductsAsync()

Request information on all world products

PromptProductPurchase(player, productId)

Request purchase

PromptProductPurchaseFinished

Handle the event required when the purchase window closes

ProcessReceipt

Event for updating the receipt status to Completed after successful delivery of the purchased product

Request Information on a Specific Product (GetProductInfo)

Returns the product information corresponding to the product ID (productId) and product type (Enum.InfoType).

local MarketplaceService = game:GetService("MarketplaceService")

local function Request_GetProductInfo(productId)
    local success, errorOrProductInfo = pcall(function()
        return MarketplaceService:GetProductInfo(productId, Enum.InfoType.Product)
    end)
    
    if not success then
        print("Error: " .. errorOrProductInfo .. " / ProductId : " .. productId)
        
    else
        local productInfo = errorOrProductInfo 
        print("World Product Name: " .. tostring(productInfo.Name))
        print("ProductId: " .. tostring(productInfo.ProductId))
        print("ProductType: " .. tostring(productInfo.ProductType))
        print("PriceInBLUC: " .. tostring(productInfo.PriceInBLUC))
        print("Description: " .. tostring(productInfo.Description))
        print("Created: " .. productInfo.Created)
        print("Updated: " .. productInfo.Updated)
        
        -- Display on UI
    end
end

Request Information on All World Products (GetWorldProductsAsync)

Returns a Pages Object containing information on all world products.

local MarketplaceService = game:GetService("MarketplaceService")

local function Request_GetWorldProductsAsync()
    local success, errorOrWorldProducts = pcall(function()
        return MarketplaceService:GetWorldProductsAsync()
    end) 
    
    if not success then
        print("Error: " .. errorOrWorldProducts)
        
    else
        local worldProducts = errorOrWorldProducts
        
        local pageCount = 1	  
        local dataList = {}
			
        while true do
            local currentPage = worldProducts:GetCurrentPage()	
		    
            -- Exit loop if it's the last page
            if worldProducts.IsFinished or currentPage == nil then           	
                print(pageCount .. " page IsFinished : " .. tostring(worldProducts.IsFinished))
                break
            else
                worldProducts:AdvanceToNextPageAsync()
                pageCount = pageCount + 1
            end
	    
            -- Each page contains up to 100 product entries
            for _, productInfo in pairs(currentPage) do		
                local i = #dataList + 1
				
                print("------ " .. i .. " ------")
                print("World Product Name: " .. tostring(productInfo.Name))
                print("ProductId: " .. tostring(productInfo.ProductId))
                
                print("ProductType: " .. tostring(productInfo.ProductType))
                print("PriceInBLUC: " .. tostring(productInfo.PriceInBLUC))
                print("Description: " .. tostring(productInfo.Description))
                print("Created: " .. productInfo.Created)
                print("Updated: " .. productInfo.Updated)
	
                table.insert(dataList, productInfo)
		
                -- Display on UI 
            end
        end
    end
end

Request Purchase (PromptProductPurchase)

Request the purchase of the product corresponding to the product ID (productID). (Purchase window appears using the system UI.)

local MarketplaceService = game:GetService("MarketplaceService")

local function Request_PromptProductPurchase(player, productId)
    local success, error = pcall(function()
        MarketplaceService:PromptProductPurchase(player, productId)
    end)
	
    if not success then
        print("Error: " .. error .. " / ProductId : " .. productId)        
    end	
end

When the Purchase Window Closes (PromptProductPurchaseFinished)

This event is triggered when the purchase window, opened via request Purchase (PromptProductPurchase), is closed. If the purchase is successful, "true" will be sent to isPurchased; if the user cancels or the purchase fails, "false" will be sent to isPurchased.

This event should only be used to detect whether the purchase window is closed. It must never be used to process the deliver of purchased products.

local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")

local function OnPromptPurchaseFinished(userId, productId, isPurchased)
    local player = Players:GetPlayerByUserId(userId)
    
    print(player.Name .. " / ProductID : " .. productId .. " / isPurchased : " .. tostring(isPurchased))
end
MarketplaceService.PromptProductPurchaseFinished:Connect(OnPromptPurchaseFinished)

Product Delivery on Successful Purchase (ProcessReceipt)

Trigger the event that returns undelivered receipt information from successfully purchased products.

Receipt Status

Status
Description
Re-trigger Eligibility

NotProcessedYet

Product Undelivered

May be triggered again depending on trigger conditions

PurchaseGranted

Product Delivered

Not triggered again

Trigger Conditions

  • When a world product is successfully purchased (the successful purchase popup is shown to the user),

    • if there are any undelivered products, those previous pending items will also be triggered together when the new purchase is made.

  • When the user connects (or reconnects) to the server

How to Update Delivery Status

  • After successfully delivering the product, return Enum.ProductPurchaseDecision.PurchaseGranted.

Important Notes

  • The ProcessReceipt event should be connected only once in a server-side script.

  • This callback can yield indefinitely and remains valid until it receives a response, as long as the server is running.

  • If there are multiple undelivered receipts, each one will be triggered individually, and the order of these callbacks is non-deterministic.

  • The callback will only be triggered when the user is present on the server.

    • However, the result of the callback may still be recorded on the backend even if the user is no longer on the server.

  • Returning PurchaseGranted from the callback does not guarantee that the backend will successfully record it. In such cases, the receipt status remains unchanged (remains undelivered).

  • Products in an undelivered state will have their funds held in an Escrow state.

local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")

local ProductDeliverer = {}

-----------------------------------------------------------------------------
-- You can define a function for each product ID in a table as shown below to 
-- implement custom delivery logic for each product.
ProductDeliverer[Enter the product number here.] = function(player)
    local success, resultOrError = pcall(function()
        -- Deliver the product to the player and handle saving using DataStore
        
        -- Tip.
        -- When saving product information using DataStore
        -- it's recommended to use IncrementAsync or UpdateAsync
        -- to prevent network conflicts or race conditions.
                
        -- Return "true" when the product has been successfully delivered and saved
        return true
    end)
    
    if success and resultOrError then
        return true
        
    else
        return false, resultOrError
    end
end

-----------------------------------------------------------------------------
-- Callback for handling the receipt triggered after a successful product purchase
local function OnProcessReceipt(receiptInfo)	
    -- Receipt information
    local success, error = pcall(function()	
        print("PurchaseId: " .. receiptInfo.PurchaseId)
        print("UserId: " .. receiptInfo.PlayerId)
        print("ProductId: " .. receiptInfo.ProductId)
        print("CurrencySpent: " .. receiptInfo.CurrencySpent)
        print("PurchaseDateTime: " .. receiptInfo.PurchaseDateTime)
    end)
    
    if not success then
        print("Error: " .. tostring(error))
        return Enum.ProductPurchaseDecision.NotProcessedYet
    end
    
    -- If the player is valid 
    local productId = receiptInfo.ProductId        
    local userId = receiptInfo.PlayerId
    
    local player = Players:GetPlayerByUserId(userId)  
    if player == nil then
        print("Error: player is nil")
        return Enum.ProductPurchaseDecision.NotProcessedYet	
    end  
    
    -- Trigger the product delivery function
    local delivererFunc = ProductDeliverer[productId]
    local success, error = delivererFunc(player)
    
    -- If the product is successfully delivered
    if success then
        -- Return the status as delivered
        print("Item delivery successful / ProductId : " .. productId)
        return Enum.ProductPurchaseDecision.PurchaseGranted
        
    -- If product delivery fails
    else
        print("Error: " .. tostring(error))
        return Enum.ProductPurchaseDecision.NotProcessedYet
    end
end
MarketplaceService.ProcessReceipt = OnProcessReceipt

Test Purchase

You can test product purchases and delivery in Studio's playtest environment. (Currency will not be deducted.)

Sales Stat

Coming soon.

Revenue

Share Revenue

Coming soon.

Revenue Payout

Coming soon.

Usage Examples

  • You can drive purchases and increase revenue by separating free and paid in-game currency, adding value to the paid currency, and offering it as a world product.

  • Offering higher-quality skins as world products can tap into players' desire to customize their look, which may lead to purchases.

  • Bundling weapons, potions, and currency into value packs can boost conversion rates by offering more value than individual purchases.

  • Selling consumable items like instant revives during combat as world products helps keep the gameplay smooth while promoting purchases naturally.

  • Long-term offerings like a season pass can increase both user retention and revenue.

  • Instead of focusing only on paid items, offering a reasonable selection of free content helps build user satisfaction and trust, leading to more organic purchases.

Last updated