Let's say I'm creating a PWA (Progressive Web App) where products can be added by users. Prices of these products are variable from 0,01 EUR to 1,00 EUR. I'm using Stripe for payments. The Stripe Order object do not support dynamic price, passed on the fly, without any reference (kind of foreign key). To accept the Order, Stripe needs a reference to a SKU. This SKU will be, in my case, a variation of the price, on the product. It means that, to cover all variations, I need 100 SKUs, from 1 (0.01 EUR) to 100 (1,00 EUR). So, for each product created in Stripe, I need to create 100 SKUs in Stripe.
I tried to insert a test dataset of 200 products, which means (200 products + (200 x 100 SKUs)) = 20200 requests. I got a surprising "Request rate limit exceeded" error from Stripe. Less than half of records where created... :(
That "Request rate limit exceeded" is the core of the problem.
Right now, the insertion process is the following (x 200):
- Create product in Firestore.
- Firebase cloud function listener :
- OMG new product inserted in Firestore. Ok let's :
- Import official nodejs Stripe & Algolia libraries
- Create product in Stripe to make it billable
- Create the 100 SKU related to the product in Stripe, with Promise.all (This is where, at some point, I end up with a rate limit error, because my concurrent cloud functions instances are using the same Stripe key, which means the same Stripe account)
- Create product in Algolia to make it searchable
I need solutions to counter this Stripe API rate limit error. I have several solutions in mind :
Solution 1 :
Be able to increase Stripe rate API limit for a given amount of time. Not sure this is possible.
Solution 2 :
Be able to use differents Stripe keys, then rotate over them, to perform admin stuff, such inserting multiple products/SKUs in Stripe. Ultimately on production, be able to create programmatically 1 Stripe key per user, so each user would have its own limit. Not sure this is possible.
Solution 3 :
Slow down insertion process in javascript. Don't know how to perform that. Besides, Cloud functions have a budget/limit of 60 seconds for javascript execution. So I can't delay too much.
Solution 4 :
Delay work using Pub/Sub (?), or Firestore Triggers For example, having an integer in Firestore, that each function call increments, and same function listen the write to re-increment he number, etc, etc, etc, until the number equals 100 for the 100th SKU. That solution would sequentialize the 100 SKUs writes in Stripe. Not sure this will really slow down enough the work to be under the API rate limit. In addition, such a solution would cost lots of money : 100+ Firestore writes, and 100+ functions calls to perform these writes, for only one product, which means 20000+/20000+ for the 200 products. That would be expensive.
Solution 5 :
Perform Just-In-Time insertions, when user pays. The server side algorithm, after a Payment Request API call, might look like this :
Create order in Stripe
If error 'No such sku...' catched {
For each SKU { // Ideally filter here SKUs to create (only those in error)
If price not between 1 and 100 {
continue // Bad price, not legit
}
Create SKU in Stripe
If error 'Already exists' {
continue // no creation needed for that SKU
}
If error 'No such product...' catched {
If productId does not exists in Firestore {
continue // Bad productId, not legit
}
Create product in Stripe
}
Create SKU in Stripe
}
}
Create order in Stripe
This last solution could do the job. But it might comes with some delay for the user when it executes payment, which could increase stress. Plus it might increase Stripe calls during the business hours. Many purchases in same time could lead to a Stripe API rate limit error, especially with well furnished carts (let's say an average of 30 products in the cart, so in worst case 30+ HTTPS calls during payment, times 1000 users = 30000 calls => Stripe error). That problem might decrease over time for a given product, because once a SKU is created it is created definitively. Still, as there would be new products, so products with zero SKU at creation, every day, the problem remains.
What do you think ? Do you have any other ideas ?