# In-experience item shops

An experience can offer a reviewed catalog of deterministic cosmetics or extra content. Players
choose a game-token transfer or a Stripe-hosted item checkout when that option is configured.
The store sells a nontransferable license for the named item. It does not sell cryptocurrency,
stored cash, NFTs, wagers, random rewards or a redeemable/resellable balance.

## Integrate an SDK experience

Install **Durable item shop** from Creator Studio's Toolbox. Register lifecycle handlers and
call `arcade.ready({})` as usual. From a player click:

```js
import {itemShop} from './plugins/item-shop.js';
const shop = itemShop();
buyButton.onclick = () => shop.open('moonstone-board');
async function refreshItems() {
  const result = await shop.inventory();
  if (result.ok) boardTheme = result.items.includes('moonstone-board') ? 'moonstone' : 'classic';
}
window.addEventListener('focus', refreshItems);
```

`open()` returning `ok` means the shop opened. Grant an item only from a fresh successful
inventory response, never from a success URL, message, wallet balance or local save. A modified
client can alter its own graphics: valuable content and multiplayer effects must be enforced
by your authenticated server. This first integration authorizes no paid competitive advantage.
Keep free play, input accessibility and independent game art. Payments remain explicit.

## Submit items for review

Creators provide game ID, stable SKU, title, description, cosmetic/content kind, exact price,
visual effect and delivery behavior. The operator reviews the item, rights, game integration,
seller, tax/refund treatment and payment eligibility before enabling it. Uploading an experience
or an `arcade-shop.json` file alone never activates payments.

Open **Item shop & creator earnings** inside your Studio project. Add up to 20 permanent
items, save a private draft, or export `arcade-shop.json`. After integrating inventory delivery,
confirm rights and delivery testing, then submit the catalog. Review is tied to the exact saved
build. A reviewer’s delivery approval does not activate payments or bypass seller onboarding.

The agreed creator card-sale model is **70% creator / 30% arcade.fun after payment processing
costs and applicable taxes**. Community card sales and automated creator payouts are awaiting
Stripe Connect activation and implementation. This does not change coin trading fees. Current
reviewed token invoices transfer directly to the configured creator; a platform token split is
not active. Never promise an automatic creator payout or cash-out before it is enabled.

The operator publishes approved entries in the persistent `shop-catalog.json` in the app data
directory. The checked-in first-party catalog contains the Mancala collection. Native example:

```json
{"version":1,"items":[{
  "game":"online-mancala","sku":"moonstone-board","title":"Moonstone board",
  "description":"A moonlit board finish. Same seeds, rules and matchmaking.",
  "kind":"cosmetic","effect":"moonstone","slot":"board","usdCents":299,"tokenUnits":"250000000",
  "operatorSold":true,"approved":true
}]}
```

`tokenUnits` is an integer string in the listed coin's six-decimal units (the example is 250
tokens). Mint, network and creator recipient come from the trusted game market configuration,
never from the experience or player. Missing markets and disabled payment options are not sold.
`operatorSold` is an operator-reviewed statement that Betarian is the seller/operator for this
item. Third-party Stripe sellers require their own approved Stripe Connect onboarding and
funds-flow implementation; marking arbitrary creator goods operatorSold is not a substitute.

## Enable payments on a server

Enable the `shop` feature. No product is sold without an approved catalog entry. Token payments
require the existing Solana RPC configuration and independently checked finalized transactions.
The invoice binds wallet, mint, recipient, amount, network, creation/expiry time and a unique memo.
The client simulates the exact transaction and saves its signature before broadcasting. Pending
receipts block a second charge. Refresh a saved receipt before making another attempt.

For Stripe, use a separate sandbox first. Configure `STRIPE_RESTRICTED_KEY` and
`STRIPE_WEBHOOK_SECRET` as server secrets, plus `STRIPE_SHOP_MODE=test`. Prefer a restricted
key with only the Checkout/payment read/write access this integration needs. Never paste keys
in chat, put them in the repository or send them to an experience.

Webhook: `POST /api/shop/stripe/webhook`. Subscribe to:

- `checkout.session.completed`
- `checkout.session.async_payment_succeeded`
- `checkout.session.async_payment_failed`
- `checkout.session.expired`
- `charge.refunded`
- `charge.dispute.created`

Verified webhook signatures, correct environment, exact order/session/price/currency and paid
status are required. The server API can also refresh payment status on return. A URL is never
proof of payment. Replay/concurrent events grant once. Any refund or payment dispute revokes
the v1 license, including reversed events arriving before the success event. A dispute win
requires support review before restoring the license. Refunds are handled through seller support
and Stripe, not an automatic in-game cash-out. Blockchain transfers cannot be reversed by the app.

Before live cards: confirm business/product eligibility with Stripe, support/refund contacts,
business/tax registrations and countries served; establish the proper tax collection treatment;
complete sandbox fulfillment/refund/dispute tests; configure the live webhook and restricted key;
then set `STRIPE_SHOP_MODE=live` and `STRIPE_COMMERCE_APPROVED=yes`. Automatic tax is deliberately
not enabled without a confirmed registration. Do not mix a sandbox item with a live payment.

## Crypto purchases are separate

Stripe's standard item checkout is not a fiat-to-crypto exchange. The separately approved
[Stripe onramp](https://docs.stripe.com/crypto/onramp) handles KYC and a supported asset/network
list. An onramp approval would not automatically approve every newly launched game coin.
No card-to-token purchase is enabled by this shop module. Stripe's prohibited/restricted
business rules also apply to crypto businesses, marketplace aggregation and prize-based games.

## Mancala collection

Boards: Moonstone, Rosewood, Jade Garden and Obsidian Gold ($2.99 each).
Pieces: Pearl, Aurora, Ember and Starlight ($1.99 each). A single license works in
**online and local Mancala**. Shop and inventory use the canonical `online-mancala` ID.
Boards and pieces occupy separate slots. The classic walnut table and seeds remain free.

Previewing never unlocks an item. Equipping checks the selected SKU against fresh server-owned
inventory; refunds, invalid sessions and failed inventory loads fall back to the free look.
These cosmetics affect the buyer's own view. They do not change moves, scores or match odds.

The token invoice prices are 250 game tokens per board and 150 per piece, plus the wallet's
network/account fees. They are fixed token amounts, not USD exchange quotes. Token checkout
appears only when Mancala's real mint/network/creator configuration is registered. No mint is
invented and card checkout never turns dollars into game coins.
