#cyral_refund-subscription-attribution

1 messages ยท Page 1 of 1 (latest)

gilded dockBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1425979767076687911

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

nimble shell
#

discord wont let me type that many characters so attaching the rest of my question as a txt file

#

Better illustration:

Here is the charge in workbench, it has the invoice_id which is exactly what I want.

#

Even if I run stripe charges retrieve ch_3SCp2mBHmn7qM5jZ0YCO0qqZ in the Stripe Shell in my browser, I get the invoice ID back

#

Running the exact same command in the Stripe CLI on my local machine or with curl returns a response without the invoice field

dull bramble
#

Hi there,
the different results where an invoice is present while it isn't in your Srtipe CLI, curl, local machine has most likely to do with API versions. We had beginning of the year an API release with a lot of breaking changes. One of them being that we removed the invoice property from charges, and payment intents.

#

Basically we have removed the invoice property from the charge, and introduced a new object called Invoice Payments. So when using API version 2025-03-31.basil and later, you can use the charge ID (or Payment Intent ID) on List all all Invoice Payments https://docs.stripe.com/api/invoice-payment/list. The response will contain the invoice ID.

nimble shell
#

Ok that makes sense, thanks

#

I just tried with stripe charges retrieve ch_3SCp2mBHmn7qM5jZ0YCO0qqZ --stripe-version 2024-06-20 | grep "invoice" and sure enough it includes the invoice with the older version

dull bramble
#

Yeah that makes sense

nimble shell
#

I'm looking into this still.. not immediately clear how to relate refunds back to the invoice/subscription though

#

I see there is a invoice_payment.paid event which lets you get the invoice actually, great. easier than making another call to expand the payments of the invoice and try to find the right one

#

wish there was an invoice_payment.refunded but I guess refunds are a bit disconnected from invoices

dull bramble
#

When a refund is issued/succeeded you should receive a charge.refund.updated event. With that you receive the refund ID and the charge ID that you can use to List the Invoice Payments that also contain the Invoice ID. Does that make sense?

nimble shell
#

Hmm so the invoices endpoint (expanding payments) contains something like:

  "payments": {
        "object": "list",
        "data": [
            {
                "id": "inpay_1SGRweBHmn7qM5jZGhG3u8yL",
                "object": "invoice_payment",
                "amount_paid": 13860,
                "amount_requested": 13860,
                "created": 1760047457,
                "currency": "usd",
                "invoice": "in_1SGRwbBHmn7qM5jZ2sQnfn8J",
                "is_default": true,
                "livemode": false,
                "payment": {
                    "payment_intent": "pi_3SGRwcBHmn7qM5jZ1cO4l3A5",
                    "type": "payment_intent"
                },
                "status": "paid",
                "status_transitions": {
                    "canceled_at": null,
                    "paid_at": 1760047458
                }
            }
        ],
        "has_more": false,
        "url": "/v1/invoices/payments"
    },

Which exposes the inpay_ ID, but not the charge

#

But all of the refunded events expose the charge, not the inpay_

"object": {
"id": 
"re_3SGSMvBHmn7qM5jZ1IZKWEeV"
,
"object": 
"refund",
"amount": 
2000,
"balance_transaction": 
"txn_3SGSMvBHmn7qM5jZ1IERvQzM"
,
"charge": 
"ch_3SGSMvBHmn7qM5jZ1PB324YS"
,
"created": 
1760052214
,
"currency": 
"usd",
"destination_details": {
"card": {
"reference": 
"7300502887278129",
"reference_status": 
"available",
"reference_type": 
"acquirer_reference_number",
"type": 
"refund",
},
"type": 
"card",
},
"metadata": {},
"payment_intent": 
"pi_3SGSMvBHmn7qM5jZ1lI009Zp"
,
"reason": 
null,
"receipt_number": 
null,
"source_transfer_reversal": 
null,
"status": 
"succeeded",
"transfer_reversal": null 
}
#

So for the invoice payment we are good, but for the refund we only have a charge and no way to relate that back to an invoice payment or the invoice. The payment_intent is different between the refund and charge so no luck there either unfortunately

dull bramble
#

Only when you use the charge ID from the event to call the List all invoice payment API

#

And you can expand the invoice on the Invoice Payment API to have access to the Invoice data.

nimble shell
#

I am not seeing how to go from the charge ID to getting the invoice payment

dull bramble
#

Yeah no problem.

#

With that Charge ID, you call the List all invoice payments API

stripe invoice_payments list  \
  --expand=data.invoice
  -d "payment[type]='charge'
  -d "payment[charge]={here comes the charge ID from the event}
#

(I hope this works. Havent used the stripe cli for this in a while)

nimble shell
#

hmm okay I need to figure out the formatting for the [type] [charge] thing, its not liking that

#

looking at the docs I am not seeing "charge" as an option here though

#

just payment_intent

#

I gotta go and will look into this later but let me know if you have any other ideas

#

Appreciate the help

dull bramble
#

Oh yeah. I wonder why it showed on my screen differently. But the charge.refund.updated event also gives you the Payment Intent ID. So it should still work that way

nimble shell
#

The payment intent for refunds appears to be a new one not related to the original charge

#

If Iโ€™m looking at it right

#

Wait I had so many events pulled up I got confused sorry

#

invoice_payment.paid contains the invoice ID for finding the subscription, and the payment intent. And the refund event contains the same payment intent so we can reference both of those to find the original subscription when getting a refund event

#

And they are actually the same so it works, I should have realized that way earlier

#

Thanks again

dull bramble
#

I'm glad we could figure it out ๐Ÿ˜†

gilded dockBOT
#

cyral_refund-subscription-attribution

dull bramble
#

Is there anything I can help with? Otherwise I'll close the thread if that is ok with you.

nimble shell
#

That is all, have a good evening