Unity/UGS and FastSpring checkout integration (iOS & Android) with Steer Safe™

Build a secure in-game purchase flow using FastSpring, Unity UGS, and deep link steering to handle checkout, webhooks, and post-purchase updates.

Enable a secure, cross-platform in-game purchase flow where your mobile game (iOS or Android) launches a FastSpring checkout in a browser or in-app web context. After purchase, FastSpring notifies your backend via webhook, your backend grants the corresponding entitlement in your economy service, and the player’s balance updates inside the game.

Engine compatibility: The Unity engine is used in examples, but this pattern is engine-agnostic. Replace the authentication, economy, and deep link APIs with equivalents in your stack. The secure payload and redirect flow remain the same.

How it works

The diagram below shows the complete end-to-end flow of a FastSpring checkout from the player's perspective. It outlines which system performs each step and how data moves between the client, backend, FastSpring, and your economy service.

sequenceDiagram
    participant Player
    participant Client
    participant Backend
    participant FastSpring
    participant Economy

    Player->>Client: Initiate purchase
    Client->>Backend: POST /encode (product)
    Backend-->>Client: Signed checkout URL (securePayload + secureKey)
    Client->>FastSpring: Opens checkout
    FastSpring->>Backend: order.completed webhook
    Backend->>Economy: Grant entitlement
    Client->>Economy: Poll for updated balance

Actor key

Each part of the system plays a specific role in this process. Use this table as a quick reference while following the setup stages below.

Client

Game client (Unity or another engine) that requests the checkout URL and handles deep links.

Backend

Your secure API service that signs payloads and handles FastSpring webhook events.

FastSpring

Processes the checkout, payments, and sends the order.completed webhook.

Economy

Your entitlement or currency system (UGS, PlayFab, or custom) that grants items after purchase.


Stage 1: Environment setup

Confirm your environment and services can communicate with FastSpring before you start configuring products or code.

Compatibility baseline

Recommended versions and capabilities for each component:

ComponentRecommended baselineNotes
Unity2022.3 LTS or laterTargets .NET Standard 2.1
.NET profile.NET Standard 2.1Required for Unity 2022 LTS
Web pageModern browsersSupports FastSpring Store Builder
BackendPublic HTTPS runtime (e.g., Node.js 18+)Must be reachable by FastSpring webhooks
FastSpringAccount with Embedded CheckoutRequired for Store Builder and webhooks

Note: Android integrations using Chrome Custom Tabs require androidx.browser:browser:1.5.0.

Services checklist

Confirm each of the following is available and configured:

  • Player authentication (Unity Authentication, Firebase Auth, or equivalent)
  • Economy or entitlement service (UGS Economy, PlayFab, or custom)
  • FastSpring product added to Embedded Checkout
  • Backend that can sign payloads and receive webhooks
  • Hosted web page that initializes FastSpring checkout
  • Optional: Cloud function (e.g., Unity Cloud Code) for async grant handling

Stage 2: Configure FastSpring

Configure your FastSpring store so it can generate secure payloads, run checkout, and send order webhooks to your backend.

1. Create your product
  1. Sign in to your FastSpring account, or create an account if you’re new.
  2. Go to Catalog > One-Time Products.
  3. Create your product and set a Product Path, also known as the product ID (this will be your product value).
  4. Configure pricing and any required tax settings.
  5. Click Save and confirm the product appears in your catalog.
2. Add the product to your Embedded Checkout
  1. Go to Checkouts > Embedded Checkouts.
  2. On the applicable checkout, click Products. The Homepage Products modal opens.
  3. In the Main Products field, type the product name or ID that you want to add. Repeat this step for each product.
  4. Click Save and confirm the product appears in your embedded checkout.
3. Generate and upload your keys

Before you can pass a secure payload to your store checkout, complete a one-time encryption setup in your FastSpring account.

  1. Go to Developer Tools > Store Builder Library.

  2. Copy your Access Key (used later in data-access-key on the web page).

  3. Generate a 2048-bit RSA key pair in your terminal:

    Private key (server only)

    openssl genrsa -out privatekey.pem 2048

    Note: Keep privatekey.pem on your backend only (for creating securePayload and secureKey). Do not embed it in client or front-end code.

    Public certificate (upload to FastSpring)

    Replace <your_store_name> with your FastSpring store name (for example, "/CN=fastspring").

    openssl req -new -x509 -key privatekey.pem -out publiccert.pem -days 3650 -subj "/CN=<your-store-name>"
  4. Upload your publiccert.pem file using the File Upload section.

  5. Click Save.

4. Configure your webhook

Set up a webhook so FastSpring can notify your backend when a checkout is completed. First, create the webhook record, then attach a URL endpoint and select the event you want to receive notifications for.

Create webhook

  1. Go to Developer Tools > Webhooks > Configuration.
  2. Click Add Webhook (top right).
  3. Enter an internal Title for the webhook.
  4. Select the Get webhooks from dropdown and choose whether you would like FastSpring to send you webhook events for Live Orders, Test Orders, or Live and Test Orders.
  5. Click Add.

Add URL and event

After creating a webhook, follow the steps below to apply URLs and events to it. This enables you to send specific webhook events to multiple URLs and endpoints.

  1. Go to Developer Tools > Webhooks > Configuration. Click Add URL Endpoint on the webhook you wish to edit.
  2. In the URL field, enter the external URL or endpoint where you want FastSpring to post the JSON data. We recommend using HTTPS endpoints to encrypt data.
  3. In the HMAC SHA256 Secret field, optionally enter a secret phrase for additional security.

    Note: If you set an HMAC secret, verify the webhook signature on your backend before processing the request.

  4. In the Events section, select order.completed.
  5. Click Add.
5. Map your product IDs

Use a single product ID (per product) across all systems, so your backend can grant the correct entitlement without lookups.

FastSpring product IDEntitlement ID (economy)Client productId
coinpack-150coinpack-150coinpack-150

Warning: An exact, case-sensitive match is required across all systems. Keep IDs stable (avoid renaming after launch). Any mismatch prevents the grant from being applied after purchase.


Stage 3: Build the backend

Implement a backend that signs secure payloads, returns signed checkout URLs, and grants entitlements on order.completed. Examples use AWS, Serverless Framework, and Node.js/TypeScript, but any stack works if it exposes POST /encode and handles webhooks.

What you'll build

  • POST /encode Verifies the player and returns a signed checkout URL.

    • Input: Authorization token and { "product": "<FastSpring product ID>" }
    • Output: URL with product, securePayload, and returnUrl
  • Webhook handler (order.completed) Receives FastSpring’s webhook and grants the mapped entitlement.

    • Input: order.completed payload from FastSpring
    • Action: Grant the product and process each webhook only once (ignore retries).

Environment variables

Use this table to collect the secrets and IDs your backend needs:

KeyDescriptionSourceUsed by
UGS_PROJECT_IDUnity project IDUnity DashboardWebhook grant call
UGS_ENV_IDUnity environment IDUnity DashboardWebhook grant call
UGS_SERVICE_ACCOUNT_SECRETServer-to-server token or secretUnity ServicesAuthorize webhook calls
PEM_PRIVATE_KEYFastSpring private keyYour PKI or keygen/encode signing

Note: If you’re not using UGS, replace the UGS_* items with your economy provider’s equivalent credentials (for example, PlayFab title secret, custom service token).

If you’re using the Serverless Framework (example sets provider: aws), reference these values in serverless.yml and load actual secrets from your secrets manager:

# serverless.yml (excerpt)
UGS_PROJECT_ID: "<YOUR_UGS_PROJECT_ID>"
UGS_ENV_ID: "<YOUR_UGS_ENV_ID>"
UGS_SERVICE_ACCOUNT_SECRET: "<YOUR_UGS_SERVICE_ACCOUNT_SECRET>"
PEM_PRIVATE_KEY: "<YOUR_PEM_PRIVATE_KEY>"

Note: PEM_PRIVATE_KEY is the value you generated and uploaded in Stage 2 for secure payloads.

/encode example

The client calls /encode to obtain a signed checkout URL. Your backend verifies the player, signs the payload with your private key, and returns product, securePayload, and returnUrl.

curl https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/encode \
  --request POST \
  --header 'Authorization: <player_access_token_or_exchange_token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "product": "<your_product_ID>"
  }'

Economy grant

After validating the order.completed webhook, grant the purchase to the player using one of the following approaches:

  • UGS Virtual Purchase (example below): Call Unity Cloud Code with the mapped product ID (must equal the FastSpring product ID) and the player identity.
  • Your provider’s grant API (non-UGS): Call your economy service’s server-to-server grant endpoint with the same mapped product ID and player identity. Authenticate with your service token/secret and ensure you process each webhook only once (ignore retries/duplicates).
# UGS VirtualPurchase example (grant from your webhook handler)
curl https://cloud-code.services.api.unity.com/v1/projects/<YOUR_UGS_PROJECT_ID>/scripts/VirtualPurchase \
  --request POST \
  --header 'Authorization: <exchange_token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "params": {
      "playerId": "<target_player_id>",
      "productId": "<purchased_item_id>"
    }
  }'

Placeholder legend

  • <YOUR_UGS_PROJECT_ID> Unity project ID
  • <exchange_token> obtained via Unity’s token exchange API
  • <target_player_id> the player to grant currency/items
  • <purchased_item_id> UGS Virtual Purchase ID (must match the FastSpring product ID, for example coinpack-150)

Note: FastSpring may retry webhooks. Deduplicate by event ID or order reference and process each webhook only once.

Deploy and verify

What goes live

  • POST /encode (client requests signed checkout URLs)
  • Webhook endpoint (receives and handles order.completed events)

How to deploy

  • In UGS: deploy the VirtualPurchase script in the Unity Cloud Dashboard.
  • In AWS: deploy after configuring the AWS CLI and Serverless Framework:
npm run deploy
# or
serverless deploy

Verify

  • Call /encode and confirm the response contains product, securePayload, and returnUrl.
  • Complete a test checkout and confirm your webhook endpoint receives order.completed.

Stage 4: Build the web checkout page

Build a lightweight page that reads the signed URL parameters, initializes the FastSpring session, and redirects back to your app.

Expected query parameters

Your backend’s signed checkout URL must include these parameters; the page reads them on load to reconstruct the secure session.

ParameterRequiredDescription
productYesProduct ID (e.g., coinpack-150). Identifies the product to display.
securePayloadYesBase64-encoded and URL-escaped encrypted payload generated by your backend.
secureKeyYesBase64-encoded and URL-escaped encryption key used with the payload.
returnUrlYesDeep link to redirect to after checkout (e.g., fastspring://shop-return).

Tip: These parameters come from the /encode response. Never hard-code them on the page.

Initialize the secure session

After parsing the query string, decode both secure values and initialize the FastSpring session.

const decodedPayload = decodeURIComponent(securePayload);
const decodedKey = decodeURIComponent(secureKey);

fastspring.builder.secure(decodedPayload, decodedKey);

Embed checkout attributes

Add a FastSpring container pointing to your checkout and access key.

<div
  data-storefront="https://<your-fs-checkout-url>"
  data-access-key="ACCESS_KEY">
</div>

Placeholder legend

  • data-storefront your FastSpring Embedded Checkout URL
  • data-access-key access key from Developer Tools > Store Builder Library

Stage 5: Configure the client (Unity example)

Connect the client to your backend: request a signed checkout URL, open checkout, handle the return deep link, poll the economy, and confirm the update.

5.1 StoreConfig setup

In Unity, open the StoreConfig ScriptableObject and set the following fields. If you’re using another engine, create an equivalent configuration file or class.

FieldDescriptionExample
storeBaseUrlOrigin of your deployed or local checkout pagehttps://checkout.example.com
returnUrlDeep link to return to the Unity appfastspring://shop-return
purchaseCreatorEndpointBackend endpoint that returns a signed checkout URLhttps://api.example.com/encode

5.2 Post-checkout flow (deep link, polling, and thank-you)

After checkout, FastSpring redirects the player back to your app via a deep link, such as:

fastspring://shop-return?amount=150

Your deep link handler should:

  • Parse the amount query parameter (display only).
  • Re-authenticate the player if needed.
  • Trigger polling of your economy service.
  • Show a thank-you popup once the balance updates.

Tip: In the Unity Editor, press D to simulate a deep link return (fastspring://shop-return?amount=150).

Polling UGS Economy after return

When a purchase completes, UGS Economy may not yet reflect the change. Use an active polling mechanism (for example, PollUntilBalanceChangesAsync) until the player’s balance refreshes.

Why polling is needed

  • The FastSpring → backend → UGS webhook path can take a few seconds.
  • UGS does not push real-time balance updates to the Unity client.
  • Polling ensures the player sees their updated balance without restarting the app.

Show a thank-you message

After confirming the updated balance, display a success or thank-you message to the player. The example below shows a Unity helper method. If you use another engine, display an in-app notification or dialog after you read the updated balance from your economy service.

EconomyManager.Instance.ShowThanksYouPopup(delta); // delta = granted coin amount

5.3 Request and open a signed checkout

To initiate a purchase, the client requests a signed checkout URL from your backend. The backend signs the payload and returns a one-time URL that the client can open securely.

ActorWhat it does
ClientEnsures the player is signed in, sends product to /encode, opens the returned checkout URL, and handles the deep link.
BackendVerifies player identity, creates securePayload and secureKey, returns the signed URL, handles the order.completed webhook, and grants the entitlement.

Example usage

ShoppingManager.Instance.OpenStore("coinpack-150");

Client request (placeholders)

POST https://api.example.com/encode
Authorization: <player_access_token_or_exchange_token>
Content-Type: application/json

{ "product": "<your_product_id>" }

Backend response (placeholders)

https://<your-fs-checkout-url>?
product=<your_product_id>&
securePayload=<your_securePayload>&
returnUrl=<your_deep_link>

Placeholder legend

  • <your-fs-checkout-url> your FastSpring Embedded Checkout URL
  • <your_product_id> mapped FastSpring product ID (for example, coinpack-150)
  • <your_securePayload> URL-escaped securePayload returned by /encode
  • <your_deep_link> deep link return URL (for example, fastspring://shop-return)

5.4 Open checkout across platforms

Once your client can generate a signed checkout URL, open it using the provider that fits each platform.

Opens FastSpring checkout in the system browser (Safari). After checkout completes or is cancelled, Safari redirects back to your app via the deep link (for example, fastspring://shop-return).

Application.OpenURL(fullUrl); // Opens Safari; returns via fastspring://shop-return

5.5 Adding custom implementations

To add a new platform implementation:

  1. Create a class that implements IShopProvider.
  2. Implement the OpenStore(string url) method.
  3. Add the appropriate conditional compilation directive in OpenShopProvider.
  4. If using native plugins (Android and/or iOS), place them in the corresponding Assets/Plugins directory.

5.6 Economy integration

This example uses Unity Gaming Services (UGS) Economy, but any provider works as long as it supports player authentication, granting the mapped product, and reading the player’s balance for polling.

Set up economy (UGS example)

  1. Enable Authentication and Economy in your Unity Dashboard.
  2. Use the COINS currency (or update your code to match your own currency ID).
  3. Keep the product → amount mapping on the backend (do not trust amounts from the client).

Tip: If you use a custom or third-party economy, mirror the same pattern: verify the webhook on your backend, grant the correct entitlement, and let the client poll until the updated balance is confirmed.