Solved

Help Sending Stripe Webhooks (REST API)

  • 19 September 2022
  • 25 replies
  • 1175 views

Badge

I’ve been reading docs for hours and hours. I’ve read this post: https://www.revenuecat.com/docs/stripe

 

To accept stripe payments I can use a Stripe Checkout (https://stripe.com/payments/checkout) It’s a stripe payment page hosted by stripe which prevents me from having to set up my own payment server.

 

Here’s where I’m lost. After I receive a payment, I have to “Send Stripe tokens to RevenueCat”. How do I do that? I can’t figure out how to initiate a POST request from Stripe Checkout that sends the required info to Revenuecat. Here’s what I have to sent to Revenuecat…

 

curl -X POST \
https://api.revenuecat.com/v1/receipts \
-H 'Content-Type: application/json' \
-H 'X-Platform: stripe' \
-H 'Authorization: Bearer YOUR_REVENUECAT_STRIPE_APP_PUBLIC_API_KEY' \
-d '{ "app_user_id": "my_app_user_id",
"fetch_token": "sub_xxxxxxxxxx"
}'

 

Any help would be greatly appreciated. 

 

Chris

icon

Best answer by Jens 6 October 2022, 12:12

View original

25 replies

Userlevel 5
Badge +7

@Aliaksei okay yeah this is exactly like I thought.

Add the following to the checkoutOptions object: clientReferenceId: <YOUR USER’S ID>. That will store your app user ID in the checkout session. You need a user ID to associate the purchase in RevenueCat with.

Then, you need to do the “backend” part. As mentioned, you can use Zapier for that if you don’t want to actually run backend code, or you could also set up a Firebase Cloud Function or something. All you need to do is catch checkout.session.completed events from Stripe, extract the session ID and the clientReferenceId, and use that to make a POST request to the /receipts endpoint.

If you go down the Zapier route, the trigger you need to select is “Catch Hook in Webhooks by Zapier”. That will give you a webhook URL to use. You want to set that up as a webhook destination in the Stripe dashboard for the checkout.session.completed event. Then, you have to set up a “Webhooks by Zapier” action in Zapier based on that trigger that will make the correct POST request, using the data from the trigger. 

Userlevel 5
Badge +7

@Hemang yes, you can do that. RevenueCat always validates the purchase with Stripe after it gets posted to the REST API so there is no risk in this being misused to gain free access or something. The only downside is if something happens to the frontend between the purchase finishes and the request gets sent (eg. customer closes the browser), RevenueCat won’t know about the purchase.

Userlevel 5
Badge +7

You can make this request to the REST API from your frontend as well. All you need is:

  • The app user ID you want to link the subscription to
  • The Stripe Checkout Session ID
  • Your Stripe public API key that you can find from the RevenueCat web application

E.g., if you’re using the fetch API, you could do the following:

const RevenueCatStripePublicAPIKey = ...
const StripeCheckoutSessionID = ...
const appUserID = ...

const options = {
method: 'POST',
headers: {
accept: 'application/json',
'Content-Type': 'application/json',
'X-Platform': 'stripe',
Authorization: 'Bearer ' + RevenueCatStripePublicAPIKey
},
body: JSON.stringify({app_user_id: appUserID, fetch_token: StripeCheckoutSessionID})
};

fetch('https://api.revenuecat.com/v1/receipts', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));

 

You can make this request to the REST API from your frontend as well. All you need is:

  • The app user ID you want to link the subscription to
  • The Stripe Checkout Session ID
  • Your Stripe public API key that you can find from the RevenueCat web application

E.g., if you’re using the fetch API, you could do the following:

const RevenueCatStripePublicAPIKey = ...
const StripeCheckoutSessionID = ...
const appUserID = ...

const options = {
method: 'POST',
headers: {
accept: 'application/json',
'Content-Type': 'application/json',
'X-Platform': 'stripe',
Authorization: 'Bearer ' + RevenueCatStripePublicAPIKey
},
body: JSON.stringify({app_user_id: appUserID, fetch_token: StripeCheckoutSessionID})
};

fetch('https://api.revenuecat.com/v1/receipts', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));

 

 

I have started to create a proof of concept with Stripe and Revenue cat as well.

@Jens , I’m also a bit stuck on the documentation here. After I’ve setup the webhook, enabling Revenue cat to receive information about Stripe subscription purchases like this. How does Revenue cat figure out the relationship between Revenue cat customer information and Stripe user/subscription?

One of (the only?) alternatives is to explicitly give Revenue cat this information. What I’ve found there is exactly what you mention above.


You can send your Stripe subscriptions to RevenueCat through the POST receipt endpoint.

 

“You can” sounds more like it is optional, but I’m not sure. Are there other alternatives? Is it possible to link them through using the Stripe customer id as Revenue cats app user id?

What worries me a bit is that the suggested solution of sending this from the client after the checkout seems a bit brittle. What happens if there is an error on the client? A network hiccup? Is that relation between Stripe and Revenue cat forever lost then?

To me it sounds like we need a more robust solution if we have to tell Revenue cat about the relationship (and I can’t really see how it could work without us giving that information to Revenue cat).

What alternatives do you see?

Userlevel 5
Badge +7

@developer Posting to the receipts endpoint is the only way to associate RevenueCat customer with Stripe subscription, currently. You can make the request from the frontend, but the better (and more reliable) solution is to make them from the backend if you have one.

Userlevel 5
Badge +7

@developer that sounds like a feasible solution. I don’t think there’s a risk of a race condition there; the only thing that would be tricky is if the subscription renews before the receipt is posted (but even then, we would simply reflect the latest state of the subscription in RevenueCat, we might just not have the complete history. Also, that’s not going to happen as a race condition unless you have subscriptions that renew every few seconds)

Badge +2

@developer Posting to the receipts endpoint is the only way to associate RevenueCat customer with Stripe subscription, currently. You can make the request from the frontend, but the better (and more reliable) solution is to make them from the backend if you have one.

@Jens  Thank you! Does that mean that when we make request from the frontend..we can skip setting up webhooks in the backend and just use the checkout_session_id from the success URL after the stripe checkout has finished?

Badge +1

You can make this request to the REST API from your frontend as well. All you need is:

  • The app user ID you want to link the subscription to
  • The Stripe Checkout Session ID
  • Your Stripe public API key that you can find from the RevenueCat web application

E.g., if you’re using the fetch API, you could do the following:

const RevenueCatStripePublicAPIKey = ...
const StripeCheckoutSessionID = ...
const appUserID = ...

const options = {
method: 'POST',
headers: {
accept: 'application/json',
'Content-Type': 'application/json',
'X-Platform': 'stripe',
Authorization: 'Bearer ' + RevenueCatStripePublicAPIKey
},
body: JSON.stringify({app_user_id: appUserID, fetch_token: StripeCheckoutSessionID})
};

fetch('https://api.revenuecat.com/v1/receipts', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));

 

@Jens  hello, could you help me with this? I have a few questions: 
1) at what point can I call this fetch from the client side?
2) How can I get StripeCheckoutSessionID?
I use stripe checkout without my server

Userlevel 5
Badge +7

@Aliaksei How are you using Stripe checkout without a server, using this client-side integration? I don’t think you can get the checkout session ID on the client side using that. 

My suggestion would be to add the app user ID as metadata to the Stripe checkout session (e.g., as clientReferenceId), and then set up a Stripe webhook for checkout.session.completed. If you don’t have a backend server, you could use Zapier for that. The webhook handler would extract the clientReferenceId and the checkout session ID and post that to the RevenueCat REST API.

 

Badge +1

@Jens Thank you very much for the answer, but I may be confused with this.
I have a subscription selection page, clicking on which redirects me to a stripe payment page, and after successful payment I would like to send a receipt to
https://api.revenuecat.com/v1/receipts

Please tell me how I can implement this? And is it possible without connecting your own server? My part of the code:

 

Badge

@Jens Thank you! I’ll start working on this.

Have a great day.

Chris

Badge

I’d like to get a better understanding of the stripe integration.

So far I’ve

Are both of these necessary?   Do we need to tell the RevenueCat receipts API about a purchase, or can RevenueCat get this information from the connection created in my first bullet point above?

What does the connection do versus what does telling the receipts API do?  Can I get an explanation on how these two things work together?

Hi! Could you tell me if this is a correct approach?

I’m trying to implement an embedded Stripe Checkout https://stripe.com/docs/checkout/embedded/quickstart, so here is what I do:

  1. I create a checkout session 
  2. A user completes a payment via Stripe
  3. Stripe sends user back to my site via return_url with the session_id as get parameter
  4. I use the session_id to retrieve session status and if it’s a ‘complete’ status I then make a post call to https://api.revenuecat.com/v1/receipts
  5. I expect an INITIAL_PURCHASE webhook from RevenueCat

Does it appear to you as a reliable solution?

And one more question please, would RC send me a RENEWAL webhook when a subscription has been renewed through Stripe?

P.S. I have a Stripe webhook pointing to RC as docs says.

Badge +1

@Jens Hello, thanks a lot for your help in the previous answers, it helped me. Now I have a task to do this using my backend, but I can't find information how can I use one account in RC for testing and production? And can I set it up somehow? There is a problem with setting up webhooks for these modes

Userlevel 5
Badge +7

@Aliaksei the easiest is probably to set up separate projects in RevenueCat for testing and production, that is what a lot of our customers do. 

Badge +1

@jens

What happens when the subscription fails? (payment update?)

Do we need to forward our own web hook event to RevenueCat? The docs are non-existent on this.

Also why are we using Stripe for web, don’t you guys have your own payment system for credit cards?

Badge +1

@Jens for example we handle the following manually.

 

Userlevel 5
Badge +7

@Oliver Dixon :

What happens when the subscription fails? (payment update?)

Do we need to forward our own web hook event to RevenueCat? The docs are non-existent on this.

I am not sure what you mean. You should set up a customer.subscription.updated and invoice.updated webhook to send to RevenueCat as per our documentation, that will take care of updating the subscription on our end. You do not need to send anything to us from your client / backend in that case. Only the initial creation of the subscription needs to happen via a call to our REST API.

Also why are we using Stripe for web, don’t you guys have your own payment system for credit cards?

No, we do not. RevenueCat is not involved in processing of payments directly, neither for mobile (where that happens via the respective app stores), nor on web (where we currently support Stripe)

Badge +1

@Jens thanks for the great answer, looks like we are going to use RevenueCat.

There’s only one issue we’re not sure about.

Flutter for web is becoming very popular, we have a few platforms on it now with customers.

Right now our payment solutions are a mess.

On the Flutter version of RevenueCat for web, does it provide the payment UIs or do we forward the user to the stripe payment UIs and subscription management UIs?

 

Userlevel 5
Badge +7

For Flutter Web, unforunately the support is limited right now and you will have to integrate with Stripe directly to make payments. We plan to eventually better support this so you can use the same code across mobile and web, but it’s not on the near term product roadmap.

Badge +1

@Jens dam you’d really be a market leader if you had all 3 platforms plus the option for physical products. At the moment the Flutter payment SDKs for web are non-existent.

@Jens

Thanks for you reply. I think we will opt in for listening on some Stripe webhook ourselves to post the a receipt to Revenue cat then.

Is there any race condition between Revenue cat receiving the first webhook event from Stripe (through the webhook integration we setup in Revenue cat) and us posting the receipt?

For example, if we listen to a Stripe event “something.happened.in.stripe” and we react on our server by posting a receipt to Revenue cat. What would happen if the Revenue cat webhook receives “customer.subscription.updated” before that? Do we end up with some inconsistent state or will Revenue cat catch up and build the correct information state once we post the receipt even if that happens later in time?

Badge +2

@Aliaksei okay yeah this is exactly like I thought.

Add the following to the checkoutOptions object: clientReferenceId: <YOUR USER’S ID>. That will store your app user ID in the checkout session. You need a user ID to associate the purchase in RevenueCat with.

Then, you need to do the “backend” part. As mentioned, you can use Zapier for that if you don’t want to actually run backend code, or you could also set up a Firebase Cloud Function or something. All you need to do is catch checkout.session.completed events from Stripe, extract the session ID and the clientReferenceId, and use that to make a POST request to the /receipts endpoint.

If you go down the Zapier route, the trigger you need to select is “Catch Hook in Webhooks by Zapier”. That will give you a webhook URL to use. You want to set that up as a webhook destination in the Stripe dashboard for the checkout.session.completed event. Then, you have to set up a “Webhooks by Zapier” action in Zapier based on that trigger that will make the correct POST request, using the data from the trigger. 

Thanks Jens. I’ve been struggling with this for hours as well trying to wrap my head around how RevenueCat understand who the user is making the purchase. RC might want to consider adding this to the Stripe Web Payment docs

@Jens , thank you very much for quick replies. I think we have all the pieces to proceed the implementation :)

 

Have a nice day.

Reply