Я уже немного рассматривал GUI пользовательского интерфейса. В данном случае пойдёт речь о GUI на объектах — т.е. на предметах пространства. Начнём с нюансов:
- Если между GUI и игроком есть хоть миллиметр преграды — оно работать не будет.
- Взаимодействие с GUI предполагается, через LocalScript. Это не значит, что оно не будет работать посредством серверных скриптов, только вот через них не получишь игрока, который с ними взаимодействовал.
- LocalScript может работать, только на стороне пользователя, а значит может быть запущен только в определённых местах из чего может следовать, что привязка скрипта к интерфейсу должна быть внутри скрипта.
- При использовании серверного Script может быть необходима работа через удалённые функции.

Итак. Создаём обычный part — что будет выступать объектом и кладём на него наш будущий интерфейс:

Ну а скрипт запихнём в.. туда где он может работать:

И сам скрипт:
-- активация покупки по нажатию кнопки на объекте
local Player = game.Players.LocalPlayer -- активировавший игрок
local MPS = game:GetService("MarketplaceService") -- привязка к сервису
local SurfacePart = workspace:WaitForChild("SurfaceBlock") -- ищем наш объект
local SurfaceGui = SurfacePart.SurfaceGui -- поверхность на объекте
local Button = SurfaceGui.TextButton -- собственно сама кнопка
local ID = 998598719 -- Developer Product Id
Button.Activated:Connect(function() -- привязка активации кнопки
MPS:PromptProductPurchase(game.Players.LocalPlayer, ID) -- действия при активации кнопки
end)
Вот собственно и всё что нам нужно. Теперь при нажатии кнопки будет выскакивать окно о покупке нашего продукта. Или ошибка, если кода такого продукта нет.

Если же мы приверженцы хранить всё по полочкам (а вдруг), тогда интерфейс нужно перенести в StarterGui, а в свойствах GUI поверхности указать объект в параметре Adomee. Ну и скрипт уже держать непосредственно под кнопкой.

В результате чего он несколько похудеет.
-- активация покупки по нажатию кнопки на объекте
local Player = game.Players.LocalPlayer -- активировавший игрок
local MPS = game:GetService("MarketplaceService") -- привязка к сервису
local Button = script.Parent -- собственно сама кнопка
local ID = 998598719 -- Developer Product Id
Button.Activated:Connect(function() -- привязка активации кнопки
MPS:PromptProductPurchase(game.Players.LocalPlayer, ID) -- действия при активации кнопки
end)
Оба варианта будут выглядеть так:

Пример использования интерфейса на поверхности можно увидеть тут:
https://www.roblox.com/games/4789977549/Math-Rocket