High-Level Flow Options
Learn the different ways your game backend can work with Stash Pay. Understand how ConfirmPayment, PURCHASE_SUCCEEDED webhooks, and GetPaymentEvent fit into your architecture so you can choose the flow that best matches your game's rules and reward experience.
This article walks through three Stash Pay integration patterns and when to use each one, based on:
- Your game-specific technical requirements (inventory limits, multi-client locking)
- Your backend architecture (async/event-based vs. synchronous)
- Your preferred in-game reward-granting behavior
Before you start, you need an API key generated in Stash Studio, our developer portal.
If you don't have access to Stash Studio, contact the Stash team. They'll set up your game instance and enable payment processing for you.
Initial Setup
Set up Stash Pay instance
To set up Stash Pay, contact the Stash team. After onboarding, you'll receive access to Stash Studio, our developer portal. Your game instance (including payment processing) will be created for you so you can begin the integration.
Get your API key
Once you have your Stash Studio instance all set up, the only prerequisite is creating your first API key. You'll use this key to call Stash Pay API endpoints from your game backend. Specifically, you'll need an Ingress API key for the GetPaymentEvent endpoint, and an Egress API key for the ConfirmPayment endpoint.
Core Checkout Flow (Common to All Options)
All three options share the same basic checkout flow:
Requesting Checkout
From your game client or backend, request a checkout session via the Stash API. Provide:
- The player identifier (e.g. your internal player ID)
- The items or bundles the player wants to purchase
Get Checkout URL
Receive a customized checkout URL and a unique checkout/intent ID from Stash. Store this ID on your backend, associated with the player and the pending purchase.
Show Checkout
Display the checkout to the player via redirect, popup, or in-app browser. The player reviews the purchase and completes payment using the configured payment methods.
Stash pre-authorizes the payment, then proceeds according to the integration pattern you choose.
Choosing Your Stash Pay Flow
You can choose between three main patterns:
ConfirmPaymentPURCHASE_SUCCEEDEDwebhookGetPaymentEvent
Use the following criteria to decide which flow (or combination) fits your game best.
1. Do you need inventory management or purchase locks?
Use this criterion if your game has stricter rules around:
- Per-player inventory limits (e.g. cap on how many times a bundle can be purchased)
- Locking purchases across multiple game clients/devices
- Other validation that must happen before a purchase is finalized
Best fit: ConfirmPayment
Direction: Stash → Game (your backend exposes this endpoint).
With ConfirmPayment, Stash calls your backend before finalizing the charge. This gives your game server a chance to:
- Validate the purchase (inventory, caps, locks)
- Optionally grant rewards as part of that validation
- Approve or reject the transaction
Typical flow with ConfirmPayment
Player completes checkout.
Stash sends a ConfirmPayment request to your backend.
Your backend applies your game rules (inventory/locks/eligibility) and optionally grants rewards immediately.
Your backend responds with Approve (Stash finalizes the charge) or Reject (Stash cancels the charge).
Choose this if your game can't safely finalize a purchase without the backend being in the loop first.
2. What's your preferred Verification & Granting behavior?
Use this criterion to decide when and how rewards should be granted:
- Pre-purchase: Verify and grant before the charge is finalized
- Post-purchase, delayed: Grant later via async processing
- Post-purchase, immediate: Grant as soon as the purchase is confirmed
Option A: Pre-purchase granting with ConfirmPayment
When to use:
- You need to verify inventory and locks and grant rewards before the charge is finalized.
- You want the player to see rewards as "already granted" when the purchase finishes.
How it works:
- Stash calls your
ConfirmPaymentendpoint. - Your backend validates the purchase and grants rewards.
- Your backend approves the payment.
- Stash finalizes the charge.
Option B: Post-purchase, delayed via PURCHASE_SUCCEEDED webhook
When to use:
- Your backend processes events asynchronously.
- It's acceptable for rewards to appear a bit later in the game.
How it works:
- Stash finalizes the payment.
- Stash sends a
PURCHASE_SUCCEEDEDwebhook. - Your backend processes the event and grants rewards later.
Option C: Post-purchase, immediate via GetPaymentEvent
When to use:
- You want the client to show rewards immediately after purchase.
- You don't need pre-purchase verification beyond what Stash already does.
- You prefer your server to actively query Stash.
How it works:
- Player completes checkout.
- Your backend calls
GetPaymentEvent. - If the purchase succeeded, your backend grants rewards and returns the updated player state to the client.
You can also combine these patterns (for example, using ConfirmPayment for validation and GetPaymentEvent for client-side confirmation), depending on your game's needs.
3. What's your current backend architecture? (event-based vs synchronous)
Use this criterion if your backend is primarily:
- Async/event-driven (queues, workers, background jobs), or
- Synchronous/request–response (client expects an immediate result from the server)
Best fit for async/event-driven: PURCHASE_SUCCEEDED webhook
Best fit for synchronous: GetPaymentEvent
PURCHASE_SUCCEEDED webhook (async)
Direction: Stash → Game (your backend exposes a webhook endpoint).
This fits an event-driven architecture where your backend consumes events and processes them asynchronously.
Typical flow:
- Player completes checkout.
- Stash finalizes the payment.
- Stash sends a
PURCHASE_SUCCEEDEDwebhook to your backend. - Your backend:
- Consumes the event (e.g. via a queue or worker).
- Runs your game logic and grants rewards.
- Updates your own systems (logs, analytics, CRM, etc.).
Choose this if you're comfortable with rewards appearing slightly later in the game, and you already use webhooks and background workers to process external events.
GetPaymentEvent (synchronous)
Direction: Game → Stash (your backend calls this endpoint).
This fits a synchronous pattern where the client expects a definitive answer right after purchase. See the GetPaymentEvent API Reference for request/response details.
Typical flow:
- Player completes checkout.
- Your backend (or client via your backend) calls
GetPaymentEventwith the purchase ID. - Stash returns the final status of the payment.
- If successful, your backend grants rewards and returns an updated state to the client.
Choose this if you want to avoid webhooks and keep control on the game server side, or if your client needs a "final answer" immediately and your backend is already designed for synchronous calls.
Handling Failures and Edge Cases
Regardless of which pattern you choose:
Idempotency
Make your reward-granting logic idempotent by purchase ID so retries (from webhooks or polling) never grant rewards twice.
Timeouts and retries
- For
ConfirmPayment, define clear behavior when your backend is slow or unavailable (e.g. reject, retry, or show a recoverable error in-game). - For webhooks, implement retry handling and signature verification as recommended in the Webhook Retries guide.
- For
GetPaymentEvent, handle transient failures (e.g. retry with backoff) and show appropriate messaging to the player.
How is this guide?