Extensions
Shop extension (Cash Pack → DevProducts)

Shop extension (Cash Pack Shop → DevProducts Handler)

A worked example of a shop / monetization extension: a package that adds purchasable products and a shop section to the DevProducts Handler base. Here it's Cash Pack Shop. Read the Extensions overview first for the shared contract.

The DevProducts Handler calls these "Connected Shop Libraries" — each registers its own section against a shared Shop dispatch layer, so multiple shop extensions coexist in one place without editing each other.

What it extends

The DevProducts Handler exposes three extension points that are all auto-discovered:

  • SharedSource/Datas/Monetization/DevProductSets/ — product data files
  • ClientSource/…/ProductController/…/Shop/Sections/ — shop UI section files
  • ServerScriptService/…/ProductService/…/DevProductHandler/ — server grant logic

A shop extension drops one file into each.

Step 1 — Declare the base systems

Three required dependencies — the handler, the currency it grants, and the shop UI it slots into:

[
  {
    "display_name": "DevProducts Handler",
    "unique_id": "829a1885-182d-4c0a-8ee4-f9f3650ebd26",
    "always_on": true,
    "isInitiallyChecked": true
  },
  {
    "display_name": "Currency System",
    "unique_id": "d482364f-a580-4594-a74e-5b43c9b51124",
    "always_on": true,
    "isInitiallyChecked": true
  },
  {
    "display_name": "Robux Shop",
    "unique_id": "428973bf-60c3-4e7b-b7b4-d1cab475294a",
    "always_on": true,
    "isInitiallyChecked": true
  }
]

This is the key lesson for shop extensions: list every system you depend on, not just the handler. Cash Pack needs the Currency System to grant cash and the Robux Shop for its section to appear in.

The zip

Cash_Pack_Shop/
├─ Instructions.md
├─ metadata.json                        # name, description, version, created_by
├─ relevant_systems.json                # [ DevProducts Handler, Currency System, Robux Shop ] all always_on
├─ Unpack_On_Source/
│  ├─ ReplicatedStorage/ClientSource/Client/ProductController/Components/Others/
│  │    Shop/Sections/CashSection.lua                 # registers a shop section (drop-in)
│  ├─ ReplicatedStorage/SharedSource/Datas/Monetization/
│  │    DevProductSets/CashProducts.lua               # dev product data (drop-in)
│  └─ ServerScriptService/ServerSource/Server/ProductService/Components/Others/
│       DevProductHandler/CashHandler.lua             # server grant logic (drop-in)
└─ To_Upload_By_User/
   └─ DevProducts/superbullet_metadata.json           # maps tokens → user's dev product IDs

No Unpack_On_Roblox_Studio/ here — the shop UI is built by the section script against the existing shop window.

Step 2 — Drop-in files

Each file has a unique name (Cash…) and lands in an extension-point folder the base already scans:

-- Unpack_On_Source/ReplicatedStorage/SharedSource/Datas/Monetization/DevProductSets/CashProducts.lua
return {
	{ Name = "Cash1", Description = "Adds 2,500 cash",   ProductId = 3485188014 },
	{ Name = "Cash2", Description = "Adds 25,000 cash",  ProductId = 3485188012 },
	{ Name = "Cash3", Description = "Adds 100,000 cash", ProductId = 3485188013 },
	{ Name = "Cash4", Description = "Adds 500,000 cash", ProductId = 3485188010 },
}
  • CashSection.lua registers a section (tiles + buy buttons) against the shared Shop dispatch layer.
  • CashHandler.lua is the server-side grant logic the ProductService dispatches to on purchase.
  • The ProductId numbers above are placeholder tokens — see Step 4.

Because everything is additive drop-in files, this extension needs no shared-file edits, so its Instructions.md is minimal.

Step 4 — Dev products upload (primary method)

Each dev product must be created by the experience owner. Cash Pack uses the primary token + source_path method: after the user creates each product, its placeholder ID in CashProducts.lua is replaced in-place.

[
  {
    "display_name": "Cash1 - 2,500 Cash",
    "description": "Adds 2,500 cash",
    "token": "3485188014",
    "source_path": "ReplicatedStorage/SharedSource/Datas/Monetization/DevProductSets/CashProducts.lua",
    "suggested_price": 49
  }
]

Each entry's token is the exact placeholder string that appears in the file at source_path. See Developer products for the full contract.

Checklist

  • relevant_systems.json requires the handler and every system you rely on (currency, shop UI).
  • One drop-in file per extension point: product set, shop section, server handler — all uniquely named.
  • Placeholder ProductId tokens in the product set match the token values in the upload metadata.
  • To_Upload_By_User/DevProducts/superbullet_metadata.json has correct token + source_path + suggested_price.
  • metadata.json has name, description, and a bumped version_number.