#daniel-paymentintent-netamount

1 messages · Page 1 of 1 (latest)

unborn lichenBOT
dusty portal
#

Hi @gentle lily, following up from yesterday

gentle lily
#

Do you mean the fees?

dusty portal
#

--expand='latest_charge.balance_transaction' doesnt correctly return the net

#

looking for this data

#

I basically want to know for a given payment intent, how much we actually netted taking into account all fees, refunds, failed payments, etc

gentle lily
dusty portal
#

im finding it to be incorrect

#

the net doesnt account for refunds in that object

gentle lily
dusty portal
#

❯ stripe payment_intents retrieve pi_.... --expand='latest_charge.balance_transaction'

#

^im doing that

#

In this example, the net i get in the balance_transaction object shows 11904. It should be -96

#

im not sure exactly how the UI in the portal gets that -$0.96 net value. Thats what im looking to get

#

from what i can tell it looks like there is a separate call to payment_detail_summary

gentle lily
#

The stripe fees aren't refunded when a payment is refunded

Also, a refund would create a new balance transaction. So you might not be looking at the correct balance transaction object

dusty portal
#

im not asking about the value of the fees, The UI correctly shows -0.96. My issue is the response does not show that using the paymentIntents API with expanding latest_charge

#

i want to know how i can get the exact net value from the APIs

#

looking to get this:
"net_by_currency": [
{
"amount": -96,
"currency": "usd"
}
],

gentle lily
#

Can you share the PaymentIntent ID?

FYI, dashboard features use different APIs than the ones that are publicly available. It's not as simple as just calling the same API endpoint that the dashboard uses.

dusty portal
#

pi_3NNMENJmq474uon80fkfpOCp

#

From test mode^

unborn lichenBOT
dusty portal
#

The Dashboard shows Net: -$0.96 but the latest charge gives this:

"latest_charge": {
    "id": "...",
    "object": "charge",
    "amount": 12000,
    "amount_captured": 12000,
    "amount_refunded": 12000,
    "application": null,
    "application_fee": null,
    "application_fee_amount": null,
    "balance_transaction": {
      "id": "...",
      "object": "balance_transaction",
      "amount": 12000,
      "available_on": 1687812113,
      "created": 1687812113,
      "currency": "usd",
      "description": "Subscription creation",
      "exchange_rate": null,
      "fee": 96,
      "fee_details": [
        {
          "amount": 96,
          "application": null,
          "currency": "usd",
          "description": "Stripe processing fees",
          "type": "stripe_fee"
        }
      ],
      "net": 11904,
      "reporting_category": "charge",
      "source": "...",
      "status": "available",
      "type": "payment"
    },
gentle lily
#

because the latest charge associated with the PaymentIntent ID is type payment

#

So it is pointing to its original balance transaction

#

Balance Transactions aren't updated retroactively when a charge is refunded

#

A new Balance Transaction is created instead

dusty portal
#

But that charge reflects the refund in the amount_refunded field

gentle lily
#

Charge object is updated retroactively, BalanceTransaction object isn't

dusty portal
#

I see

#

nonetheless, what is the best way to get the correct Net field im looking for?

gentle lily
#

Not sure 100% as I have not tried this before

dusty portal
#

still not sure if thats the best way, because that just gives the net of -12000

gentle lily
dusty portal
#

yes correct. Expanded latest_charge.refunds.balance_transaction

#

type is "payment_refund" to be specific

gentle lily
#

Gotcha. Hmm that's what I was afraid of 😦
Looks like we don't currently calculate the net on refunds and this might be just limited to dashboard at the moment

dusty portal
#

maybe there is a way to get all balance transaction associated with a payment intent?

#

Brutal 😦

gentle lily
#

This should allow you to manually calculate net

dusty portal
#

worried that will be an inefficient because would have to do this for every payment intent no?

#

could use webhooks etc but thats a far far more involved implementation that i was hoping for

#

Do you think i could just leverage the latest_charge on the payment_intent?

#

and just do net = amount_captured - amount_refunded - fee

gentle lily
#

You can, you can look at the amount refunded and then the fees

#

yeah

dusty portal
#

that seems like it could work. Are there any edge cases that I may be missing though?

gentle lily
#

Can't think of one, it should work. Would recommend testing it thoroughly though

dusty portal
#

want this math to work for any payment intent

gentle lily
#

👍

dusty portal
#

ugh dont think it works for failed payments 😦

#

doesnt include the -4.00 fee

grim pawn
#

Interesting, still for that same pi_3NNMENJmq474uon80fkfpOCp?

dusty portal
#

no no, different one, was checking other examples to see if it could work

#

@grim pawn Do you know of any ways to get the value shown in the dashboard?

grim pawn
#

Looking in to this. I would have thought the same things that hanzo said. Can you send me the ID of the intent that you aren't seeing the $4 fee on?

dusty portal
#

is it ok if its a live mode id?

grim pawn
#

If you can also send the related balance transaction as well IDs that would save me some time looking them up

dusty portal
#

not sure how to replicate it in test mode

grim pawn
#

Yep, safe to share. No one here can do anything with those IDs unless they have your login or API secret key

dusty portal
#

pi_3NMaHLJmq474uon80yC8oez5

#

txn_3NMaHLJmq474uon80biUZLMj

grim pawn
#

Thank you, checking in to those in a minute

#

So it looks like that extra 304 can be found on the payment_refund balance transaction for the refund though I'm not 100% sure on how it will display for you. Can you retrieve txn_1NNOfRJmq474uon8ZfeQAo9X to check?

dusty portal
#

{
"id": "txn_1NNOfRJmq474uon8ZfeQAo9X",
"object": "balance_transaction",
"amount": -12000,
"available_on": 1688515200,
"created": 1687821476,
"currency": "usd",
"description": "REFUND FOR FAILED PAYMENT (Subscription creation)",
"exchange_rate": null,
"fee": 304,
"fee_details": [
{
"amount": 304,
"application": null,
"currency": "usd",
"description": "Stripe processing fees",
"type": "stripe_fee"
}
],
"net": -12304,
"reporting_category": "charge_failure",
"source": "pyr_1NNOfQJmq474uon8nO1a1FYk",
"status": "pending",
"type": "payment_failure_refund"
}

#

ok I see that

#

but how do i get that transaction from the payment intent?

grim pawn
#

Thinking on the best way to do that. It looks like the charge object itself has a list of refunds that you can access through expansion. If you retrieve the payment intent and expand latest_charge.refunds.data.balance_transaction that should give you all the info you need here https://stripe.com/docs/api/charges/object#charge_object-refunds

dusty portal
#

crazy how difficult this is, the value is right there on the dashboard!

#

are we sure there isnt a way to just get that value?

grim pawn
#

Yeah, those balance transactions are the only way to see these values that I am aware of. As far as I can tell this is the same calculation that our dashboard does

dusty portal
#

is there a simple way to just get the balance transactions associated with a payment attempt?

unborn lichenBOT
grim pawn
#

That might work but I think that the payment intent, charges, and refund may all be considered separate sources in which case I don't think there will be an easier way to get all of them for a specific attempt

dusty portal
#

yea its a different source

#

Still not totally sure how this works on the dashboard?

#

or how i can correctly capture all possible sources of fees/revenue from a given payment intent?

blazing summit
#

👋 stepping in here as Pompey needs to step away

#

Can you clarify what data is not present on the balance transaction object that you are looking for?

dusty portal
#

let me step back, maybe you have a different way of approaching the issue:

#

on the Payment intent page on the dashboard, there is a Payment Details section, with a Net value, that takes into account Fees, refunds, diputes, successes, etc

#

I need to get or compute that net value for each payment attempt

#

Goals is to know exactly how much revenue(possibly negative) we got for each paymentIntent

unborn lichenBOT
mental sky
#

daniel-paymentintent-netamount

blazing summit
#

Gotcha. In that case you are going to need to aggregate all the balance transactions that are associated to the Charge

#

So mostly you want to expand the latest_charge associated with the PaymentIntnet

#

Then you look at if that has refunds or disputes and grab all relevant balance transactions

#

And aggregate

dusty portal
#

so for this example: pi_3NKUE2Jmq474uon81h0TsSpH

#

what specicially would i need to expand on the retrieve a paymentintent call?

blazing summit
#

So looks like that has a Charge and a Dispute

#

So you expand the latest_charge.balance_transaction

#

Then you see that it says disputed: true

#

And when you do that you also need to expand the balance_transaction for the dispute as well

dusty portal
#

Wait can i just expand: latest_charge.balance_transaction, latest_charge.dispute

blazing summit
#

No because the Charge doesn't have a property for the dispute object

#

Only disputed

dusty portal
#

im seeing it though:)

#

rather the paymentIntent does

#

.latest_charge.dispute.balance_transactions

blazing summit
#

Hmm yeah you are right. I forgot that was there and then double checked on the API reference. I'll file some feedback to get it properly added to the API Reference.

#

But yes that works well

dusty portal
#

How about failed requests: pi_3NNO2tJmq474uon81Roug0DJ

#

how would i get the $3.04 additional fee for the failure

blazing summit
#

Hmm I don't think those payment failure fees are directly associated to the Charge

#

Looking

#

Ah okay

#

There should be a refund associated

#

Do you see an amount for that latest_charge in amount_refunded?

#

And is there anything in the refunds hash?

dusty portal
#

hmm, refunded = false

#

and amount_refunded = 0

blazing summit
#

If you expand latest_charge.refunds what do you see?

dusty portal
#

"refunds": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/py_3NNO2tJmq474uon81NKwRZmv/refunds"
},

blazing summit
#

Hrmmmm

#

And expand data.source when you do that?

dusty portal
#

{
"object": "list",
"data": [],
"has_more": false,
"url": "/v1/balance_transactions"
}

#

Wierdly if i list without filtering by type i do see examples with payment_failure_refund

#

One example is: pyr_1NNwmdJmq474uon8szKE0AJB

blazing summit
#

Yep that is what I was hoping was going to show up in refunds

#

Surprised it doesn't

#

I'll have to file feedback about that

dusty portal
#

what is a pyr?

blazing summit
#

It is basically just a refund of a Charge

#

For non-Card Charges they are "Payment" objects that start with py_xxx

#

But they are the same thing as Charge objects

dusty portal
#

Whats intersting is the source references a payment intent

blazing summit
#

I thought we tied that to the Charge more easily.

dusty portal
#

it has the charge too

blazing summit
#

As noted, I'll file feedback on that. But for now you would need to list these and then reconcile via the PaymentIntent

#

Oh it does?

#

Okay then yeah you will want to match on Charge ID

dusty portal
#

{
"object": "list",
"data": [
{
"id": "txn_1NNwmdJmq474uon8egHGU1a2",
"object": "balance_transaction",
"amount": -12000,
"available_on": 1688515200,
"created": 1687952619,
"currency": "usd",
"description": "REFUND FOR FAILED PAYMENT (Subscription creation)",
"exchange_rate": null,
"fee": 304,
"fee_details": [
{
"amount": 304,
"application": null,
"currency": "usd",
"description": "Stripe processing fees",
"type": "stripe_fee"
}
],
"net": -12304,
"reporting_category": "charge_failure",
"source": {
"id": "pyr_1NNwmdJmq474uon8szKE0AJB",
"object": "refund",
"amount": 12000,
"balance_transaction": "txn_1NNwmdJmq474uon8egHGU1a2",
"charge": "py_3NMsYiJmq474uon81mZ7UgNl",
"created": 1687952619,
"currency": "usd",
"description": "Payment failure refund",
"metadata": {},
"payment_intent": "pi_3NMsYiJmq474uon81KX1Z8Tm",
"reason": null,
"receipt_number": null,
"source_transfer_reversal": null,
"status": "pending",
"transfer_reversal": null
},
"status": "pending",
"type": "payment_failure_refund"
}
],
"has_more": false,
"url": "/v1/balance_transactions"
}

blazing summit
#

That said, we should return this via refunds on the Charge

#

So I will file to get that added

dusty portal
#

there is no way to search for balancetransactions assocaited with a charge or payment intent however

#

so kinda gross but maybe what i do is get all balance transactions. Then for each payment intent, sum up the net value of each transaction found that is associated with that payment intent

#

i guess that should work

blazing summit
#

That would be a good method, yes.

dusty portal
#

my ultimate goal here is to create a report of each payment intent over an n day span in excel

#

want to know the revenue of each payment attatched to the date it was started

#

so we can compute analytics on our LTV and CAC

blazing summit
#

Gotcha

#

Well either listing Balance Transactions as you noted is a good way. Or you could actually look into our Reports API

#

Which would do a lot of this work for you

#

But really just depends on exactly what you are looking for

dusty portal
#

i couldnt tell if the report would back date refunds/fees to the date the payment was initiated

blazing summit
#

Those reports will mostly provide all balance transactions

dusty portal
#

like if a user signs up and pays june 20, i want all the fees, revenue, etc to be associated with june 20, rather than days or weeks later when the refund processes

blazing summit
#

So yeah it won't backdate to the payment date for something like the refund. The balance transaction will have the refund date for instance

#

Gotcha

#

Then yeah imo this may be easiest to do yourself

#

If you use the Reports API you would need to do some work after downloading

dusty portal
#

because we ultimately want to know if we spent $1000 on ads on June 20th, what do we have to show for it

blazing summit
#

Yeah that makes sense

#

Listing balance transactions and then linking everything to the Charge created date will give the most accurate date

dusty portal
#

you'd use charge created date over the paymentIntent date?

blazing summit
#

Mostly yes but that depends on your integration

#

A PaymentIntent can have multiple Charges (if there are declines for instance)

#

So the PaymentIntent created date could be far before the actual successful Charge

dusty portal
#

in our current implemtation it should be instant

#

we use ACH and dont retry

blazing summit
#

That should be fine then

dusty portal
#

its for a subscription, so the date of the intent is the date the user most likely got the app

#

Ok im going to try this out. Thank you all for the help! Would it be possible to get a feedback for making the data more easily accessed, since it show right in the dashboard?

blazing summit
#

Yep I'll file feedback about that