-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensuring webhook is called before client is notified of new entitlement #1094
Comments
👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out! |
Hi, this webhook delay could have to do with not having server notifications enabled. Can you make sure that you have these enabled for the platforms you are using? See our docs here for how to do this: https://www.revenuecat.com/docs/platform-resources/server-notifications |
@HaleyRevcat thanks, I already have server notifications enabled. But I am looking for a guarantee that my app will be notified of the successful purchase only after the webhook has been successfully called. There is nothing in the docs saying that "A purchase request will only return a successful result after the webhook has been called, assuming that a webhook has been configured, and that server side notifications have been enabled". This may already be true, but I need to know that this is a fundamental rule about how RevenueCat works. |
Hi, any updates? Does this guarantee hold? The only alternative I can think of is that upon the client being notified of a successful purchase, the client should call the server and ask the server to pull down the user's purchase information if the webhook has not yet been called, so that the client can know that the server is up to date. It seem silly to have to do that, but if no guarantee can be made that the webhook has been called before the client is notified, then there is no alternative. If the client tries to call a privileged endpoint immediately after being notified of a successful subscription, and the server has not yet been notified via a webhook, then the endpoint call will fail (in other words, there would be a race condition). |
Hi, Your alternative is the right idea, you don't want to handle both at the same time. You should wait until your server gets the webhook then the server can tell the device that it got the webhook, or vice versa where if you get the entitlement in app without the webhook, then tell your server. I believe the easiest way to go about this would be to wait for the webhook as this is more convenient. |
@HaleyRevcat That is not convenient at all! In the client (the app), currently I call await Purchases.purchasePackage(package) and when that call returns, I check the It also means that I can't update the UI to show the new entitlement info as soon as the All you would have to do to fix this on your end is If the webhook call fails, then the Please escalate this, this is a very serious flaw in the design of the RevenueCat package purchasing flow, and it is a major pain to have to code defensively around this problem. |
So just to clarify, this is the flow I am looking for (assuming a webhook is configured):
Currently the following flow is the only way of guaranteeing that the app and the app server have the same information on purchases as RevenueCat:
This latter flow is much more inefficient -- there are several extra roundtrips, and the
|
I see how this can be awkward, but having us delay the response until the webhook returns a success would introduce a lot of complications that could ultimately lead to a bad user experience. For one, we don't control servers other than our own, so webhooks might take a long time to get a response, and they might fail if a customer's servers are down or misbehaving, but that doesn't in all cases mean that the user should not get access. If anything, not granting access in this case is fairly rare (although, I can see that it is what you need). Note that a user whose purchase went through but then the webhook failed is still getting charged, and their purchase was registered correctly by our servers. Much like relying on a push notification can be complicated because delivery isn't guaranteed, webhooks suffer from the same problem since we can only control our own servers. As for finding ways to have your server provide service only if the user has access, it's still a good idea for your server to check with ours in any case - a malicious user could be replicating network calls from the app to your server in order to get free access, and they could even do this from a non-jailbroken device. So I'd recommend basically:
Doing this, any time the webhook arrives before success returns, there would be no extra backend calls. And when it does, there would only be one extra call to Hope this helps! |
OK, so you basically confirmed that the `CustomerInfo` received from
purchasing a product is more or less useless, except as a trigger for the
app to call the app server, so that the server can call the REST endpoint
to get a server-trusted view of the ground truth.
However the following suggestion is basically impossible, because there's
no way for the app server to know when it receives a webhook request if
that request is supposed to be paired with the previous purchase
confirmation received by the app, or the next one -- and there is no way to
know the time delay or ordering between the app and the app server
receiving updated views of the same info:
- you can use the webhook and its contents as way to cache entitlements
so if the webhook arrived before your app's request, you don't need to
contact our servers
However, there is also a second race condition here, caused by the relative
ordering between the webhook call being received, and the new
entitlements/purchases being written to the RevenueCat databases. Can you
please confirm whether it is guaranteed that by the time the webhook call
is initiated, the updated entitlement/purchase info has been written to the
RevenueCat database, so that if my webhook function calls back to the
RevenueCat REST endpoint (as your docs suggest, rather than parsing the
webhook request itself), the latest purchase will always be included in the
result of the REST call?
I am concerned that since you can't offer any guaranteed ordering between
the app purchase completing and the webhook call being made, then you also
won't be able to offer any guaranteed ordering between the webhook call
being made and the RevenueCat database being updated for the REST call to
return the latest data. If that is the case, that's an even more serious
problem than the first problem!
This would all be a lot simpler if you could guarantee the following
ordering:
1. Customer makes purchase request, which is approved, but purchase request
awaits the next two steps before returning.
2. New purchases are written to the RevenueCat database, as used by REST
endpoint calls, and (crucially) the database update is awaited.
3. Only after the previous step has completed, webhook calls are made, and
(crucially) their completion awaited.
4. Only after the previous step has completed, the purchase request returns
a successful result back to the app.
Implementing this is trivial in any async/await-capable programming
language. I would hope you would simply make this change, because it would
solve every problem I have raised, and it would allow you to offer much
stronger guarantees to your users about the validity of each data view and
each event.
…On Fri, Jun 28, 2024 at 3:45 PM Andy Boedo ***@***.***> wrote:
@lukehutch <https://github.com/lukehutch>
I see how this can be awkward, but having us delay the response until the
webhook returns a success would introduce a lot of complications that could
ultimately lead to a bad user experience.
For one, we don't control servers other than our own, so webhooks might
take a long time to get a response, and they might fail if a customer's
servers are down or misbehaving, but that doesn't in all cases mean that
the user should not get access. If anything, not granting access in this
case is fairly rare (although, I can see that it is what you need). Note
that a user whose purchase went through but then the webhook failed is
still getting charged, and their purchase was registered correctly by our
servers.
Much like relying on a push notification can be complicated because
delivery isn't guaranteed, webhooks suffer from the same problem since we
can only control our own servers.
As for finding ways to have your server provide service only if the user
has access, it's still a good idea for your server to check with ours in
any case - a malicious user could be replicating network calls from the app
to your server in order to get free access, and they could even do this
from a non-jailbroken device.
So I'd recommend basically:
- upon a successful purchase, call your backend endpoint, then have
your backend use our rest API to ensure that the call is valid
- you can cache the entitlements for the user so you don't need to
perform this check every time
- you can use the webhook and its contents as way to cache
entitlements so if the webhook arrived before your app's request, you don't
need to contact our servers
Doing this, any time the webhook arrives before success returns, there
would be no extra backend calls. And when it does, there would only be one
extra call to subscriptions.
Hope this helps!
—
Reply to this email directly, view it on GitHub
<#1094 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGGCKIYCMJG2KYS5IZE3D3ZJXKRNAVCNFSM6AAAAABI4CLSW6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOJXGY4TSNBYGM>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
For those who use Firebase claims and specially claims inside firestore security rules : This is painful specially to manage subscription cancelling, renewal and real time. |
This is by far the biggest problem and liability of using RevenueCat. Please, RevenueCat developers, reconsider this bugfix request. The change is very simple: just wait to return from any API call until the RevenueCat view of the entitlements and purchases is consistent with the app store view. |
In my app, when the user purchases a product, the app is notified of the new entitlement, and then separately the server is notified of the new entitlement via the webhook.
However, I need a way to guarantee that the webhook call is completed before the app is notified of the new entitlement. Otherwise, if the app receives the entitlement first, the app may try to call a method on the server that the serve thinks the user should not have access too (because the webhook call hasn't been received yet, so the endpoint is not yet authorized for this user).
Is there some way to guarantee that the webhook call is always completed before the client is notified of the new entitlement? (Or is that already the behavior of RevenueCat?)
Sorry if this is a FAQ, I didn't see anything about this in the docs...
The text was updated successfully, but these errors were encountered: