Reputation: 24395
I have a webhook for the Stripe event of invoice.payment_failed
. This webhook is triggered whenever a customer payment fails for an invoice.
The webhook can be called multiple times per month if the user can insufficient funds for example.
My application allows a user to login to their account and initiate a manual attempt to pay the invoice if they have already had a failed payment attempt that month. It is initiated through the below call:
stripe.invoices.pay(invoiceId);
Docs: https://stripe.com/docs/api/invoices/pay
The above method also calls the invoice.payment_failed
webhook. As far as I can tell, there are no ways of telling whether the webhook was initiated by a Stripe internal action (such as a payment retry), or a manual API action such as my call above.
I compared the event objects between the two types of calls and they are identical. Are there any other ways of determining what triggered the webhook?
Upvotes: 0
Views: 1841
Reputation: 3217
After running into the same issue I have figured out how to differentiate invoice.payment_failed
webhook events from manual vs automated attempts.
Take a look at the attempt_count field on the invoice object, this only increments on automated retries not on manual API calls e.g: stripe.invoices.pay(invoiceId)
https://stripe.com/docs/api/invoices/object#invoice_object-attempt_count
The way this works in my webhook endpoint is I look up the userRecord which contains a property user.subscription.attemptCount
and I compare this to the attempt_count from the webhook payload.
Documentation for this property is as follows:
Number of payment attempts made for this invoice, from the perspective of the payment retry schedule. Any payment attempt counts as the first attempt, and subsequently only automatic retries increment the attempt count. In other words, manual payment attempts after the first attempt do not affect the retry schedule.
Upvotes: 2
Reputation: 71
A simple way to address this problem is to proxy the webhook requests that are initiated by the Stripe internal action. You can use a free webhook routing tool such as Pipedream (or equivalent) and append a field to the request.
First, create an endpoint to proxy the webhook
Second, handle the event:
{
"id": "in_1DGXg2BSZsoltGfCP90zepqA",
"object": "invoice",
"account_country": "US",
"account_name": null,
"amount_due": 999,
....
Third, add an identifier Stripe internal action:
$event.body.identifier = 'internal_action'
And then route the data to the endpoint in your application.
Here is an example pipeline with this process working -- https://urlzs.com/nGd1a
Upvotes: 0
Reputation: 5857
Before calling stripe.invoices.pay(invoiceId)
, you could add something to the metadata
field to be able to identify the invoice later: https://stripe.com/docs/api/invoices/update#update_invoice-metadata
Upvotes: 2