SDK error · code 20

paymentPendingError (error code 20): Payment pending

What it means

paymentPendingError (code 20) means the purchase has started but is not paid yet. A parent must approve it (Ask to Buy), a bank must confirm it, or a delayed Google Play payment method must settle. It is not a failure. Tell the customer it is pending, keep listening for customer info updates, and grant access only when the entitlement turns active.

Code

20

iOS (Swift)

ErrorCode.paymentPendingError

Android (Kotlin)

PurchasesErrorCode.PaymentPendingError

Causes

Why the SDK returns paymentPendingError

  • StoreKit 2: the purchase result is .pending, which Apple describes as a purchase that requires action from the customer. The SDK throws paymentPendingError (StoreKit2TransactionListener.swift).
  • StoreKit 1: a transaction in the deferred state, which Apple describes as pending external action such as Ask to Buy.
  • Android: the Play purchase state is PENDING. The SDK raises this error instead of posting the purchase (PostReceiptHelper.kt). Google says to grant entitlement only when the state is PURCHASED (Google docs).
  • The backend answered 7651 (payment not complete), which the Android SDK maps here.
Backend codeMeaning
7651Payment not complete (Android mapping).

Fix

How to fix paymentPendingError

  1. 01

    Show a pending message

    Tell the customer "Your purchase is waiting for approval" and close the paywall. Do not show a failure.

  2. 02

    Listen for updates

    On iOS, implement purchases(_:receivedUpdated:) on PurchasesDelegate. On Android, set an UpdatedCustomerInfoListener. Both fire when the pending purchase completes.

  3. 03

    Check customer info on resume

    Call getCustomerInfo when the app returns to the foreground. A purchase can complete while the app is closed, and StoreKit delivers a pending purchase that succeeds through Transaction.updates (Apple docs).

  4. 04

    Do not acknowledge or consume a pending purchase

    On Android, acknowledge only after the state is PURCHASED. Google starts the three-day acknowledgement window at that moment (Google docs).

In your app

How to handle it in code

  • Do not retry the purchase. The customer would start a second one.
  • Do not grant access until CustomerInfo shows the entitlement active.
  • Treat it as a state, not an error: store a "pending" flag for the product so the paywall can say so on the next launch.
Match the errorSwift · Kotlin
// Swift
do {
  let result = try await Purchases.shared.purchase(package: package)
} catch let error as ErrorCode where error == .paymentPendingError {
  // handle payment pending
}

// Kotlin
if (error.code == PurchasesErrorCode.PaymentPendingError) { /* ... */ }

On RevenueDot: The Android SDK does not post pending purchases, so RevenueDot normally never sees them. If a pending Google purchase does reach POST /v1/receipts, RevenueDot answers 503 with code 7101, so the SDK posts it again later, and a cancelled pending purchase gets 400 with 7103.

FAQ

paymentPendingError: questions people ask

What is Ask to Buy, and how does it show up in the SDK?

Ask to Buy lets a parent approve a child's purchase. The SDK reports the waiting state as paymentPendingError, and customer info updates once the parent approves.

When should I grant access for a pending purchase?

Only when the entitlement is active in CustomerInfo. Google says to grant entitlement only for a PURCHASED state, not PENDING (Google docs).

How do I check for paymentPendingError in React Native and Flutter?

In React Native, compare error.code with PURCHASES_ERROR_CODE.PAYMENT_PENDING_ERROR. In Flutter, convert the PlatformException with PurchasesErrorHelper.getErrorCode(e) and compare the result with PurchasesErrorCode.paymentPendingError.

Get started

Keep the RevenueCat SDK. Change the backend.

RevenueDot answers the same SDK calls with the same error codes. Start free on RevenueDot Cloud, free up to $10,000 a month in tracked revenue.

Already have an account? Sign in · Prefer your own servers? Self-host free