Skip to main content
Solved

Questions regarding "Restore a Google Play purchase" API

  • September 9, 2026
  • 1 reply
  • 21 views

Forum|alt.badge.img

I’m currently writing an API endpoint for use by an Android app, to interface with the “Restore a Google Play purchase by order ID” REST API endpoint. This is due to well-known “consumed purchase” misconfiguration issue. It’s hard to test it due to the nature of the issue, and therefore I have a few questions.

  • If the restoration succeeds (i.e. the response code is 200), can I immediately query the customer info (using the app SDK) and expect the entitlement that wasn’t present before to now be immediately present, or does it take time? I will disable caching for the request.
  • If the customer entered an invalid order_id (the GPA… value) what response code should I expect from the API? I’m seeing 404, is that correct?
  • What safeguards are there for customers restoring to multiple devices, for example if their order_id became public? Once an order is restored can it be restored to other users? How much protection should I build into my API?
  • Are there any other potential vectors for abuse I should be aware of?
  • Is the {customer_id} path segment in the REST API URL the full, URI-encoded “$RCAnonymousID:...” value, or just the numbers after $RCAnonymousID:?

Also, are there any other common response codes?

Best answer by cvalderrama-rc

Hi there!

  • If the restoration succeeds (i.e. the response code is 200), can I immediately query the customer info (using the app SDK) and expect the entitlement that wasn’t present before to now be immediately present, or does it take time? I will disable caching for the request.

Yes. By the time the API returns a 200, the backend state has been updated. A cache-bypassing SDK getCustomerInfo request should show the entitlement immediately; no additional wait is required.

  • If the customer entered an invalid order_id (the GPA… value) what response code should I expect from the API? I’m seeing 404, is that correct?

Yes. A 404 is the expected response when the order cannot be found.

  • What safeguards are there for customers restoring to multiple devices, for example if their order_id became public? Once an order is restored can it be restored to other users? How much protection should I build into my API?

A GPA order ID is not proof of purchase by itself. Restore the purchase only to a logged-in App User ID. Once the order has been associated with that user, another customer attempting to restore it will receive a 422 response.

Restoring the purchase on another device is fine, provided the customer is logged in with the same App User ID. The restore operation is idempotent for that user.

Because the endpoint requires a secret API key, your backend is the primary security boundary. Do not expose an unauthenticated endpoint that accepts an arbitrary GPA order ID, restore purchases to anonymous users, or allow the client to choose the customer ID. Require authentication, restore only to the authenticated account, and rate-limit attempts. With these protections in place, a leaked order ID alone should not be sufficient to claim a purchase.

  • Are there any other potential vectors for abuse I should be aware of?

Requiring authentication and following the safeguards above should address the primary abuse vectors without unnecessary overengineering.

  • Is the {customer_id} path segment in the REST API URL the full, URI-encoded “$RCAnonymousID:...” value, or just the numbers after $RCAnonymousID:?

Use the full URI-encoded $RCAnonymousID:... value, not only the portion after $RCAnonymousID:.

 

Let me know if there’s anything else I can help with!

Best,

1 reply

cvalderrama-rc
RevenueCat Staff
Forum|alt.badge.img
  • RevenueCat Staff
  • Answer
  • September 9, 2026

Hi there!

  • If the restoration succeeds (i.e. the response code is 200), can I immediately query the customer info (using the app SDK) and expect the entitlement that wasn’t present before to now be immediately present, or does it take time? I will disable caching for the request.

Yes. By the time the API returns a 200, the backend state has been updated. A cache-bypassing SDK getCustomerInfo request should show the entitlement immediately; no additional wait is required.

  • If the customer entered an invalid order_id (the GPA… value) what response code should I expect from the API? I’m seeing 404, is that correct?

Yes. A 404 is the expected response when the order cannot be found.

  • What safeguards are there for customers restoring to multiple devices, for example if their order_id became public? Once an order is restored can it be restored to other users? How much protection should I build into my API?

A GPA order ID is not proof of purchase by itself. Restore the purchase only to a logged-in App User ID. Once the order has been associated with that user, another customer attempting to restore it will receive a 422 response.

Restoring the purchase on another device is fine, provided the customer is logged in with the same App User ID. The restore operation is idempotent for that user.

Because the endpoint requires a secret API key, your backend is the primary security boundary. Do not expose an unauthenticated endpoint that accepts an arbitrary GPA order ID, restore purchases to anonymous users, or allow the client to choose the customer ID. Require authentication, restore only to the authenticated account, and rate-limit attempts. With these protections in place, a leaked order ID alone should not be sufficient to claim a purchase.

  • Are there any other potential vectors for abuse I should be aware of?

Requiring authentication and following the safeguards above should address the primary abuse vectors without unnecessary overengineering.

  • Is the {customer_id} path segment in the REST API URL the full, URI-encoded “$RCAnonymousID:...” value, or just the numbers after $RCAnonymousID:?

Use the full URI-encoded $RCAnonymousID:... value, not only the portion after $RCAnonymousID:.

 

Let me know if there’s anything else I can help with!

Best,