{"slug":"roblox-gamepasses","title":"roblox-gamepasses","summary":"Implement Roblox game passes, developer products, subscriptions, and Robux transfers. Use for purchase prompts, server-side fulfillment, ownership checks, recurring benefits, and monetization policy.","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-10-18T17:23:56.37472Z","repo":{"url":"https://github.com/nonlooped/roblox-suite","stars":22,"forks":0,"license":"MIT","updatedAt":"2026-10-17T23:48:49Z"},"bodyHtml":"<hr>\n<h2>name: roblox-gamepasses\ndescription: \"Implement Roblox game passes, developer products, subscriptions, and Robux transfers. Use for purchase prompts, server-side fulfillment, ownership checks, recurring benefits, and monetization policy.\"\nlast_reviewed: 2026-07-16</h2>\n<h1>roblox-gamepasses</h1>\n<p><strong>Primary official source:</strong> <a href=\"https://create.roblox.com/docs/en-us/production/monetization/passes\">https://create.roblox.com/docs/en-us/production/monetization/passes</a> (plus developer-products.md for contrast, and the MarketplaceService class reference).</p>\n<p>Grant benefits on the server after verifying the purchase or ownership. Keep purchase prompts and shop display on the client.</p>\n<p>See roblox-datastores for how to store \"player owns this pass\" state or associated perks, and roblox-networking for the Remote validation layer around purchase prompts.</p>\n<h2>Game passes and developer products</h2>\n<ul>\n<li><strong>Game Pass</strong>: One-time purchase. Permanent privilege for that specific experience (VIP access, permanent item, extra slot, cosmetic unlock, etc.). Roblox tracks ownership per user per experience.</li>\n<li><strong>Developer Product</strong>: Repeatable / consumable (currency packs, potions, revives, temporary boosts). Can be bought many times. Requires ProcessReceipt callback on the server for fulfillment.</li>\n<li>As of <strong>May 30, 2026</strong>, cross-experience game pass and developer product sales are disabled. Design experience-specific passes or use the <a href=\"https://create.roblox.com/docs/en-us/production/monetization/robux-transfers\">Robux Transfers API</a> for donation-style flows. <code>MarketplaceService:PromptRobuxTransferAsync</code> must be called from the server. Only <strong>Roblox Plus</strong> subscribers can initiate transfers, transfer amounts must be between <strong>10 and 500 Robux</strong>, and the sender cannot equal the receiver. The recipient receives <strong>90%</strong> and the experience earns the other <strong>10%</strong>; Roblox takes no transfer fee. A <code>BindReceiptHandler</code> callback must process transfer receipts. Roblox permits an experience to grant items or perks after a successful receipt; choosing not to attach rewards is an opinionated anti-abuse/design recommendation, not a platform rule.</li>\n<li>You (the creator) are 100% responsible for actually delivering the benefit. Roblox only handles the transaction and the UserOwnsGamePassAsync query.</li>\n<li>Passes can be used for randomized virtual items only if you follow the Paid Random Items policy.</li>\n</ul>\n<h2>Creation and asset ID</h2>\n<ol>\n<li>Creator Dashboard → your published experience → Monetization → Passes → Create a Pass.</li>\n<li>Upload circular-friendly icon (≤512×512, jpg/png/bmp; important content must survive circular crop).</li>\n<li>Name + description.</li>\n<li>After creation: hover the pass → ⋯ → Copy Asset ID. This number is the passID you use in all scripts.</li>\n</ol>\n<p>For external sales on the game page Store tab: go to the pass → Sales → enable \"Item for Sale\" and set Robux price (1 to 1B).</p>\n<h2>Prompt purchases and grant benefits</h2>\n<p><strong>Client side (LocalScript or UI module; only for prompting and optimistic display):</strong></p>\n<ul>\n<li>Call MarketplaceService:UserOwnsGamePassAsync (pcall) to decide \"Buy\" vs \"Owned\" button state.</li>\n<li>If not owned, call MarketplaceService:PromptGamePassPurchase(player, passID).</li>\n</ul>\n<p><strong>Server side (Script in ServerScriptService; the only place that grants benefits):</strong></p>\n<pre><code>local MarketplaceService = game:GetService(\"MarketplaceService\")\nlocal Players = game:GetService(\"Players\")\n\nlocal PASS_ID = 1234567890\nlocal granted = {} -- idempotency guard: granted[player][passID]\n\nlocal function grantPassBenefits(player: Player, passID: number)\n    if not player or not player:IsDescendantOf(Players) then\n        return\n    end\n    local playerGranted = granted[player]\n    if not playerGranted then\n        playerGranted = {}\n        granted[player] = playerGranted\n    end\n    if playerGranted[passID] then\n        return\n    end\n    playerGranted[passID] = true\n\n    -- Apply the actual privilege (attributes, table entry, DataStore flag, Remote to client for visuals, etc.)\n    -- This is the source of truth.\nend\n\nMarketplaceService.PromptGamePassPurchaseFinished:Connect(function(player: Player, purchasedPassID: number, wasPurchased: boolean)\n    -- This event also fires on the client; never grant benefits from the client copy.\n    if not player or typeof(purchasedPassID) ~= \"number\" then\n        return\n    end\n    if wasPurchased and purchasedPassID == PASS_ID then\n        local ok, err = pcall(function()\n            grantPassBenefits(player, PASS_ID)\n        end)\n        if not ok then\n            warn(\"Failed to grant pass benefits:\", err)\n        end\n    end\nend)\n\nPlayers.PlayerAdded:Connect(function(player: Player)\n    local success, owns = pcall(function()\n        return MarketplaceService:UserOwnsGamePassAsync(player.UserId, PASS_ID)\n    end)\n    if success and owns then\n        local ok, err = pcall(function()\n            grantPassBenefits(player, PASS_ID)\n        end)\n        if not ok then\n            warn(\"Failed to apply owned pass benefits:\", err)\n        end\n    elseif not success then\n        warn(\"UserOwnsGamePassAsync failed for\", player.Name)\n    end\nend)\n\nPlayers.PlayerRemoving:Connect(function(player: Player)\n    granted[player] = nil\nend)\n</code></pre>\n<p><strong>GetProductInfoAsync for dynamic UI (price, name, description, IsForSale):</strong>\nUse <code>MarketplaceService:GetProductInfoAsync(id, Enum.InfoType.GamePass)</code>. Do this on the client for display, but never grant based on the result. The non-async counterpart <code>GetProductInfo</code> still exists, but <code>GetProductInfoAsync</code> is preferred.</p>\n<h2>Capability requirements</h2>\n<p>Game passes and developer products require a published experience. Enable <strong>Studio Access to API Services</strong> only when a specific API used by a dedicated test experience requires it; do not treat that Studio setting as a blanket prerequisite for every <code>MarketplaceService</code> purchase API. Verify each API's current requirements in its Engine Reference entry.</p>\n<h2>Product recommendations</h2>\n<ul>\n<li><code>MarketplaceService:RankProductsAsync(arrayOfIdentifiers)</code>: pass a table of up to 50 <code>{InfoType = Enum.InfoType.GamePass, Id = ...}</code>. Returns a personalized ranking for the current user as <code>{ProductIdentifier, ProductInfo}</code> items. Use sparingly; call once at join.</li>\n<li><code>MarketplaceService:RecommendTopProductsAsync({Enum.InfoType.GamePass, Enum.InfoType.Product})</code>: returns up to 50 recommended products the user is likely to engage with. Results usually exclude already-owned items, but verify in your UI. Use sparingly; call once at join.</li>\n</ul>\n<p>Use these results in a \"Recommended for you\" section of your shop. Measure whether they improve conversion in your experience.</p>\n<h2>Promotions (buy robux page bonus pool)</h2>\n<p>You can opt passes into the promotion pool so that users buying Robux packages may receive the pass for free (contextually relevant to their history).</p>\n<p>Requirements (from the passes doc):</p>\n<ul>\n<li>Unique pass recommended.</li>\n<li>If on sale, price between 50 and 800 Robux.</li>\n<li>Must have thumbnail.</li>\n<li>Must comply with Community Standards.</li>\n<li>Cannot be a paid random item.</li>\n</ul>\n<p>Opt-in via the pass's Promotions tab in the dashboard.</p>\n<h2>Analytics and iteration</h2>\n<p>In Creator Dashboard → experience → Monetization → Passes → Analytics tab you get:</p>\n<ul>\n<li>Top passes by sales and net Robux.</li>\n<li>Time-series graphs.</li>\n<li>Attribution for passes acquired via Buy Robux promotions and subsequent joins.</li>\n</ul>\n<p>Use this data to decide pricing, which perks are compelling, and when to run promotions.</p>\n<h2>Security, data, and policy constraints</h2>\n<ul>\n<li>Prompt only from client. Grant and record only on the server in the PromptGamePassPurchaseFinished handler or on PlayerAdded re-check.</li>\n<li>Always pcall <code>UserOwnsGamePassAsync</code> and <code>Prompt...</code> calls.</li>\n<li>Re-check ownership on every relevant join/session start before granting gameplay or economy perks.</li>\n<li>Store your own record of ownership + associated state in DataStores if you need history or custom metadata (Roblox does not expose full per-user pass purchase history via the Engine API).</li>\n<li>For RTBF / right-to-be-forgotten, include pass-related keys in your deletion patterns (see roblox-datastores skill).</li>\n<li>Never hardcode Robux prices in UI that the player sees: use <code>GetProductInfoAsync</code> so regional pricing and optimizations work.</li>\n<li>Test purchases only on dedicated test experiences.</li>\n<li>For paid random items (loot boxes / gacha passes), use <code>PolicyService</code> first: check <code>PolicyService:GetPolicyInfoForPlayerAsync(player).ArePaidRandomItemsRestricted</code> and <code>IsPaidItemTradingAllowed</code> before offering randomized paid content.</li>\n<li>For developer products, <code>MarketplaceService.ProcessReceipt</code> can only be assigned <strong>once</strong> globally; assign it once in a single server script. The callback must return <code>Enum.ProductPurchaseDecision.PurchaseGranted</code> after successful fulfillment, or <code>Enum.ProductPurchaseDecision.NotProcessedYet</code> if fulfillment fails, because Roblox may redeliver the receipt until <code>PurchaseGranted</code> is returned.</li>\n<li>Donation / tipping games using <code>PromptRobuxTransferAsync</code> are high-risk for abuse; implement rate limits, alt-account detection, moderation pipelines, and avoid granting in-experience advantages in exchange for transfers.</li>\n</ul>\n<h2>Subscriptions (recurring benefits)</h2>\n<p>Subscriptions offer users recurring benefits for a monthly fee, auto-renewing in Robux or local currency. Unlike passes (permanent), subscription benefits persist only while the user keeps paying. Up to 50 per experience; single-tiered (no mutually exclusive Bronze/Silver/Gold); regional pricing enabled by default for Robux-priced subs.</p>\n<p><strong>API surface</strong> (subscription IDs are <strong>strings</strong> like <code>\"EXP-11111111\"</code>):</p>\n<ul>\n<li><code>MarketplaceService:GetUserSubscriptionStatusAsync(player, subscriptionId)</code>: <strong>server-only</strong>, returns <code>{IsSubscribed: boolean}</code>.</li>\n<li><code>MarketplaceService:PromptSubscriptionPurchase(player, subscriptionId)</code>: client prompt.</li>\n<li><code>MarketplaceService.PromptSubscriptionPurchaseFinished(player, subscriptionId, didTryPurchasing)</code>: note <code>didTryPurchasing</code> is an <em>attempt</em> signal, not success; re-check status after a delay.</li>\n<li><code>Players.UserSubscriptionStatusChanged(player, subscriptionId)</code>: <strong>server-only</strong>, fires on purchase/renewal/cancellation.</li>\n<li><code>MarketplaceService:GetSubscriptionProductInfoAsync(subscriptionId)</code> and <code>GetUserSubscriptionPaymentHistoryAsync(player, subscriptionId)</code>.</li>\n</ul>\n<p><strong>Security (same posture as passes):</strong> prompt on client, check status and grant/revoke on server only, pcall everything, re-check on every join (subscriptions lapse), respect <code>PolicyService:IsEligibleToPurchaseSubscription</code> per player, persist nothing sensitive on the client.</p>\n<p><strong>Payouts:</strong> Robux-priced subs pay 70% each month. Local-currency subs pay 70% first month, 100% thereafter, with a 30-day hold. Robux subs are not refundable; local-currency subs are refundable within the hold window.</p>\n<p>See <a href=\"references/subscriptions.md\">references/subscriptions.md</a> for the complete flow, client/server code, migration from passes, and gotchas.</p>\n<h2>Creator Rewards (replaces Premium Payouts)</h2>\n<p>As of <strong>July 24, 2025</strong>, Engagement-Based Payouts (formerly \"Premium Payouts\") and the Creator Affiliate program were <strong>discontinued and replaced by Creator Rewards</strong>. There is no longer a per-Premium-play-minute payout to integrate against.</p>\n<p>Creator Rewards is a platform program with two payment types. It requires no in-experience integration:</p>\n<ul>\n<li><strong>Daily Engagement Rewards</strong>: 5 Robux per day per Active Spender who spends 10+ minutes in your experience, provided it's one of the first three experiences they visit that day.</li>\n<li><strong>Audience Expansion Rewards</strong>: 35% revenue share on a new/reactivated user's first $100 of qualifying purchases in their first 60 days, attributed via Share Links, direct experience links, or experience-name search.</li>\n</ul>\n<p>Official source: <a href=\"https://create.roblox.com/docs/en-us/creator-rewards\">https://create.roblox.com/docs/en-us/creator-rewards</a></p>\n<h2>When to use game passes vs other monetization</h2>\n<ul>\n<li>One-time permanent unlock or access → Game Pass.</li>\n<li>Repeatable purchase (currency, consumables, temporary power) → Developer Product (with proper ProcessReceipt).</li>\n<li>Recurring monthly benefit → Subscription (see references/subscriptions.md; <code>MarketplaceService:GetUserSubscriptionStatusAsync</code> etc.).</li>\n</ul>\n<p>See the developer-products doc for the repeatable flow.</p>\n<h2>Scripts</h2>\n<ul>\n<li><code>scripts/PassPurchaseHelper.lua</code>: a client-side helper for game pass button state, price display, and prompting.</li>\n</ul>\n\n<h2>Reference index</h2>\n<ul>\n<li><a href=\"references/creation-and-setup.md\">creation-and-setup.md</a>: Create a pass, find its asset ID, or configure sales and test access.</li>\n<li><a href=\"references/policyservice.md\">policyservice.md</a>: Gate a feature using per-player monetization or content restrictions.</li>\n<li><a href=\"references/purchase-flow-and-granting.md\">purchase-flow-and-granting.md</a>: Implement pass purchase prompts, ownership checks, and server grants.</li>\n<li><a href=\"references/rules-policies-and-security.md\">rules-policies-and-security.md</a>: Review monetization restrictions, paid random items, or purchase security.</li>\n<li><a href=\"references/subscriptions.md\">subscriptions.md</a>: Create recurring benefits or handle subscription status and renewals.</li>\n</ul>\n\n","files":[{"path":"references/creation-and-setup.md","sizeBytes":5032,"isText":true},{"path":"references/policyservice.md","sizeBytes":9038,"isText":true},{"path":"references/purchase-flow-and-granting.md","sizeBytes":6520,"isText":true},{"path":"references/rules-policies-and-security.md","sizeBytes":4917,"isText":true},{"path":"references/subscriptions.md","sizeBytes":12247,"isText":true},{"path":"scripts/PassPurchaseHelper.lua","sizeBytes":6916,"isText":false},{"path":"SKILL.md","sizeBytes":12967,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-10-18T17:24:16.452656Z","sha256":"A813DCD0BFB137D674D3CEC89F2C510828D2F366E4C1BDFC50A95AB4AF838C3D","sizeBytes":22090},"review":null,"source":{"repositoryUrl":"https://github.com/nonlooped/roblox-suite","path":"roblox-gamepasses","license":"MIT","commit":"2904c1660c702d82f1ab67f46ddf619d6abc9a2d","subtreeSha":"9EDA2188F80C3ABB55FEFECE0650FE955D46E894BE647828046CDCAD93D83AA3","lastSyncedAt":"2026-10-18T17:23:55.435396Z"},"reviewedAt":"2026-10-18T17:24:43.304785Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/nonlooped/roblox-suite/tree/main/roblox-gamepasses"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install nonlooped-roblox-suite@llmmart"},{"target":"git","command":"git clone https://github.com/nonlooped/roblox-suite.git"}]}