Back to the RevenueCat homepage
Google Play Billing

Appendix B: BillingResult Response Code Reference

This appendix provides a complete reference for all BillingResponseCode values returned by the Play Billing Library, along with the sub response codes introduced in PBL 8.0.

Response Codes

Code

Value

Retriable

Description

Recommended Strategy

OK

0

N/A

Operation succeeded

Process the result normally.

USER_CANCELED

1

No

User dismissed the purchase dialog

No action needed. Do not show an error message.

SERVICE_UNAVAILABLE

2

Yes

Google Play service is temporarily unavailable

Retry with exponential backoff (2s base, 2x factor, max 3 attempts).

BILLING_UNAVAILABLE

3

No (auto)

Billing is unavailable on this device or for this user

Do not auto retry. Check Play Store version and user account. Let the user try again manually.

ITEM_UNAVAILABLE

4

No

The requested product is not available for purchase

Refresh product details with queryProductDetailsAsync(). The product may have been deactivated.

DEVELOPER_ERROR

5

No

Invalid arguments passed to the API

Fix your code. Check product IDs, offer tokens, and parameter construction. This is a programming error.

ERROR

6

Yes

An internal Google Play error occurred

Retry with exponential backoff. If persistent, report to Google.

ITEM_ALREADY_OWNED

7

No

The user already owns this non consumable item

Call queryPurchasesAsync() to refresh your local purchase cache. The user may have purchased on another device.

ITEM_NOT_OWNED

8

No

Attempted to consume or acknowledge an item the user does not own

Call queryPurchasesAsync() to refresh your local purchase cache. The purchase may have been refunded.

NETWORK_ERROR

12

Yes

A network error occurred during the operation

Retry with a short delay (1-2 seconds). Check device connectivity.

SERVICE_DISCONNECTED

-1

Yes

The BillingClient is not connected to Google Play Services

With enableAutoServiceReconnection() (PBL 8), the library retries automatically. Without it, call startConnection() and retry.

FEATURE_NOT_SUPPORTED

-2

No

The requested feature is not supported on this device or Play Store version

Check isFeatureSupported() before calling feature specific APIs. Provide fallback behavior.

SERVICE_TIMEOUT

-3

Yes (Deprecated)

The request timed out

Deprecated in recent PBL versions. Treat as SERVICE_UNAVAILABLE and retry with backoff.

Sub Response Codes (PBL 8.0+)

Sub response codes provide more granular information about why a purchase failed. They are only available in the PurchasesUpdatedListener.onPurchasesUpdated() callback, retrieved via BillingResult.getOnPurchasesUpdatedSubResponseCode().

Sub Response Code

Description

When It Appears

Recommended Action

NO_APPLICABLE_SUB_RESPONSE_CODE

No specific sub response applies

Default value for most responses

Handle based on the main response code only.

PAYMENT_DECLINED_DUE_TO_INSUFFICIENT_FUNDS

User's available funds are less than the purchase price

When the main response indicates a payment failure

Show a message suggesting the user check their payment method balance.

USER_INELIGIBLE

User does not meet eligibility requirements for an offer

When the user attempts to use an offer they are not eligible for

Show standard pricing without the offer. Check your offer eligibility logic.

Accessing Sub Response Codes

kotlin
val listener = PurchasesUpdatedListener {
    billingResult, purchases ->
    if (billingResult.responseCode !=
        BillingResponseCode.OK
    ) {
        val subCode = billingResult
            .onPurchasesUpdatedSubResponseCode
        when (subCode) {
            OnPurchasesUpdatedSubResponseCode
                .PAYMENT_DECLINED_DUE_TO_INSUFFICIENT_FUNDS
            -> showInsufficientFundsMessage()
            OnPurchasesUpdatedSubResponseCode
                .USER_INELIGIBLE
            -> showStandardPricing()
            else -> handleGeneralError(billingResult)
        }
    }
}

Error Handling Decision Tree

Use this decision tree when you receive a BillingResult:

  1. Is responseCode == OK?
    • Yes: Process the result. Done.
    • No: Continue.
  2. Is responseCode == USER_CANCELED?
    • Yes: Do nothing. The user chose to cancel. Done.
    • No: Continue.
  3. Is the error retriable? (SERVICE_UNAVAILABLE, ERROR, NETWORK_ERROR, SERVICE_DISCONNECTED, SERVICE_TIMEOUT)
    • Yes: Retry with appropriate strategy (simple retry for network errors, exponential backoff for service errors). If all retries fail, show an error message.
    • No: Continue.
  4. Is it a cache sync issue? (ITEM_ALREADY_OWNED, ITEM_NOT_OWNED)
    • Yes: Call queryPurchasesAsync() to refresh your purchase cache. Update UI accordingly.
    • No: Continue.
  5. Is it a product issue? (ITEM_UNAVAILABLE)
    • Yes: Refresh product details. The product may no longer be available.
    • No: Continue.
  6. Is it a device/environment issue? (BILLING_UNAVAILABLE, FEATURE_NOT_SUPPORTED)
    • Yes: Show a user friendly message. Do not retry automatically. Let the user initiate a retry.
    • No: Continue.
  7. Is it a developer error? (DEVELOPER_ERROR)
    • Yes: Log the error with full details. Fix the API usage in your code. This should not happen in production.

Retry Implementation Summary

Strategy

Base Delay

Factor

Max Attempts

Use For

Simple retry

1-2 seconds

1x (fixed)

3

NETWORK_ERROR

Exponential backoff

2 seconds

2x

3

SERVICE_UNAVAILABLE, ERROR, SERVICE_TIMEOUT

Auto reconnect

Handled by PBL 8

N/A

N/A

SERVICE_DISCONNECTED

User initiated

N/A

N/A

N/A

BILLING_UNAVAILABLE

No retry

N/A

N/A

N/A

USER_CANCELED, DEVELOPER_ERROR, FEATURE_NOT_SUPPORTED

Want a simpler approach?

The RevenueCat SDK Handbook covers the same topics — with less code and a managed backend.

Related chapters

  • Chapter 8: Error Handling and Retry Strategies

    Every BillingResponseCode explained. Simple retry, exponential backoff, and the complete error decision tree.

    Learn more
  • Chapter 5: Integrating the Play Billing Library

    BillingClient setup, connection lifecycle, product queries, and the four builder methods you must call correctly.

    Learn more
  • Chapter 6: The Purchase Flow

    End-to-end from launchBillingFlow() to acknowledgement: payment dialog, callbacks, pending purchases, and multi-quantity.

    Learn more