> For the complete documentation index, see [llms.txt](https://docs.overdare.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.overdare.com/development/api-reference/classes/marketplaceservice.md).

# MarketplaceService

MarketplaceService : `Instance`

## Overview

MarketplaceService is a service responsible for handling in-world product purchases and processing delivery upon successful payment.

Creators must define the ProcessReceipt callback function to ensure that deliveries are not missed when a product is sold, and are responsible for using DataStore or similar mechanisms to make sure deliveries complete successfully.

## Properties

### ProcessReceipt

`Value`

A callback function that processes undelivered receipts from successfully purchased products.

#### Code Samples

## Methods

### GetProductInfo

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

#### Parameters

| `number` ProductId       | The ID of the product.   |
| ------------------------ | ------------------------ |
| `Enum.InfoType` InfoType | The type of the product. |

#### Return

| `Value` | <p>A dictionary containing the product information.</p><ul><li><code>string</code> Name: Product name</li><li><code>string</code> Description: Product description</li><li><code>number</code> ProductId: Product ID</li><li><code>string</code> ProductType: Product type</li><li><code>number</code> PriceInBLUC: Product price</li><li><code>number</code> Created: Time the product was created (UNIX timestamp)</li><li><code>number</code> Updated: Time the product was last updated (UNIX timestamp)</li></ul> |
| ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

#### Code Samples

```lua
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)
    end
end
```

### GetWorldProductsAsync

Returns a Pages object containing information about all world products.

#### Parameters

#### Return

| `Pages` | An object containing information about every world product in the current world. |
| ------- | -------------------------------------------------------------------------------- |

#### Code Samples

```lua
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)
            end
        end
    end
end
```

### PromptProductPurchase

Requests the purchase of the product corresponding to the world product ID (productId). (A purchase window is displayed through the system UI.)

#### Parameters

| `Player` Player    | The Player who will purchase the product. |
| ------------------ | ----------------------------------------- |
| `number` ProductId | The world product ID.                     |

#### Return

| `void` |   |
| ------ | - |

#### Code Samples

```lua
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
```

## Events

### PromptProductPurchaseFinished

This event is triggered when the purchase window opened by a purchase request (PromptProductPurchase) is closed. If the purchase succeeds, `true` is passed to isPurchased; if the user cancels or the purchase fails, `false` is passed.

This event should only be used to detect whether the purchase window has been closed. <mark style="color:red;">**It must never be used to process delivery for purchased products.**</mark>

#### Parameters

| `string` UserId     | The UserId of the Player who requested the purchase. |
| ------------------- | ---------------------------------------------------- |
| `number` ProductId  | The ID of the requested product.                     |
| `bool` bIsPurchased | Whether the purchase succeeded.                      |

#### Code Samples

```lua
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)
```

## Callback

### ProcessReceipt

An event is triggered that returns information about **undelivered receipts** among successfully purchased products.

**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.

#### Parameters

| `table` Receipt | <p>A dictionary containing the receipt information for a successfully purchased product.</p><ul><li><code>string</code> PurchaseId: Receipt ID</li><li><code>string</code> PlayerId: The Player's UserId</li><li><code>number</code> ProductId: Product ID</li><li><code>number</code> CurrencySpent: Amount of currency spent on the transaction</li><li><code>number</code> PurchaseDateTime: Time the product was purchased (UNIX timestamp)</li></ul> |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

#### Return

| `Enum.ProductPurchaseDecision` | <p>The delivery status of the world product.</p><ul><li>PurchaseGranted: The product has been successfully delivered to the Player.</li><li>NotProcessedYet: The product has not yet been delivered.</li></ul> |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

#### Code Samples

```lua
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
```

## See also

{% content-ref url="/pages/9Hau8mThHVEcQwyAQ829" %}
[World Product Sales](/manual/monetization/marketplace.md)
{% endcontent-ref %}
