High-Level Flow

Learn how Stash Pay's purchase flow works and discover three integration patterns for granting purchases based on your existing infrastructure.

This article walks through three Stash Pay integration patterns and when to use each one, based on:

  • Your game-specific technical requirements and limitations.
  • Your backend architecture (async/event-based vs. synchronous).
  • Your preferred in-game purchase-granting behavior.

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 backend, request a checkout session via the Stash API.

Get Checkout URL

Receive a customized checkout URL and a checkout link order ID (UUID) 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.

While these three steps are always consistent, the way you finalize the purchase and grant items can vary. Choose the granting flow that best fits how your game handles reward delivery and payment confirmation below:

Choosing Your Granting Flow

Select the pattern that best matches your backend architecture and reward-granting requirements. The three differ mainly in when they fire relative to the charge, and only one of them lets your server reject a purchase:

PatternWhen it firesDirectionCan your server reject?Best for
ConfirmPaymentBefore the charge is capturedStash calls your serverYes. See the warning in that tab.Inventory limits, purchase caps, multi-client locking
PURCHASE_SUCCEEDED webhookAfter the payment completesStash calls your serverNoBackends that process events asynchronously through queues, workers, or jobs
GetPaymentEventAfter the payment completes, when you ask for itYour server calls StashNoShowing rewards in the client immediately after purchase

This is an integration-time choice, not a runtime one. Which delivery mechanism a shop uses is fixed when the shop is configured, not selected per purchase. A single shop uses one of these patterns rather than switching between them, so treat the table above as a decision you make once per integration.

Async post-purchase. Stash sends your backend a PURCHASE_SUCCEEDED event after the payment completes.

Direction: Stash → Game (your backend exposes a webhook endpoint).

Best for: Backends that already process events via queues, workers, or background jobs. Rewards may appear slightly after purchase.

Flow:

Player completes checkout.
Stash finalizes the payment.
Stash sends a PURCHASE_SUCCEEDED webhook to your backend.
Your backend consumes the event, runs game logic, and grants rewards.

For full implementation details see the Webhook guides.

Synchronous post-purchase. Your backend asks Stash for the final payment status as soon as the purchase completes.

This is a targeted lookup, not a background poll. The trigger is the client's completion signal, which depends on how you present the checkout: the onSuccess prop or option on web; the successCallback argument of OpenCard or OpenModal (for example successCallback: OnSuccess) in Unity; and, in browser presentation modes such as openBrowser, the deep link that returns the player to your game, since those modes have no success callback (see Presentation Options). Your backend already holds the checkout link order ID from creating the link, so it can look the purchase up as soon as the client reports completion.

Direction: Game → Stash (your backend calls GetPaymentEvent).

Best for: Games where the client needs to show rewards immediately, or backends designed for synchronous request-response patterns without incoming webhooks.

Flow:

Player completes checkout.
The client receives the completion signal (the SDK success callback, or the deep-link return in browser modes) and notifies your backend.
Your backend calls GetPaymentEvent with the purchase ID.
Stash returns the final payment status.
Your backend grants rewards and returns updated state to the client.

See the GetPaymentEvent API Reference for request/response details.

Validation before the charge is captured. Stash calls your backend with ConfirmPayment before capturing the payment, and waits for your response.

This is the only one of the three patterns where your server can reject a purchase, and it grants items during the same call. It fires earliest of the three.

Direction: Stash → Game (your backend exposes the ConfirmPayment endpoint).

Best for: Games with per-player inventory limits, multi-client purchase locking, or any validation that must happen before a purchase is finalized.

Flow:

Player completes checkout.
Stash sends a ConfirmPayment request to your backend.
Your backend validates the purchase (inventory, caps, locks), grants the items, and returns them in the response body.
Stash captures the payment.

There is no approve or deny field. Your server signals success by returning 200 OK with the granted results in the body. It rejects by returning an HTTP error status.

Any failure response fails the purchase. Stash treats every non-success response the same way, whether it is a deliberate rejection, an unhandled 500, a timeout, or a malformed body. When that happens the purchase fails and Stash does not retain the funds.

Respond 200 OK unless you specifically do not want Stash to take the money.

For the full request/response schema see the ConfirmPayment API Reference.

How is this guide?