Purchasing & 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:
Register an Observer: At app launch, register a transaction observer to listen for events from the payment queue.
Initiate a Purchase: Add a payment to the queue when a user taps a "Buy" button.
Process Transactions: Handle the transaction states (e.g., purchased, failed) delivered to your observer.
Unlock Content: Grant the user access to their purchased content.
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
OnsidePaymentQueueis 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 viaadd(_:). 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.
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:
OnsideSignedInAppsHistoryRequestErrorif the SDK cannot create a request instance.OnsideSignedInAppsHistoryRequeston success.
OnsideSignedInAppsHistoryRequest is a request object you control and retain.
Typical flow
Create the request with
Onside.makeSignedInAppsHistoryRequest().Provide an
OnsideSignedInAppsHistoryRequestDelegateimplementation.Keep a strong reference to the request for the whole operation.
Call
start().In the delegate callbacks, handle either:
OnsideSignedInAppsHistoryon 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?