Shop
The Shop API lets server owners set up stores with categories, products, cart, orders, reviews, and a wallet system.
Shops are consumer storefronts, not isolated admin catalogs. Personal shops, server shops, Buddy
cards, and app-backed products should share the same product, offer, order, entitlement,
fulfillment, settlement, and review model. Buyer-facing pages should make the provider, shop,
server context, delivery result, validity, refund/support rule, and asset-home link visible before
checkout.
Get / Create shop
GET /api/servers/:serverId/shop
Returns the shop for the server, creating one if it doesn't exist.
TypeScript Python
const shop = await client . getShop ( 'server-id' ) shop = client . get_shop ( "server-id" )
Update shop
PUT /api/servers/:serverId/shop
TypeScript Python
await client . updateShop ( 'server-id' , { name : 'My Store' } ) client . update_shop ( "server-id" , name = "My Store" )
Categories
List categories
GET /api/servers/:serverId/shop/categories
TypeScript Python
const categories = await client . listCategories ( 'server-id' ) categories = client . list_categories ( "server-id" )
Create category
POST /api/servers/:serverId/shop/categories
TypeScript Python
const category = await client . createCategory ( 'server-id' , {
name : 'Merch' ,
description : 'Official merchandise' ,
} ) category = client . create_category ( "server-id" , name = "Merch" , description = "Official merchandise" )
Update category
PUT /api/servers/:serverId/shop/categories/:categoryId
TypeScript Python
await client . updateCategory ( 'server-id' , 'category-id' , { name : 'Accessories' } ) client . update_category ( "server-id" , "category-id" , name = "Accessories" )
Delete category
DELETE /api/servers/:serverId/shop/categories/:categoryId
TypeScript Python
await client . deleteCategory ( 'server-id' , 'category-id' ) client . delete_category ( "server-id" , "category-id" )
Products
List products
GET /api/servers/:serverId/shop/products
Param Type Description statusstring Filter by status categoryIdstring Filter by category keywordstring Search keyword limitnumber Max results offsetnumber Offset
TypeScript Python
const products = await client . listProducts ( 'server-id' , { keyword : 'shirt' } ) products = client . list_products ( "server-id" , keyword = "shirt" )
Get product
GET /api/servers/:serverId/shop/products/:productId
Product responses include media?: Array<{ type: 'image' | 'video'; url: string; thumbnailUrl?: string; position?: number }> when covers or gallery assets are attached. Private upload references returned from POST /api/media/upload can be used as product media url; Shop API responses resolve those references into authorized render URLs.
TypeScript Python
const product = await client . getProduct ( 'server-id' , 'product-id' ) product = client . get_product ( "server-id" , "product-id" )
Create product
POST /api/servers/:serverId/shop/products
TypeScript Python
const product = await client . createProduct ( 'server-id' , {
name : 'Creator badge' ,
slug : 'creator-badge' ,
type : 'entitlement' ,
categoryId : 'category-id' ,
basePrice : 100 ,
media : [ { type : 'image' , url : '/shadow/uploads/cover.png' , position : 0 } ] ,
} ) product = client . create_product (
"server-id" ,
name = "Creator badge" ,
slug = "creator-badge" ,
type = "entitlement" ,
categoryId = "category-id" ,
basePrice = 100 ,
media = [ { "type" : "image" , "url" : "/shadow/uploads/cover.png" , "position" : 0 } ] ,
)
Update product
PUT /api/servers/:serverId/shop/products/:productId
TypeScript Python
await client . updateProduct ( 'server-id' , 'product-id' , { price : 19.99 } ) client . update_product ( "server-id" , "product-id" , price = 19.99 )
Delete product
DELETE /api/servers/:serverId/shop/products/:productId
TypeScript Python
await client . deleteProduct ( 'server-id' , 'product-id' ) client . delete_product ( "server-id" , "product-id" )
Cart
Get cart
GET /api/servers/:serverId/shop/cart
TypeScript Python
const cart = await client . getCart ( 'server-id' ) cart = client . get_cart ( "server-id" )
Remove from cart
DELETE /api/servers/:serverId/shop/cart/:itemId
TypeScript Python
await client . removeCartItem ( 'server-id' , 'item-id' ) client . remove_cart_item ( "server-id" , "item-id" )
Add to cart
POST /api/servers/:serverId/shop/cart
Field Type Required Description productIdstring Yes Product ID skuIdstring No SKU variant quantitynumber Yes Quantity
TypeScript Python
await client . addToCart ( 'server-id' , {
productId : 'product-id' ,
quantity : 2 ,
} ) client . add_to_cart ( "server-id" , productId = "product-id" , quantity = 2 )
Update cart item
PUT /api/servers/:serverId/shop/cart/:itemId
TypeScript Python
await client . updateCartItem ( 'server-id' , 'item-id' , 3 ) client . update_cart_item ( "server-id" , "item-id" , quantity = 3 )
Remove from cart
DELETE /api/servers/:serverId/shop/cart/:itemId
TypeScript Python
await client . removeFromCart ( 'server-id' , 'item-id' ) client . remove_from_cart ( "server-id" , "item-id" )
Orders
Place order
POST /api/servers/:serverId/shop/orders
Field Type Required Description idempotencyKeystring Yes Client-generated key for safe retries itemsarray Yes Cart item IDs or product specs buyerNotestring No Note to seller
Entitlement-only orders are delivered immediately after payment. They grant the configured access or community asset, move to completed, and become visible in Wallet access/asset records. Physical and manually fulfilled services remain in the normal paid -> processing -> shipped -> delivered -> completed flow.
TypeScript Python
const order = await client . createOrder ( 'server-id' , {
idempotencyKey : crypto . randomUUID ( ) ,
items : [ { productId : 'pid' , quantity : 1 } ] ,
buyerNote : 'Please gift-wrap' ,
} ) order = client . create_order (
"server-id" ,
idempotency_key = "order-123" ,
items = [ { "productId" : "pid" , "quantity" : 1 } ] ,
buyerNote = "Please gift-wrap" ,
)
List my orders
GET /api/servers/:serverId/shop/orders
TypeScript Python
const orders = await client . listOrders ( 'server-id' , { status : 'paid' } ) orders = client . list_orders ( "server-id" , status = "paid" )
Admin: manage orders
GET /api/servers/:serverId/shop/orders/manage
TypeScript Python
const orders = await client . listShopOrders ( 'server-id' , { status : 'pending' } ) orders = client . manage_orders ( "server-id" , status = "pending" )
Get order
GET /api/servers/:serverId/shop/orders/:orderId
TypeScript Python
const order = await client . getOrder ( 'server-id' , 'order-id' ) order = client . get_order ( "server-id" , "order-id" )
Update order status
PUT /api/servers/:serverId/shop/orders/:orderId/status
Field Type Required Description statusstring Yes New status trackingNostring No Tracking number sellerNotestring No Note to buyer
TypeScript Python
await client . updateOrderStatus ( 'server-id' , 'order-id' , {
status : 'shipped' ,
trackingNo : 'TRACK123' ,
} ) client . update_order_status ( "server-id" , "order-id" , status = "shipped" , trackingNo = "TRACK123" )
Cancel order
POST /api/servers/:serverId/shop/orders/:orderId/cancel
TypeScript Python
await client . cancelOrder ( 'server-id' , 'order-id' ) client . cancel_order ( "server-id" , "order-id" )
Confirm completed delivery
Buyers call this after a seller marks the order delivered. This moves the order to completed and releases the settlement flow.
POST /api/servers/:serverId/shop/orders/:orderId/complete
TypeScript Python
await client . completeOrder ( 'server-id' , 'order-id' ) client . complete_order ( "server-id" , "order-id" )
Reviews
List product reviews
GET /api/servers/:serverId/shop/products/:productId/reviews
TypeScript Python
const reviews = await client . getProductReviews ( 'server-id' , 'product-id' ) reviews = client . list_product_reviews ( "server-id" , "product-id" )
Submit review
POST /api/servers/:serverId/shop/orders/:orderId/review
Field Type Required Description productIdstring Yes Product reviewed ratingnumber Yes 1 – 5 contentstring No Review text imagesstring[] No Image URLs isAnonymousboolean No Post anonymously
TypeScript Python
await client . createReview ( 'server-id' , 'order-id' , {
productId : 'product-id' ,
rating : 5 ,
content : 'Excellent quality!' ,
} ) client . submit_review ( "server-id" , "order-id" , productId = "product-id" , rating = 5 , content = "Excellent quality!" )
Reply to review (seller)
PUT /api/servers/:serverId/shop/reviews/:reviewId/reply
TypeScript Python
await client . replyToReview ( 'server-id' , 'review-id' , 'Thank you!' ) client . reply_to_review ( "server-id" , "review-id" , reply = "Thank you!" )
Wallet
Get wallet
TypeScript Python
const wallet = await client . getWallet ( ) wallet = client . get_wallet ( )
Top up
Public wallet top-up is disabled. Balance increases must come from a verified payment flow, refund, settlement, task reward, or admin grant.
The legacy POST /api/wallet/topup route now returns 403.
TypeScript Python
await client . topUpWallet ( 100 ) // throws; use the payment flow instead client . top_up_wallet ( 100 ) # raises; use the payment flow instead
List transactions
GET /api/wallet/transactions
TypeScript Python
const txns = await client . getWalletTransactions ( { limit : 50 } ) txns = client . list_transactions ( limit = 50 )
Entitlements
GET /api/servers/:serverId/shop/entitlements
TypeScript Python
const entitlements = await client . getEntitlements ( 'server-id' ) entitlements = client . list_entitlements ( "server-id" )