face-tongue-moneyPurchasing & Restoring Purchases

Learn how to initiate in-app purchases and restore past purchases using Onside’s SDK. Includes transaction handling, restoring routines, and best practices.

The entire payment process is managed through a central component: the OnsidePaymentQueue. This queue processes payment requests and maintains a list of transactions that your app needs to handle.

Purchasing

To interact with this queue and receive updates about purchases, you must use an observer that conforms to the OnsidePaymentTransactionObserver protocol. This observer is the cornerstone of your payment logic. It’s responsible for listening to all transaction updates, whether a purchase succeeds, fails, is being processed, or needs to be restored.

The overall workflow is:

  1. Register an Observer: At app launch, register a transaction observer to listen for events from the payment queue.

  2. Initiate a Purchase: Add a payment to the queue when a user taps a "Buy" button.

  3. Process Transactions: Handle the transaction states (e.g., purchased, failed) delivered to your observer.

  4. Unlock Content: Grant the user access to their purchased content.

  5. Finish the Transaction: Mark the transaction as complete to remove it from the queue. This is a mandatory step.

Step 1: Set Up the Transaction Observer

Your application must have an active transaction observer to process payments.

How the Queue Works: The OnsidePaymentQueue is designed to be safe. It will not process any transactions—new purchases or pending ones—and will remain in a "paused" state until at least one observer is registered via add(_:). Once an observer is present, the queue becomes active and begins processing.

Best Practice: The observer should be registered as early as possible in your app's lifecycle, ideally in your AppDelegate. This "un-pauses" the queue, allowing it to immediately process any transactions.

Step 2: Making a Purchase

Once you have fetched an OnsideProduct object, you can initiate a purchase by creating payment object and adding it to the payment queue.

The SDK will take over from here, presenting the necessary UI (login, payment sheet, etc.). The result will be delivered asynchronously to your active transaction observer.

Step 3: Processing Transactions

This is where you handle the results of a purchase. The onsidePaymentQueue(_:updatedTransactions:) method in your observer will be called with an array of transactions. You must inspect the transactionState of each one.

⚠️ CRITICAL: You MUST Finish Transactions

You must call Onside.defaultPaymentQueue().finishTransaction(_:) for every transaction that reaches a final state (.purchased, .restored, or .failed).

If you do not finish a transaction, the payment queue will assume it was not processed, and it will deliver the same transaction to your observer again the next time the app launches. This can lead to bugs, such as repeatedly asking to unlock content.

Restoring Purchases

You should provide a "Restore Purchases" button in your app (e.g., in the settings screen) for users who have reinstalled your app or are using a new device. This allows them to regain access to their non-consumable and subscription purchases without paying again.

How Restoration Works: When you call this method, OnsideKit communicates with the backend to find all previous purchases for the current user.

  • The results are not delivered directly from the method call.

  • Instead, for each restored purchase, the payment queue calls the same onsidePaymentQueue(_:updatedTransactions:) delegate method on your observer.

  • The transactions will have a state of .restored.

Your existing logic in the switch statement will handle these restored transactions, unlocking the content and finishing the transaction, just like a new purchase.

After all individual transactions have been delivered, the SDK calls one of two delegate methods to signal the completion of the entire restore operation. This is where you should update your UI (e.g., hide an activity indicator).

Purchase Validation

This document outlines the process of validating purchases for publishers using the Onside SDK.

Overview

Publishers integrate the Onside Mobile SDK to facilitate in-app purchases. The SDK manages the purchase process and generates a signed transaction history. The publisher's backend is responsible for validating these transactions to ensure purchase integrity and unlock content.

Validation involves two crucial steps: obtaining a signed transaction history from the Onside SDK via the mobile application, and verifying specific orders on the publisher's backend against the Onside Merchant API with a secure, server-to-server authentication mechanism.

Integration Flow

The following diagram illustrates the complete validation process.

spinner

Prerequisites

To interact with the Merchant API, obtain a Merchant ID, a Merchant Secret, and a Secret Key ID (kid) from the Onside Manager. These credentials enable secure server-to-server authentication.

Client-Side Transaction History

The mobile application requests transaction history via the Onside SDK, which returns a JSON Web Signature (JWS) containing the transaction history. Each purchase includes a unique order_id for verification.

SDK API: Getting a signed JWS on the client

Use Onside.makeSignedInAppsHistoryRequest() to create a request that downloads a signed in-app purchase history as a compact JWS.

The call returns:

  • OnsideSignedInAppsHistoryRequestError if the SDK cannot create a request instance.

  • OnsideSignedInAppsHistoryRequest on success.

OnsideSignedInAppsHistoryRequest is a request object you control and retain.

Typical flow

  1. Create the request with Onside.makeSignedInAppsHistoryRequest().

  2. Provide an OnsideSignedInAppsHistoryRequestDelegate implementation.

  3. Keep a strong reference to the request for the whole operation.

  4. Call start().

  5. In the delegate callbacks, handle either:

    • OnsideSignedInAppsHistory on success.

    • An error describing why the history could not be loaded.

OnsideSignedInAppsHistory.data is the raw JWS blob.

OnsideSignedInAppsHistory.string is the same blob as a String, when available.

Send this JWS to your backend (or validate it locally) to verify purchase authenticity and build entitlements from the original signed history.

Backend Validation Request

To validate a purchase, the backend receives the order_id from the mobile app and queries the Onside Merchant API.

Authentication

Authenticate requests to the Onside Merchant API with a JSON Web Token (JWT) in the Authorization header, signing it using HS256 and your Merchant Secret. The JWT header must specify alg as HS256 and kid as your Secret Key ID, while the payload claims should include aud set to onside, iss set to onside, and sub set to your Merchant ID. Ensure exp and nbf define a validity period of no more than 30 seconds, and include a unique jti.

API Request

To obtain the in-app purchase history, send a GET request to the endpoint /merchant-api/v1/purchases/in-app/history/{order_id}. Make sure to include the JWT token in the Authorization header for authentication.

Response Format

Upon a successful request, the Onside Merchant API provides a signed JSON Web Signature (JWS). After verifying the JWS, the payload includes a TransactionHistory object, detailing transaction events.

Example Response Payload (Decoded)

The decoded response contains a JSON object with a list of transactions:

Response Validation

To ensure authenticity, verify the JWS signature using Onside's public keys available at https://onside.io/.well-known/jwks.json. Confirm the payload against the TransactionHistory schema as specified in the API documentation.

Last updated

Was this helpful?