Making purchases
Learn how to make and restore mobile purchases using Adapty iOS SDK. Adapty handles server-side validation, including renewals and grace periods
To make the purchase, you have to call .makePurchase()
method:
Adapty.makePurchase(product: product) { result in
switch result {
case let .success(info):
// successful purchase
case let .failure(error):
// handle the error
}
}
Adapty.makePurchase(activity, product) { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
//NOTE: profile is null in case of cross-grade with DEFERRED proration mode
// successful purchase
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
Adapty.makePurchase(activity, product, result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue();
//NOTE: profile is null in case of cross-grade with DEFERRED proration mode
// successful purchase
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
try {
final profile = await Adapty().makePurchase(product: product);
// successful purchase
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
}
Adapty.MakePurchase(product, (profile, error) => {
if(error != null) {
// handle error
return;
}
// successful purchase
});
try {
const profile = await adapty.makePurchase(product);
} catch (error) {
// handle the error
}
Request parameters:
- Product (required): an
AdaptyPaywallProduct
object retrieved from the paywall.
Response parameters:
- Profile: an
AdaptyProfile
object. This model contains info about access levels, subscriptions, and non-subscription purchases. Generally, you have to check only access level status to determine whether the user has premium access to the app.
iOS
Make sure you've added App Store Shared Secret (for iOS) and uploaded Service Account Key File (for Android) in Adapty Dashboard, without them, we can't validate purchases.
Below is a complete example of making the purchase and checking the user's access level.
Adapty.makePurchase(product: product) { result in
switch result {
case let .success(info):
if info.profile.accessLevels["premium"]?.isActive ?? false {
// grant access to premium features
}
case let .failure(error):
// handle the error
}
}
Adapty.makePurchase(activity, product) { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
//NOTE: profile is null in case of cross-grade of DEFERRED proration mode
if (profile?.accessLevels?.get("premium")?.isActive == true) {
// grant access to premium features
}
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
Adapty.makePurchase(activity, product, result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue();
//NOTE: profile is null in case of cross-grade with DEFERRED proration mode
if (profile != null) {
AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("premium");
if (premium != null && premium.isActive()) {
// grant access to premium features
}
}
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
try {
final profile = await Adapty().makePurchase(product: product);
if (profile?.accessLevels['premium']?.isActive ?? false) {
// grant access to premium features
}
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
}
Adapty.MakePurchase(product, (profile, error) => {
if(error != null) {
// handle error
return;
}
// "premium" is an identifier of default access level
var accessLevel = profile.AccessLevels["premium"];
if (accessLevel != null && accessLevel.IsActive) {
// grant access to premium features
}
});
try {
const profile = await adapty.makePurchase(product);
const isSubscribed = profile.accessLevels['premium']?.isActive;
if (isSubscribed) {
// grant access to premium features
}
} catch (error) {
// handle the error
}
Make sure to set up App Store Server Notifications (for iOS) and Real-time Developer Notifications (RTDN) (for Android) to receive subscription updates without significant delays.
Subscription offers
If your paywall has an active promotional offer for the product you are attempting to purchase, Adapty will automatically apply that offer at the time of purchase.
Adapty signs the request according to Apple guidelines, please make sure you've uploaded Subscription Key in Adapty Dashboard when using promotional offers.
(Android) Change subscription
If you need a subscription to be replaced with another one, you have to call .makePurchase()
method with additional parameter:
Adapty.makePurchase(activity, product, subscriptionUpdateParams) { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
//NOTE: profile is null in case of cross-grade with DEFERRED proration mode
// successful cross-grade
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
Adapty.makePurchase(activity, product, subscriptionUpdateParams, result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue();
//NOTE: profile is null in case of cross-grade with DEFERRED proration mode
// successful cross-grade
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
// TODO: add example
// TODO: add example
// TODO: add example
Additional request parameter:
- subscriptionUpdateParams: an
AdaptySubscriptionUpdateParameters
object.
You can read more about proration modes here.
Please read recommendations from Google for proration modes.
IMMEDIATE_AND_CHARGE_PRORATED_PRICE
proration mode is available only for a subscription upgrade, where the price per unit of time increases.
If you use
DEFERRED
proration mode, in case of success,profile
in the callback is null since real subscription change will occur only when current subscription's billing period ends.
Restoring purchases
To restore purchases, you have to call .restorePurchases()
method:
Adapty.restorePurchases { [weak self] result in
switch result {
case let .success(profile):
// check the access level
case let .failure(error):
// handle the error
}
}
Adapty.restorePurchases { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
// check the access level
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
Adapty.restorePurchases(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue();
// check the access level
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
try {
final profile = await Adapty().restorePurchases();
// check the access level
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
}
Adapty.RestorePurchases((profile, error) => {
if (error != null) {
// handle the error
} else {
// check the access level
}
});
try {
const profile = await adapty.restorePurchases();
// check the access level
} catch (error) {
// handle the error
}
Response parameters:
- Profile: an
AdaptyProfile
object. This model contains info about access levels, subscriptions, and non-subscription purchases. Generally, you have to check only access level status to determine whether the user has premium access to the app.
(iOS) Deferred purchases
For deferred purchases, Adapty SDK has an optional delegate method, which is called when the user starts the purchase in the App Store, and the transaction continues in your app. Just store makeDeferredPurchase
and call it later if you want to hold your purchase for now. Then show the paywall to your user. To continue purchase, call makeDeferredPurchase
.
extension AppDelegate: AdaptyDelegate {
func paymentQueue(shouldAddStorePaymentFor product: AdaptyDeferredProduct, defermentCompletion makeDeferredPurchase: @escaping (ResultCompletion<AdaptyPurchasedInfo>?) -> Void) {
// you can store makeDeferredPurchase callback and call it later
// or you can call it right away
makeDeferredPurchase { result in
// check the purchase
}
}
}
(iOS) Redeeming an Offer Code
Since iOS 14.0 your users can redeem Offer Codes. To allow them to do so, you can present the Offer Code redemption sheet by calling the related SDK method.
Adapty.presentCodeRedemptionSheet()
adapty.presentCodeRedemptionSheet();
Our experience shows that in some applications Offer Code Redemption sheet behaves unstable. We recommend that you redirect the user directly to the App Store.
In order to do this, you need to open the url of the following format:
https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}
Updated 4 months ago