Semua artikel

31 Oktober 2026 · 2 menit baca

ProcessReceipt yang benar: jangan sampai pembelian pemain hilang

Pemain yang sudah membayar Robux tapi tidak menerima barang adalah masalah serius. Ini cara menulis ProcessReceipt yang aman untuk Developer Product.

Setiap kali pemain membeli Developer Product, Roblox memanggil callback MarketplaceService.ProcessReceipt di server game Anda. Tugas callback ini sederhana tapi kritis: memberikan barang yang dibeli, lalu memberi tahu Roblox bahwa pembelian sudah selesai diproses.

Aturan utamanya

Kembalikan Enum.ProductPurchaseDecision.PurchaseGranted hanya setelah barang benar-benar diberikan dan tercatat. Bila ada yang gagal, kembalikan Enum.ProductPurchaseDecision.NotProcessedYet. Roblox akan mencoba memanggil callback lagi nanti, misalnya saat pemain bergabung kembali.

Kesalahan yang sering terjadi

  • Mengembalikan PurchaseGranted sebelum data tersimpan. Bila server mati di tengah jalan, pemain kehilangan barang yang sudah dibayar.
  • Memberikan barang dua kali karena callback dipanggil ulang untuk pembelian yang sama.
  • Membuat lebih dari satu ProcessReceipt. Callback ini hanya boleh di-set sekali di satu script server.

Contoh struktur

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

local COIN_PACKS = {
	[123456789] = 500, -- ganti dengan ID Developer Product Anda
}

MarketplaceService.ProcessReceipt = function(receipt)
	local player = Players:GetPlayerByUserId(receipt.PlayerId)
	if not player then
		-- Pemain sudah keluar: proses lagi saat ia kembali.
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	local amount = COIN_PACKS[receipt.ProductId]
	if not amount then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	-- grantAndSave: tambahkan koin, catat receipt.PurchaseId sebagai sudah diberikan,
	-- lalu simpan ke DataStore. Kembalikan true hanya bila penyimpanan berhasil.
	local ok = grantAndSave(player, receipt.PurchaseId, amount)
	if not ok then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	return Enum.ProductPurchaseDecision.PurchaseGranted
end

Cegah pemberian ganda dengan PurchaseId

Setiap pembelian punya receipt.PurchaseId yang unik. Simpan daftar PurchaseId yang sudah diproses di data pemain. Saat callback dipanggil, cek dulu: bila PurchaseId sudah ada, langsung kembalikan PurchaseGranted tanpa memberikan barang lagi.

Uji sebelum rilis

  • Uji pembelian di Studio; pembelian di Studio tidak memotong Robux sungguhan.
  • Simulasikan kegagalan penyimpanan dan pastikan callback mengembalikan NotProcessedYet.
  • Coba skenario pemain keluar tepat setelah membeli.

Penutup

Pembelian yang selalu sampai membangun kepercayaan, dan kepercayaan membuat pemain mau membeli lagi. Butuh sistem pembelian yang andal? Lihat layanan Scripting & Sistem.

Punya ide game? Kita bangun bareng.

Ceritakan idemu lewat formulir brief. Tim kami membalas dengan estimasi dalam 2 hari kerja.