MarketplaceService
MarketplaceService is responsible for in-experience transactions. The most notable methods are PromptProductPurchase and PromptPurchase, as well as the callback ProcessReceipt which must be defined so that developer product transactions do not fail.
MarketplaceService also has methods that fetch information about developer products (GetProductInfo and GetDeveloperProductsAsync), passes (UserOwnsGamePassAsync), and other assets (PlayerOwnsAsset, PlayerOwnsBundle).
Understanding MarketplaceService is the first step towards learning to monetize an experience on Roblox, as well as learning to use DataStoreService, which is responsible for saving and loading all data related to purchases.
Podsumowanie
Metody
Prompts a user to purchase multiple avatar items with the given assetId or bundleId.
Prompts a user to purchase a bundle with the given bundleId.
Prompts a user to cancel a subscription for the given subscriptionId.
Prompts a user to purchase a pass with the given gamePassId.
Prompts a user to purchase Roblox Premium.
- PromptProductPurchase(player : Instance,productId : number,equipIfPurchased : bool,currencyType : Enum.CurrencyType):void
Prompts a user to purchase a developer product with the given productId.
- PromptPurchase(player : Instance,assetId : number,equipIfPurchased : bool,currencyType : Enum.CurrencyType):void
Prompts a user to purchase an item with the given assetId. Does not work for USD Creator Store purchases.
Prompts a user to purchase a subscription for the given subscriptionId.
Returns a Pages object which contains information for all of the current experience's developer products.
Returns the product information of an asset using its asset ID.
Returns the product information of a subscription for the given subscriptionId.
Returns a table that contains the details of the user's subscription for a given subscriptionId.
Returns an Array that contains up to one year of the user's subscription payment history for the given subscriptionId.
Returns a table that contains the subscription status of the user for the given subscriptionId.
Returns whether the given user has the given asset.
Returns whether the given player owns the given bundle.
Returns true if the player with the given UserId owns the pass with the given gamePassId.
Zdarzenia
- PromptBulkPurchaseFinished(player : Instance,status : Enum.MarketplaceBulkPurchasePromptStatus,results : Dictionary):RBXScriptSignal
Fires when a purchase prompt for bulk avatar items is closed.
- PromptBundlePurchaseFinished(player : Instance,bundleId : number,wasPurchased : bool):RBXScriptSignal
- PromptGamePassPurchaseFinished(player : Instance,gamePassId : number,wasPurchased : bool):RBXScriptSignal
Fires when a purchase prompt for a pass is closed.
Fires when a purchase prompt for Roblox Premium is closed.
- PromptProductPurchaseFinished(userId : number,productId : number,isPurchased : bool):RBXScriptSignal
Fires when a purchase prompt for a developer product is closed. Do not use this event to process purchases.
Fires when a purchase prompt for an affiliate gear sale or other asset is closed. Does not fire for developer product or pass prompts.
- PromptSubscriptionPurchaseFinished(user : Player,subscriptionId : string,didTryPurchasing : bool):RBXScriptSignal
Fires when a purchase prompt for a subscription is closed.
Wywołania zwrotne
A callback to process receipts of developer product purchases.
Właściwości
Metody
PromptBulkPurchase
Prompts a user to purchase multiple avatar items with the given assetId or bundleId. Does not work with non-avatar items.
PromptBulkPurchase only allows prompting from server scripts.
For limited items, original copies are prompted until they run out, regardless of the price. Once original copies are out, resale copies are prompted.
A maximum of 20 items can be added to a single bulk purchase prompt.
Parametry
The user to prompt to purchase items.
An array of avatar items to be included in the bulk purchase.
Each line item contains the following structure:
{Type: MarketplaceProductType,Id: string}
Each line item contains the following pairs:
- Type: The corresponding Enum.MarketplaceProductType (Enum).
- Id: The ID of the asset or bundle.
Not available at this time.
Zwroty
Przykłady kodu
The following sample prompts players to buy "Beautiful Hair for Beautiful People" and "Blue Collar Cat" when they join the experience.
Place this LocalScript somewhere on the client such as within Players -> StarterPlayerScripts so that it will be able to fire a remote event signal from a client to the server.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local promptBulkPurchaseEvent = ReplicatedStorage:WaitForChild("PromptBulkPurchaseEvent")
local part = Instance.new("Part")
part.Parent = workspace
local clickDetector = Instance.new("ClickDetector")
clickDetector.Parent = part
clickDetector.MouseClick:Connect(function()
promptBulkPurchaseEvent:FireServer(
{
{ Type = Enum.MarketplaceProductType.AvatarAsset, Id = "16630147" },
{ Type = Enum.MarketplaceProductType.AvatarBundle, Id = "182" }
})
end)
The following code is listening for a RemoteEvent.OnServerEvent to fire to the Server from a Client. Place this script somewhere on the server such as within ServerStorage.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local promptBulkPurchaseEvent = Instance.new("RemoteEvent")
promptBulkPurchaseEvent.Name = "PromptBulkPurchaseEvent"
promptBulkPurchaseEvent.Parent = ReplicatedStorage
--Listen for the RemoteEvent to fire from a Client and then trigger the bulk purchase prompt
promptBulkPurchaseEvent.OnServerEvent:Connect(function(player, items)
MarketplaceService:PromptBulkPurchase(player, items, {})
end)
PromptBundlePurchase
Prompts a user to purchase a bundle with the given bundleId.
Parametry
Zwroty
PromptCancelSubscription
Prompts a user to cancel a subscription for the given subscriptionId. Once the user successfully cancels the subscription, the Players.UserSubscriptionStatusChanged event fires.
Parametry
Zwroty
PromptGamePassPurchase
Prompts a user to purchase a pass with the given gamePassId.
Parametry
Zwroty
PromptPremiumPurchase
Prompts a user to purchase Roblox Premium. To learn more about Premium and about incorporating Premium incentives into your experience, see Engagement-based payouts.
See also
- MarketplaceService.PromptPremiumPurchaseFinished which fires when the Premium purchase UI closes.
- Players.PlayerMembershipChanged which fires when the server recognizes that a user's membership has changed.
Parametry
The user being prompted to purchase Premium.
Zwroty
Przykłady kodu
The following code prompts users to purchase Premium when their character touches the part that its containing Script is attached to, such as a teleporter that allows access to an exclusive area.
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local teleporter = script.Parent
local showModal = true
local TELEPORT_POSITION = Vector3.new(1200, 200, 60)
-- Teleport character to exclusive area
local function teleportPlayer(player)
-- Request streaming around target location
player:RequestStreamAroundAsync(TELEPORT_POSITION)
-- Teleport character
local character = player.Character
if character and character.Parent then
local currentPivot = character:GetPivot()
character:PivotTo(currentPivot * CFrame.new(TELEPORT_POSITION))
end
end
-- Detect character parts touching teleporter
teleporter.Touched:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if not player then return end
if not player:GetAttribute("CharacterPartsTouching") then
player:SetAttribute("CharacterPartsTouching", 0)
end
player:SetAttribute("CharacterPartsTouching", player:GetAttribute("CharacterPartsTouching") + 1)
if player.MembershipType == Enum.MembershipType.Premium then
-- User has Premium; teleport character to exclusive area within experience
teleportPlayer(player)
else
-- Show purchase modal, using debounce to show once every few seconds at most
if not showModal then return end
showModal = false
task.delay(5, function()
showModal = true
end)
MarketplaceService:PromptPremiumPurchase(player)
end
end)
-- Detect character parts exiting teleporter
teleporter.TouchEnded:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player and player:GetAttribute("CharacterPartsTouching") then
player:SetAttribute("CharacterPartsTouching", player:GetAttribute("CharacterPartsTouching") - 1)
end
end)
-- Handle membership changed event
Players.PlayerMembershipChanged:Connect(function(player)
warn("User membership changed; new membership is " .. tostring(player.MembershipType))
-- Teleport character if membership type is Premium and character is on teleporter
if player.MembershipType == Enum.MembershipType.Premium and player:GetAttribute("CharacterPartsTouching") > 0 then
teleportPlayer(player)
end
end)
PromptProductPurchase
Prompts a user to purchase a developer product with the given productId.
Parametry
Zwroty
Przykłady kodu
The following example illustrates how to prompt purchase of a developer product with the PromptProductPurchase() method. Depending on the needs of your experience, you can call the promptPurchase() function in situations such as when the player presses a button or when their character talks to a vendor NPC.
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local productId = 0000000 -- Change this to your developer product ID
-- Function to prompt purchase of the developer product
local function promptPurchase()
MarketplaceService:PromptProductPurchase(player, productId)
end
promptPurchase()
PromptPurchase
Prompts a user to purchase an item with the given assetId. This does not work for USD Creator Store purchases. If prompting a purchase of a limited item:
- (Recommended) Server requests prompt original copies until they run out, regardless of the price. Once original copies run out, resale copies are prompted.
- Client requests prompt from the lowest resale price even if original copies are available.
Parametry
Ignored.
Zwroty
Przykłady kodu
The below example would prompt all new players to buy Beautiful Hair for Beautiful People when they click on a part.
Place this LocalScript somewhere on the Client such as within Players -> StarterPlayerScripts so that it will be able to fire a RemoteEvent:FireServer() signal from a Client to the Server.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local promptPurchaseEvent = ReplicatedStorage:WaitForChild("PromptPurchaseEvent")
local part = Instance.new("Part")
part.Parent = workspace
local clickDetector = Instance.new("ClickDetector")
clickDetector.Parent = part
clickDetector.MouseClick:Connect(function()
promptPurchaseEvent:FireServer(16630147)
end)
Since the below code is listening for a RemoteEvent.OnServerEvent to fire to the Server from a Client. Place this script somewhere on the Server such as within ServerStorage.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local promptPurchaseEvent = Instance.new("RemoteEvent")
promptPurchaseEvent.Name = "PromptPurchaseEvent"
promptPurchaseEvent.Parent = ReplicatedStorage
-- Listen for the RemoteEvent to fire from a Client and then trigger the purchase prompt
promptPurchaseEvent.OnServerEvent:Connect(function(player, id)
MarketplaceService:PromptPurchase(player, id)
end)
PromptSubscriptionPurchase
Prompts a user to purchase a subscription for the given subscriptionId.
Parametry
The ID of the subscription to subscribe to.
Zwroty
GetDeveloperProductsAsync
Returns a Pages object which contains information for all of the current experience's developer products.
Zwroty
Przykłady kodu
The below example would print the name, price, ID, description and icon AssetId for all of the developer products which belong to the current game.
local MarketplaceService = game:GetService("MarketplaceService")
local developerProducts = MarketplaceService:GetDeveloperProductsAsync():GetCurrentPage()
for _, developerProduct in pairs(developerProducts) do
for field, value in pairs(developerProduct) do
print(field .. ": " .. value)
end
print(" ")
end
GetProductInfo
This method provides information about an asset, developer product, or pass based on the asset ID and the Enum.InfoType. If an item with the given ID does not exist, this method throws an error.
Information about the queried item is provided in a dictionary with the following keys. Note that not all information is provided or necessarily relevant for the kind of product you're querying.
Key | Type | Description |
---|---|---|
Name | string | The name shown on the asset's page. |
Description | string | The description shown on the asset's page; can be nil if blank. |
PriceInRobux | number | The cost of purchasing the asset using Robux. |
Created | string | Timestamp of when the asset was created, for example 2022-01-02T10:30:45Z. Formatted using ISO 8601. |
Updated | string | Timestamp of when the asset was last updated by its creator, for example 2022-02-12T11:22:15Z. Formatted using ISO 8601. |
ContentRatingTypeId | number | Indicates whether the item is marked as 13+ in catalog. |
MinimumMembershipLevel | number | The minimum subscription level necessary to purchase the item. |
IsPublicDomain | boolean | Describes whether the asset can be taken for free. |
Creator Information
Key | Type | Description |
---|---|---|
Creator | table | Dictionary table of information describing the creator of the asset (see following lines). |
Creator.CreatorType | string | Either User or Group. |
Creator.CreatorTargetId | number | The ID of the creator user or group. |
Creator.HasVerifiedBadge | boolean | Whether the creator has a verified badge. |
Creator.Name | string | The name/username of the creator. |
Creator.Id | number | Use Creator.CreatorTargetId instead. |
Asset Information
Key | Type | Description |
---|---|---|
AssetId | number | The asset ID if Enum.InfoType is Asset. |
AssetTypeId | number | The type of asset. See Enum.AssetType for the asset type ID numbers. |
IsForSale | boolean | Describes whether the asset is purchasable. |
IsLimited | boolean | Describes whether the asset is a Roblox Limited that is no longer (if ever) sold. |
IsLimitedUnique | boolean | Describes whether the asset is a unique Roblox Limited ("Limited U") item that only has a fixed number sold. |
IsNew | boolean | Describes whether the asset is marked as "new" in the catalog. |
Remaining | number | The remaining number of items a limited unique item may be sold. |
Sales | number | The number of items the asset has been sold. |
SaleAvailabilityLocations | table | The item's ProductLocationRestriction or sale location setting. |
CanBeSoldInThisGame | boolean | Describes whether the asset is purchasable in the current experience. |
Developer Products and Passes
Key | Type | Description |
---|---|---|
ProductId | number | The product ID if Enum.InfoType is Product. |
IconImageAssetId | number | The asset ID of the product/pass icon, or 0 if there isn't one. |
Parametry
The asset ID of the specified product.
An Enum.InfoType enum value specifying the type of information being retrieved.
Zwroty
A dictionary containing information about the queried item, described in the previous tables.
Przykłady kodu
The below example will print the name and description of the asset with an ID of 125378389. In this case it will print: "Mr. Fancy Top Hat :: So fancy that even his top hat's top hat has a top hat."
local MarketplaceService = game:GetService("MarketplaceService")
local ASSET_ID = 125378389
local asset = MarketplaceService:GetProductInfo(ASSET_ID)
print(asset.Name .. " :: " .. asset.Description)
GetSubscriptionProductInfoAsync
Note: Because it returns a localized price, you can only call this method from a Script with Enum.RunContext.Client.
Returns the product information of a subscription for the given subscriptionId.
Key | Type | Description |
---|---|---|
Name | string | The name of the subscription product. |
Description | string | The description of the subscription product. |
IconImageAssetId | number | The asset ID of the subscription product icon. |
SubscriptionPeriod | Enum.SubscriptionPeriod | The duration of the subscription (for example, Month, Year, etc.). |
DisplayPrice | string | Localized price with the appropriate currency symbol for display (for example, $4.99). For users in unsupported countries, DisplayPrice returns a string without specific price information. |
DisplaySubscriptionPeriod | string | Localized subscription period text for display (for example, /month). Can be used together with DisplayPrice. |
SubscriptionProviderName | string | Name of the subscription benefit provider (for example, the name of the associated experience). |
IsForSale | boolean | True if the subscription product is available for sale. |
PriceTier | number | A number that can be used to compare the price of different subscription products. This is not the actual price of the subscription (for example, 499). |
Parametry
The ID of the subscription to check.
Zwroty
GetUserSubscriptionDetailsAsync
Returns a dictionary table containing the details of the user's subscription for the given subscriptionId. The table contains the following keys:
Key | Type | Description |
---|---|---|
SubscriptionState | Enum.SubscriptionState | Current state of this particular subscription. |
NextRenewTime | DateTime | Renewal time for this current subscription. May be in the past if the subscription is in SubscribedRenewalPaymentPending state. This field is will be nil if the subscription will not renew, is Expired, or the user never subscribed. |
ExpireTime | DateTime | When this subscription expires. This field will be nil if the subscription is not cancelled or the user never subscribed. |
ExpirationDetails | table | Table containing the details of the subscription expiration. This field will be nil if the subscription is not in the Expired state. If populated, the table contains a ExpirationReason key of type Enum.SubscriptionExpirationReason describing why the subscription is expired. |
Note that this method can only be called from a Script with RunContext of Server. If you only need to determine the IsSubscribed status of a user, it's recommended to use GetUserSubscriptionStatusAsync as it is faster and more efficient for that particular purpose.
Parametry
The ID of the subscription to check.
Zwroty
GetUserSubscriptionPaymentHistoryAsync
Note: You can only call this method from a Script with Enum.RunContext.Server.
Returns an Array that contains up to one year of the user's subscription payment history for the given subscriptionId, sorted from the most recent status to the least recent.
Each entry in the payment history Array contains the following keys:
Key | Type | Description |
---|---|---|
CycleStartTime | DateTime | DateTime at the start of this particular subscription period. |
CycleEndTime | DateTime | DateTime at the end of this particular subscription period. |
PaymentStatus | Enum.SubscriptionPaymentStatus | Enum.SubscriptionPaymentStatus.Paid if the user paid for this particular subscription period. Enum.SubscriptionPaymentStatus.Refunded if the user refunded this particular subscription period. |
Payment History Length
Only creators affiliated with the subscription product can access up to one year worth of the user's subscription payment history. Non-associated creators can only get the user's current subscription payment status or an empty Array if the user has no active subscription.
Grace Period
Subscription renewal payments can have some processing time. Payment history doesn't return a table for this period. However, in order to preserve a user's subscription experience during the processing period, GetUserSubscriptionStatusAsync returns IsSubscribed: true for the given user. Don't grant durable items or currency type subscription benefits to the user until after payment has been confirmed for the current cycle.
For example, on August 31, 2023, User A's Subscription B is up for renewal. On September 1, 2023, the payment has yet to be processed. If you call GetUserSubscriptionPaymentHistoryAsync on September 1, 2023 on User A for Subscription B, the first entry of the return value is:
Key | Value |
---|---|
CycleStartTime | ... |
CycleEndTime | August 31, 2023 |
PaymentStatus | Enum.SubscriptionPaymentStatus.Paid |
Note that since the user is within the grace period, the cycle they have yet to pay for (September 1, 2023) does not appear in the return value at all. This field only populates after the payment has been received and processed.
At the same time, GetUserSubscriptionStatusAsync returns the following result until the renewal payment process fails or the user cancels:
Key | Return |
---|---|
IsSubscribed | True |
IsRenewing | True |
Parametry
Zwroty
Przykłady kodu
This code sample demonstrates how to check the last 12 months of a user's payment history for a given subscription ID. Rather than the raw values, it prints formatted values for easier readability. Roblox Studio includes several subscription IDs for testing purposes:
- EXP-0 represents an active and renewing subscription.
- EXP-1 represents a returning subscription.
- EXP-2 represents a refunded subscription. Depending on your subscription benefits, refunds can require special handling, so testing for this case is particularly useful.
- EXP-3 represents an active subscription that is pending successful payment for the current cycle. Continued failure to pay results in automatic cancellation of the subscription.
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local SUBSCRIPTION_ID = "EXP-0"
local function checkSubscriptionHistory(player: Player)
local subscriptionHistory = {}
local success, err = pcall(function()
subscriptionHistory = MarketplaceService:GetUserSubscriptionPaymentHistoryAsync(player, SUBSCRIPTION_ID)
end)
if not success then
warn(`Error while checking subscription history: {err}`)
return
end
if next(subscriptionHistory) then
-- User has some subscription history within the past 12 months.
-- Print the details of each payment entry from the subscription history.
print(`Player {player.Name} has subscribed to {SUBSCRIPTION_ID} before:`)
for entryNum, paymentEntry in subscriptionHistory do
local paymentStatus = tostring(paymentEntry.PaymentStatus)
local cycleStartTime = paymentEntry.CycleStartTime:FormatLocalTime("LLL", "en-us")
local cycleEndTime = paymentEntry.CycleEndTime:FormatLocalTime("LLL", "en-us")
print(`{entryNum}: {paymentStatus} ({cycleStartTime} - {cycleEndTime})`)
end
else
print(`Player {player.Name} has never subscribed to {SUBSCRIPTION_ID} before.`)
end
end
-- Call checkSubscriptionHistory for any players already in the game
for _, player in ipairs(Players:GetPlayers()) do
checkSubscriptionHistory(player)
end
-- Call checkSubscriptionHistory for all future players
Players.PlayerAdded:Connect(checkSubscriptionHistory)
GetUserSubscriptionStatusAsync
Returns a table that contains the subscription status of the user for the given subscriptionId. The table contains the following keys:
Key | Type | Description |
---|---|---|
IsSubscribed | boolean | True if the user's subscription is active. |
IsRenewing | boolean | True if the user is set to renew this subscription after the current subscription period ends. |
Note that IsSubscribed will be true only when a user has purchased the subscription and the payment has been successfully processed. If the payment for a user's initial subscription purchase is still processing or has failed, IsSubscribed returns false. To understand when a user's subscription status has changed, see the Players.UserSubscriptionStatusChanged event.
Parametry
The ID of the subscription to check for.
Zwroty
Przykłady kodu
This code sample demonstrates how to check the subscription status of a user for a certain subscription. As a user enters the game, their account is checked for the status of that subscription and a message is printed.
Notice how the call to GetUserSubscriptionStatusAsync is wrapped in pcall - this prevents the code from throwing an error in case the user's subscription status can't be checked for some reason. Should such an error occur, the success variable would be false.
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local subscriptionID = "EXP-00000"
local function checkSubStatus(player)
local subStatus = {}
local success, message = pcall(function()
-- returns IsRenewing and IsSubscribed
subStatus = MarketplaceService:GetUserSubscriptionStatusAsync(player, subscriptionID)
end)
if not success then
warn("Error while checking if player has subscription: " .. tostring(message))
return
end
if subStatus["IsSubscribed"] then
print(player.Name .. " is subscribed with " .. subscriptionID)
-- Give player permissions associated with the subscription
end
end
Players.PlayerAdded:Connect(checkSubStatus)
PlayerOwnsAsset
Returns whether the inventory of a specific user contains an asset, based on the asset ID. This method throws an error if the query fails, so you should wrap calls to this method in pcall().
- This method should not be used for passes since they use a separate ID system. Legacy passes that still depend on an asset ID should use UserOwnsGamePassAsync instead of this method.
- This method cannot be used to check for developer products since they can be purchased multiple times but not owned themselves. Instead, use a data store to save when a user buys a developer product.
Parametry
The asset ID for which the given player's inventory is tested.
Zwroty
Indicates whether the given player's inventory contains the given asset.
Przykłady kodu
This code sample demonstrates how to check if a player owns a certain item. Here, we're checking for the item Midnight Shades, a hat that costs R$ 250. As a player enters the game, their account is checked for the ownership of that item and a message is printed.
Notice how the call to PlayerOwnsAsset is wrapped in pcall - this prevents the code from throwing an error in case the player's inventory can't be checked for some reason. Should such an error occur, the success variable would be false.
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
-- The item we're checking for: https://www.roblox.com/catalog/30331986/Midnight-Shades
local ASSET_ID = 30331986
local ASSET_NAME = "Midnight Shades"
local function onPlayerAdded(player)
local success, doesPlayerOwnAsset = pcall(MarketplaceService.PlayerOwnsAsset, MarketplaceService, player, ASSET_ID)
if not success then
local errorMessage = doesPlayerOwnAsset
warn(`Error checking if {player.Name} owns {ASSET_NAME}: {errorMessage}`)
return
end
if doesPlayerOwnAsset then
print(`{player.Name} owns {ASSET_NAME}`)
else
print(`{player.Name} doesn't own {ASSET_NAME}`)
end
end
Players.PlayerAdded:Connect(onPlayerAdded)
PlayerOwnsBundle
Returns whether the inventory of a specific user contains a bundle, based on the bundle ID. This method throws an error if the query fails, so you should wrap calls to this method in pcall().
Parametry
The bundle ID for which the given player's inventory is tested.
Zwroty
Indicates whether the given player's inventory contains the given bundle.
Przykłady kodu
This code sample demonstrates how to check if a player owns a certain bundle. Here, we're checking for the bundle Junkbot. As a player enters the game, their account is checked for the ownership of that item and a message is printed.
Notice that a pcall() wraps the call to MarketplaceService:PlayerOwnsBundle() to prevent the code from throwing an error in case the player's inventory can't be checked. If such an error occurs, the success variable is false.
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
-- The bundle we're checking for: https://www.roblox.com/bundles/589/Junkbot
local BUNDLE_ID = 589
local BUNDLE_NAME = "Junkbot"
Players.PlayerAdded:Connect(function (player)
local success, doesPlayerOwnBundle = pcall(function()
return MarketplaceService:PlayerOwnsBundle(player, BUNDLE_ID)
end)
if success == false then
print("PlayerOwnsBundle call failed: ", doesPlayerOwnBundle)
return
end
if doesPlayerOwnBundle then
print(player.Name .. " owns " .. BUNDLE_NAME)
else
print(player.Name .. " doesn't own " .. BUNDLE_NAME)
end
end)
UserOwnsGamePassAsync
Returns true if the user with the given UserId owns the pass with the given gamePassId (not to be confused with an asset ID).
Caching Behavior
The results of this function are remembered so that repeated calls are returned faster.
This function always returns true when the user first enters a server after purchasing the pass.
If the user has purchased the pass inside an experience through PromptGamePassPurchase, the UserOwnsGamePassAsync function might return false because of caching behavior. Alternatively, the function might return true even after the user has deleted the pass from their inventory.
Parametry
The pass ID you want to check for. Not to be confused with an asset ID.
Zwroty
Zdarzenia
PromptBulkPurchaseFinished
This event fires when a purchase prompt for a bulk avatar items closes. For example, when a user receives the purchase prompt and clicks Cancel, or when they receive a success or error message and click OK.
Note: This is not a trusted event from the client. To check if the user owns the items purchased, use MarketplaceService.PlayerOwnsAsset or MarketplaceService.PlayerOwnsBundle.
Parametry
The status of the bulk purchase.
The table type containing the line items and their status in the following format:
{RobuxSpent: numberItems: {{type: MarketplaceProductType,id: string,status: MarketplaceItemPurchaseStatus},...}}
Each line item contains the following pairs:
- type: The corresponding Enum.MarketplaceProductType (Enum).
- id: The ID of the asset or bundle (string).
- status: The Enum.MarketplaceItemPurchaseStatus of the purchase (Enum)
PromptGamePassPurchaseFinished
This event fires when a purchase prompt for a pass closes. For example, when a user receives the purchase prompt and clicks Cancel, or when they receive a success or error message and click OK.
See also
- For repeatable developer product purchase prompts, use PromptProductPurchaseFinished.
- For affiliate gear sales or other assets, use PromptPurchaseFinished.
- For more information on saving and replicating user data like purchases and progress, see Implementing player data and purchases.
Parametry
The ID number of the pass shown in the prompt. Not to be confused with an asset ID.
Indicates if the user pressed OK (true), Cancel (false) on the purchase prompt, or if the purchase prompt errored (false).
This might not accurately reflect if the purchase itself has been successfully processed. Use MarketplaceService.UserOwnsGamePassAsync|UserOwnsGamePassAsync as ownership confirmation.
Przykłady kodu
local MarketplaceService = game:GetService("MarketplaceService")
local function gamepassPurchaseFinished(...)
-- Print all the details of the prompt, for example:
-- PromptGamePassPurchaseFinished PlayerName 123456 false
print("PromptGamePassPurchaseFinished", ...)
end
MarketplaceService.PromptGamePassPurchaseFinished:Connect(gamepassPurchaseFinished)
PromptPremiumPurchaseFinished
This event fires when a purchase prompt for Roblox Premium closes. For example, when a user receives the purchase prompt and clicks Cancel, or when they receive a success or error message and click OK.
See also
- PromptPremiumPurchase to prompt a user to purchase Premium.
- PlayerMembershipChanged, which fires when the server recognizes that a user's membership has changed.
PromptProductPurchaseFinished
IMPORTANT: Do not use the PromptProductPurchaseFinished event to process purchases; instead, use the ProcessReceipt callback. The firing of PromptProductPurchaseFinished does not mean that a user has successfully purchased an item.
This event fires when a purchase prompt for a developer product closes. For example, when a user receives the purchase prompt and clicks Cancel, or when they receive a success or error message and click OK. The firing of this event does not mean that a user has successfully purchased an item.
While you can use the PromptProductPurchaseFinished event to detect when a user closes a purchase prompt, you should not use it to process purchases because those purchases might still fail in the backend for several reasons. For example, if a Roblox system is offline, or if the product price has changed and the user now doesn't have enough Robux to make the purchase. To process purchases, you must use ProcessReceipt. Using ProcessReceipt allows you to confirm that the purchase has succeeded before you grant the user the item they have purchased.
The PromptProductPurchaseFinished event fires with a Player.UserId instead of a reference to the Player object.
See also
- PromptGamePassPurchaseFinished to prompt a user to purchase a pass.
- PromptPurchaseFinished to prompt a user to purchase affiliate gear or other assets.
- For more information on saving and replicating user data like purchases and progress, see Implementing player data and purchases.
Parametry
The ID number of the developer product shown in the prompt. Not to be confused with an asset ID.
Indicates if the user pressed OK (true), Cancel (false) on the purchase prompt, or if the purchase prompt errored (false).
Do not use this parameter to process developer product purchases.
PromptPurchaseFinished
This event fires when a purchase prompt for an affiliate gear sale or other asset closes. For example, when a user receives the purchase prompt and clicks Cancel, or when they receive a success or error message and click OK.
This event does not fire for developer product or pass prompts.
See also
- PromptGamePassPurchaseFinished to prompt a user to purchase a pass.
- PromptProductPurchaseFinished to prompt a user to purchase a developer product.
- For more information on saving and replicating user data like purchases and progress, see Implementing player data and purchases.
Parametry
The asset ID of the item shown in the prompt.
Indicates if the user pressed OK (true), Cancel (false) on the purchase prompt, or if the purchase prompt errored (false).
This might not accurately reflect if the purchase itself has been successfully processed.
Przykłady kodu
The below example would print 'Telamon bought an item with AssetID: 1111' to the output, if they were to complete a transaction in (your) game with an item that had an AssetID of 1111. Alternatively, it would print 'Telamon didn't buy an item with AssetID: 1111' if the opposite was true.
local MarketplaceService = game:GetService("MarketplaceService")
local function onPromptPurchaseFinished(player, assetId, isPurchased)
if isPurchased then
print(player.Name, "bought an item with AssetID:", assetId)
else
print(player.Name, "didn't buy an item with AssetID:", assetId)
end
end
MarketplaceService.PromptPurchaseFinished:Connect(onPromptPurchaseFinished)
PromptSubscriptionPurchaseFinished
This event fires when a purchase prompt for an affiliate gear sale or other asset closes. For example, when a user receives the purchase prompt and clicks Cancel, or when they receive a success or error message and click OK.
See also
- PromptSubscriptionPurchase to prompt a user to purchase a subscription.
- UserSubscriptionStatusChanged, which fires when the server recognizes that a user's membership has changed.
Parametry
The ID of the subscription with a status change.
Whether the user attempted to purchase the subscription.
Wywołania zwrotne
ProcessReceipt
IMPORTANT: We highly recommend that you properly implement the ProcessReceipt callback in order to sell your developer products. You should use ProcessReceipt to grant users their purchased product over any other granting method. If your ProcessReceipt implementation isn't correct, you will not be able to grant users the products they have purchased on the Store tab of your experience details page.
A callback to process receipts from developer product purchases. You can sell developer products inside an experience using MarketplaceService functions, or outside an experience on the Store tab of your experience details page.
You should only set the ProcessReceipt callback one time in a single server-side Script. This callback must handle the receipts for all developer products you have for sale.
Guarantees
The ProcessReceipt callback is called for all unresolved developer product purchases when:
- A user successfully completes the purchase of a developer product.
- A successful developer product purchase prompt appears to the user.
- A user joins the server.
A purchase is considered successfully initiated when:
- The purchase is processed on Roblox's backend.
- The funds are placed in escrow.
A purchase is considered resolved when:
- The purchase is successfully recorded on Roblox's backend.
Unresolved developer product purchases
An unresolved developer product purchase takes place when a user's purchase of a developer product has not yet been acknowledged by the server through the ProcessReceipt function.
Unresolved developer product purchases are not removed or refunded after the escrow period expires.
Retries and timeouts
ProcessReceipt has no time-based retry mechanism. If a user makes a purchase that returns a Enum.ProductPurchaseDecision enum of NotProcessedYet, the ProcessReceipt callback is only called again on the same server if:
- The user successfully initiates another developer product purchase.
- The user re-joins any server under the same experience.
ProcessReceipt also has no timeout for yielded callbacks. A ProcessReceipt callback can yield for as long as the server is running, and the callback result is still accepted when the result returns.
Limitations
- When there are multiple purchases pending for a user, ProcessReceipt callbacks are called in a non-deterministic order.
- The user must be on the server for the ProcessReceipt callback to be invoked.
- The user does not have to be on the server for the result of the ProcessReceipt callback to be recorded on the backend.
- The ProcessReceipt callback for a specific purchase might run on two different servers at the same time if the user joins the second server before the callback returns on the first server.
- The ProcessReceipt callback might still fail to be recorded on the backend, even if it returns a Enum.ProductPurchaseDecision enum of PurchaseGranted. When this happens, the purchase remains unresolved.
Parametry
The receiptInfo table passed to this callback contains the following data:
- PurchaseId — A unique identifier for the specific purchase.
- PlayerId — The user ID of the user who made the purchase.
- ProductId — The ID of the purchased product.
- PlaceIdWherePurchased — The place ID in which the purchase was made. Depending on where the user is during gameplay, the purchase place's ID can be the same as or different from the current place's ID.
- CurrencySpent — The amount of currency spent in the transaction.
- CurrencyType — The type of currency spent in the purchase; always Enum.CurrencyType.Robux.
- ProductPurchaseChannel — How the user acquired the developer product. One of Enum.ProductPurchaseChannel.
Zwroty
An enum that represents how the developer product receipt was processed.
- PurchaseGranted:
- Indicates that the experience successfully granted the player the developer product.
- Indicates to Roblox that the developer product sale was successful.
- NotProcessedYet:
- Indicates that the experience failed to grant the player the developer product.
Przykłady kodu
The following code sample:
- Sets up the ProcessReceipt callback function to handle the purchase of two developer products for an experience.
- Checks for and records purchases using a GlobalDataStore called PurchaseHistory.
- Properly returns PurchaseGranted if the transaction completes successfully, or if the function detects that the purchase has already been granted using the PurchaseHistory data store.
local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
-- Data store setup for tracking purchases that were successfully processed
local purchaseHistoryStore = DataStoreService:GetDataStore("PurchaseHistory")
-- Table setup containing product IDs and functions for handling purchases
local productFunctions = {}
-- ProductId 123123 for a full heal
productFunctions[123123] = function(_receipt, player)
-- Logic for the player buying a full heal
if player.Character and player.Character:FindFirstChild("Humanoid") then
-- Heal the player to full health
player.Character.Humanoid.Health = player.Character.Humanoid.MaxHealth
-- Indicate a successful purchase
return true
end
end
-- ProductId 456456 for 100 gold
productFunctions[456456] = function(_receipt, player)
-- Logic for player buying 100 gold
local stats = player:FindFirstChild("leaderstats")
local gold = stats and stats:FindFirstChild("Gold")
if gold then
gold.Value = gold.Value + 100
-- Indicate a successful purchase
return true
end
end
-- The core 'ProcessReceipt' callback function
local function processReceipt(receiptInfo)
-- Check the data store to determine if the product was already granted
local playerProductKey = receiptInfo.PurchaseId
local purchased = false
local success, result, errorMessage
success, errorMessage = pcall(function()
purchased = purchaseHistoryStore:GetAsync(playerProductKey)
end)
-- If the purchase is recorded, the product was already granted
if success and purchased then
return Enum.ProductPurchaseDecision.PurchaseGranted
elseif not success then
error("Data store error:" .. errorMessage)
end
-- Update the purchase record
local success, isPurchaseRecorded = pcall(function()
return purchaseHistoryStore:UpdateAsync(playerProductKey, function(alreadyPurchased)
if alreadyPurchased then
return true
end
-- Find the player who made the purchase in the server
local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
-- The player probably left the game
-- If the player returns, the callback is called again
return nil
end
local handler = productFunctions[receiptInfo.ProductId]
local success, result = pcall(handler, receiptInfo, player)
-- Do not record the purchase if granting the product failed
if not success or not result then
error("Failed to process a product purchase for ProductId: " .. tostring(receiptInfo.ProductId) .. " Player: " .. tostring(player) .. " Error: " .. tostring(result))
return nil
end
-- Record the transaction in purchaseHistoryStore
return true
end)
end)
if not success then
error("Failed to process receipt due to data store error.")
return Enum.ProductPurchaseDecision.NotProcessedYet
elseif isPurchaseRecorded == nil then
-- Did not update the value in the data store
return Enum.ProductPurchaseDecision.NotProcessedYet
else
-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
return Enum.ProductPurchaseDecision.PurchaseGranted
end
end
-- Set the callback; this can only be done once by one script on the server!
MarketplaceService.ProcessReceipt = processReceipt