#яσчαℓтℓя
1 messages · Page 1 of 1 (latest)
Hi Soma
Well, our client takes one-off payments from customers for various digital products such as classifieds and auctions.
I did initially go down the route of using the checkout API to create invoices until I realised that you cannot use this API for one-off invoices
As explained here in the second sentence
So, I have built a custom invoicing flow for customers who need to check out some of our client's products. In most, if not all cases, the flow is very similar to the checkout flow (except we don't have payment intent, session or anything like that)
Essentially the flow is this:
- User signs up and Stripe customer is created. They enter their payment method details (this is required to sign up to the platform)
- User bids on auctions or sells an auctions - both buyer and seller are charged a commission. This is triggered by cronjobs and invoices are sent accordingly
- User decides they want to buy a classified ad. During classified creation, they must confirm their order. When they click "Confirm Order" - we do a few things - generate an invoice (create), generate the invoice items (create invoice items), finalize the invoice and make the payment of the invoice.
We do this so it acts like a checkout flow.
However. We've run in to some weird 'race-condition-esque' issues. For example. Let's say an auction ends and triggers invoice create, finalise and pay flow for both buyer and seller.
But at the same time, the same user is ordering a classified ad. This ultimately causes some issues where the invoice items are wrong. The code assumes that the auction invoice item is supposed to be the classified order invoice item or vice versa
How do you suggest we tackle this problem?
It's ultimately not a good situation because there is the possibility of invoicing customers with the incorrect line items.
The main question I have is how do you suggest we have a checkout-like flow for one-off payments using invoices when a user could (by nature of how we have configured the invoice API integration) create line items for two separate things at the exact same time ?
Hi there 👋 I'm jumping in to lend a hand, please bear with me a moment while I catch up on the context here.
Sure no probs
I'm not sure to fully understand the race-condition-esque issues you are having ?
You are creating the invoice and then you attach the invoice_item to that invoice. In other words, you set the invoice property when creating the invoice_item, no ?
Yes that is true
I guess the best way to explain it is through what actually happened
In fact, let me see if I can find the webhook logs
we_1LibZqIlSjun4h3swLsFoj6D
This is our webhook ID
Ah ok.
Stripe does not guarantee delivery of events in the order in which they are generated
https://stripe.com/docs/webhooks/best-practices#event-ordering
Yeah so that's maybe what's causing the issue
Do you have any suggestions for guaranteeing continuity between webhook events and our database?
We keep records of every Stripe Transaction in our database
Here is the odd one
Now, if you click the invoiceDownloadUrl
You will see the description. Well, the description is incorrect. This description was set by a Webhook event
evt_1LzLFEIlSjun4h3s9C8NQGMT
It's a really challenging problem to solve
If your implementation is based on webhook event order. then you need to redesign your flow.
What do you mean by this ?
Basically what I meant is that an invoice was sent and in our database, the Stripe Transaction record has a related ID for the item the invoice was for. However the related item ID and the actual invoice description do not match.
Same with all the other fields in our database
If you look above at the JSON I sent, at the bottom it shows VAT
VAT: 58000
And you check the VAT, it is not the same. Basically, something has gone wrong in the webhooks.
Could the solution be to move all invoice finalization logic our of the webhook and into a controller instead?
I'm 95% sure it's the webhooks that are making our database records out of sync, and ultimately the invoices being associated with incorrect items in our database
So the event you shared evt_1LzLFEIlSjun4h3s9C8NQGMT is for this invoiceId in_1LzLFCIlSjun4h3s1Trzpweo. While the record you are showing is for another invoice which is in_1LzLFDIlSjun4h3sVeuwJmZT
Those are two different invoices
Okay let me check
Yes exactly
So let me show you
These are the three rows in question
Let me know if you are able to view this?
Could you please provide the content here in messages
I'm not sure I'm following you. The webhook event is related to an invoice and you are referring in your database to completly another invoiceId
so you'll have different values at the end
Ok let me see if I can explain concisely
yes please!
evt_1Lz2N8IlSjun4h3sxNFv5xdX
Please first check this event
As you can see, the invoice ID for this event is in_1Lz2N8IlSjun4h3sbRa3z7rD
And the idempotency key is create-invoice-ef27aad3-17db-4c92-a731-4350571df7d5
Make note of the createdAt time as well 1667239566
Note that the idempotency key is matching the webhook event, but the invoice ID is not
As you can see in our webhook event code, we are updating the record in our database when the event comes through
We then update the record again when the invoice is finalized
But yes, as you can see it is causing some weird inconsistencies. The data in our database is not correct, the relational data is correct but the data the is updated via the webhook is out of sync.
I guess it all comes back to what you said earlier:** Stripe does not guarantee delivery of events in the order in which they are generated**
So my question becomes, how do we keep the integrity in our database when Stripe cannot guarantee delivery of events in the order in which they are generated?
This record has an idempotencyKey: ef27aad3-17db-4c92-a731-4350571df7d5 and an invoiceId in_1LzLFCIlSjun4h3s1Trzpweo different to the webhook event Id (create-invoice-ef27aad3-17db-4c92-a731-4350571df7d5 and in_1Lz2N8IlSjun4h3sbRa3z7rD
The idempotencyKey are not the same also not just the invoiceId
It's because we append it
The idempotency key is appended, sorry forgot to mention that
first off all you need to keep the same idempotencyKey on all sides
In your database, persist the event_id also
not sure that you are referring to the same event, which did triggered the record in your database
evt_1Lz2N8IlSjun4h3sxNFv5xdX
evt_1LzLFDIlSjun4h3s5SOBYCIY
Both of these events have the same metadata
{ transactionId: 1 }
However, according to my code I am surprised that is the case.
They should have different transactionIds
Okay so you suggest persisting the event ID
I will redesign this flow then. There's clearly something wrong. I think I might try to stay away from webhooks as it can be quite confusing and often getting unexpected behaviour which, to be fair, might be my fault but yeah, it's not what we need when it comes to payments
Hello, soma had to step out but I can help. Taking a minute to catch up in this thread...
No worries, I think we are done here
I am struggling a bit but it seems like the solution is to just not use webhooks as much as feasibly possible
Gotcha, good to hear you have a way forward at least. Let me know if you come across any further questions