Catalog Management

Dynamic Catalog

Learn how to expose REST API endpoints on your game backend to power dynamic, player-personalized web shops with special offers. This guide covers the Catalog, Player, and Purchase APIs with protobuf-based type-safe integration.

The Stash v1 WebShop APIs enable game studios to power dynamic, player-personalized web shops with special offers. These protobuf-based APIs provide a robust, type-safe integration path that accelerates development while ensuring reliability at scale.

Why Protobuf-Based APIs?

BenefitImpact
Type SafetyCompile-time validation catches integration errors before deployment
Auto-generated DocumentationAlways up-to-date API docs from proto definitions
Multi-language SupportGenerate clients in Go, TypeScript, C#, Java, Python, and more
Faster Integration~2 weeks faster integration vs implementing REST APIs by hand
Backward CompatibilityProto versioning ensures smooth API evolution

Getting Started

Clone the proto repository and generate type-safe clients automatically:

# Add the public-api repo as a submodule in your backend repo
git submodule add https://github.com/stashgg/public-api.git
# Or just clone it locally
git clone https://github.com/stashgg/public-api.git

# Generate clients using the included script
cd public-api
./gen.sh

The gen.sh script generates clients for Go, TypeScript, and OpenAPI specs. Adapt it for your preferred language (C#, Java, Python, etc.) using standard protobuf tooling.

No documentation required: The generated clients provide full type definitions, so your IDE's autocomplete guides the integration.

Step 2: Implement the REST APIs

Implement the REST endpoints that Stash will call. You can either use the API Reference to write your own clients or generate clients automatically from the protobufs.

Integration Steps

Obtain API credentials

Your Stash engineering partner will generate an Egress API key for you in Stash Studio. Set your Game Backend URL in Stash Studio to match where the APIs will be hosted. Custom API endpoint paths can be configured if needed.

Generate clients or review the API reference

Use the proto repository to generate type-safe clients, or review the API Reference for detailed endpoint documentation.

Implement the required endpoints

At minimum, implement these endpoints on your game backend:

Required:

Recommended:

For the best multi-platform user experience across the Web Shop & Game Client(s), especially when selling items with limited inventory:

Optional:

  • GetOfferDetails — Show extra details like drop rates for legal compliance
  • GetPlayer — Show player-specific details like avatar, level, currency

Test with test credentials

Test your integration with your studio-test.stash.gg credentials before going live.

API Overview

The v1 APIs are organized into three services, exposed as REST endpoints. Stash sends requests to your Game Studio's backend servers:

All endpoints use HMAC authentication for secure server-to-server communication.

Catalog API

Retrieve dynamic, player-specific product catalogs.

GetCatalog

Returns the complete product catalog with purchasable items, offer chains, and display elements.

Endpoint: GET /api/v1/catalog

Query Parameters:

ParameterTypeDescription
platformenumIOS, ANDROID, or WEBSTORE — enables platform-specific pricing
regionstringISO-3166-1 alpha-2 code (e.g., US, GB, DE) for localized pricing
languagestringISO 639-1 code (e.g., en, es, fr) for localized text
playerIdstringPlayer ID for personalized offers and purchase limits

Response Structure:

Catalog
└── Sections[]
    ├── header (LocalizableText)
    ├── displayType (GRID or CAROUSEL)
    └── items[]
        ├── PurchasableItem (products & bundles)
        ├── OfferChainItem (progressive unlocks)
        └── NonPurchasableItem (banners & info)

See the full GetCatalog API Reference for detailed response schema.

GetOfferDetails

Returns detailed offer information including drop rates for loot boxes (required for legal compliance in many jurisdictions).

Endpoint: GET /api/v1/catalog/offer

Query Parameters:

ParameterTypeDescription
guidstringUnique offer instance identifier
productIdstringProduct SKU
platformenumPlatform for price resolution
regionstringRegion for localization
languagestringLanguage for text
playerIdstringPlayer ID for personalization

See the full GetOfferDetails API Reference for detailed response schema.

Purchase API

Handle the complete purchase lifecycle with three endpoints.

Purchase Flow

RegisterPayment

Step 1: Registers a purchase intent. Your backend should reserve inventory for the player.

Endpoint: POST /api/v1/purchase/register

Key Fields:

FieldDescription
playerIdPlayer making the purchase
transactionIdUnique transaction identifier (generated by Stash)
currencyISO-4217 currency code (e.g., USD, EUR)
registrations[]Items to purchase with productId, quantity, cents
platformIOS, ANDROID, or WEBSTORE
sourceCART (web shop) or DIRECT (StashPay checkout link)

Response Status Codes:

StatusMeaningAction
SUCCESS_REGISTEREDInventory reservedProceed to payment
FAILED_INVALID_OFFEROffer expired or invalidShow error, refresh catalog
FAILED_INSUFFICIENT_INVENTORYNot enough stockShow error, update UI
FAILED_PURCHASE_LIMIT_EXCEEDEDPlayer limit reachedShow limit info to player
FAILED_INVALID_PRICEPrice mismatchRefresh pricing
FAILED_PURCHASE_LOCKEDPurchase restrictedShow restriction message

See the full RegisterPayment API Reference for detailed request/response schema.

ConfirmPayment

Step 2A: Confirms and completes the purchase after successful payment.

Unified Integration: This endpoint is the same API used for StashPay integrations. Implement once to power both your WebShop and StashPay checkout links.

Endpoint: POST /api/v1/purchase/confirm

Key Fields:

FieldDescription
playerIdPlayer who completed purchase
transactionIdTransaction ID from registration
currencyCurrency code
taxTax amount in cents
totalTotal amount including tax in cents
timeMillisCompletion timestamp (Unix millis)
items[]Purchased items with final pricing
extraInGameCurrencyOptional bonus currency to grant
extraLoyaltyPointsOptional bonus loyalty points
emailMarketingOptInCustomer marketing preference

See the full ConfirmPayment API Reference for detailed request/response schema.

CancelPayment

Step 2B: Cancels a pending purchase. Your backend should release reserved inventory.

Endpoint: POST /api/v1/purchase/cancel

See the full CancelPayment API Reference for detailed request/response schema.

Player API

Retrieve player profile information for personalized experiences.

GetPlayer

Returns player profile data for display in the web shop.

Endpoint: GET /api/v1/player

Query Parameters:

ParameterTypeDescription
playerIdstringPlayer ID to retrieve

Response Example:

{
  "player": {
    "playerId": "abc123",
    "name": "PlayerOne",
    "avatarUrl": "https://...",
    "language": "en",
    "inGameLevel": 42,
    "inGameCurrency": 15000
  }
}

See the full GetPlayer API Reference for detailed response schema.

Coming Soon: Loyalty Data

The Player API will soon include loyalty program data to power rich loyalty experiences:

FieldDescription
loyalty.currentTierCurrent loyalty tier/level
loyalty.totalPointsXP accumulated so far
loyalty.currencyAmountSpendable loyalty currency balance

Key Data Types

Catalog Items

The catalog supports three item types using protobuf oneof:

TypeUse Case
PurchasableItemStandard products and bundle offers with pricing
OfferChainItemProgressive offers that unlock sequentially
NonPurchasableItemBanners, promotions, and informational displays

PurchasableItem Structure

PurchasableItem
├── productId (required) - Your unique SKU
├── guid (optional) - Instance UUID for dynamic offers
├── type - STANDARD_OFFER or BUNDLE_OFFER
├── name/description (LocalizableText)
├── image - Product image URL
├── price
│   ├── amount.currency - ISO currency code
│   └── amount.cents - Price in smallest unit
├── maxPurchasable - Per-player purchase limit
├── expiration - Offer end timestamp
├── contents[] - Items included in purchase
│   ├── name, image, quantity
│   ├── bonusQuantity - Web store bonus amount
│   └── dropRate - For legal compliance
└── attributes
    ├── banner - Promotional banner text
    ├── badge - Corner badge (e.g., "NEW", "50% OFF")
    ├── background - Custom styling
    └── buyButton - CTA customization

Offer Chains

Progressive offers encourage repeat purchases:

OfferChainItem
└── links[]
    ├── status: CLAIMED (purchased)
    ├── status: UNLOCKED (available)
    └── status: LOCKED (requires previous)

Localization

All user-facing text supports localization:

{
  "defaultText": "Special Bundle",
  "localizationKey": "offer.special_bundle.title",
  "localizedText": "Offre Spéciale"
}

Choose between:

  • localizationKey: Stash-side lookup in our localization system (requires sharing locKeys)
  • localizedText: Pre-resolved server-side text

Integration Considerations

When to Use Each Endpoint

ScenarioEndpoints Used
Initial page loadGetCatalog + GetPlayer
Player clicks "View Details"GetOfferDetails
Player starts checkoutRegisterPayment
Rewards granted successfullyConfirmPayment
Rewards failed to grantCancelPayment

Caching Strategy

DataRecommended TTLNotes
Catalog structure1-5 minutesBalance freshness vs. load
Player data30 secondsKeep profile current
Offer details5 minutesDrop rates rarely change
PricesReal-timeAlways fetch current prices

Error Handling

  • Catalog API: Returns empty sections for unavailable content
  • Purchase API: Uses inline status codes (always HTTP 200) for predictable error handling
  • Player API: Returns 404 for unknown players

Platform & Region Pricing

Price Resolution

Prices can vary by platform and region. The API resolves the correct price based on:

FactorImpact
PlatformDifferent prices for iOS, Android, and Web (web often offers better margins)
RegionLocalized currency and regional pricing strategies
Player ContextPersonalized offers based on player behavior and segments

Platform Values

ValueDescription
CATALOG_PLATFORM_IOSiOS App Store pricing
CATALOG_PLATFORM_ANDROIDGoogle Play pricing
CATALOG_PLATFORM_WEBSTOREWeb shop pricing (typically lower fees)

Price ID vs Price Amount

When returning prices in the catalog, you have two options:

  • Your backend calculates and returns the exact price in the player's currency
  • Full control over pricing logic and regional strategies
  • Requires your backend to maintain price tables for all supported currencies

Best for: Studios managing their own pricing tables

  • Share your price IDs and corresponding prices in various currencies with Stash
  • Stash manages the price lookup based on player region and platform
  • Simplifies your backend — just return the price ID, and Stash handles currency conversion
  • Easier to update prices without code changes

Best for: Studios wanting Stash to manage regional & platform prices

Web Store Bonuses

Incentivize web purchases with bonus content:

FeatureDescription
Bonus ItemsExtra items added exclusively for web purchases
Bonus QuantitiesPercentage increases on item quantities
Visual IndicatorsContentItemType.WEB_STORE_BONUS for UI highlighting

Drop Rate Compliance

For loot boxes and randomized rewards, the API supports drop rate disclosure required for legal compliance in many jurisdictions.

Enabling Drop Rate Display

To show drop rates or offer details in a popup:

  1. Add a badge with the show details action — Include a badge on the offer with action: BADGE_ACTION_SHOW_OFFER_DETAILS. This signals to the frontend to display an info button that calls the GetOfferDetails API and opens the corresponding modal.

  2. Enable per-item details (optional) — For individual content items that should show their own reward/drop rate details, include clickAction: CONTENT_ITEM_CLICK_ACTION_SHOW_DETAILS_BY_ID on that ContentItem.

Example Catalog.PurchasableItem Response

{
  "attributes": {
    "badge": {
      "text": { "defaultText": "Loot Box" },
      "action": "BADGE_ACTION_SHOW_OFFER_DETAILS"
    }
  },
  "contents": [
    {
      "name": "Legendary Hero",
      "guid": "xxx",
      "image": "https://...",
      "quantity": "1",
      "dropRate": "2.5%",
      "clickAction": "CONTENT_ITEM_CLICK_ACTION_SHOW_DETAILS_BY_ID"
    },
    {
      "name": "Common Item",
      "quantity": "1",
      "dropRate": "97.5%"
    }
  ]
}

If using clickAction, the guid must be supplied (can't be auto-generated) to cross-reference with the GetOfferDetails API response.

Authentication

All API calls use HMAC-SHA256 signatures for authentication:

Header: stash-hmac-signature
Value: HMAC-SHA256(request_body, BASE64(egress_api_key))

Your base64-encoded Egress API key obtained from Stash Studio is the secret used to sign the request body.

If you've implemented HMAC authentication and your game backend is still responding to Stash's API requests with 3xx, 4xx, or 5xx error codes, you may need to allowlist test-api.stash.gg and api.stash.gg on your cloud network firewall.

Configuration

To configure your dynamic catalog endpoint in Stash Studio:

In Stash Studio, navigate to your game settings.

Open Configuration

Go to WebshopConfiguration

Set endpoint URL

Set your Game Backend URL to match where the Catalog & Purchase APIs will be hosted.

Configure authentication

Your Stash engineering partner can configure custom API endpoint paths if needed.

Debugging & Logs

Stash Studio provides comprehensive logging and debugging tools for your dynamic catalog. Use these tools to monitor your catalog endpoint and troubleshoot issues:

  • Check Stash Studio logs for endpoint response times
  • Verify your endpoint returns valid JSON
  • Ensure all required fields are present
  • Test with your studio-test credentials before going live

How is this guide?