#carlos-fontana_api
1 messages · Page 1 of 1 (latest)
đź‘‹ 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/1331644260033888308
📝 Have more to share? Add more details, code, screenshots, videos, etc. below.
Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- carlos-fontana_api, 3 hours ago, 19 messages
Hello, I’m experiencing an issue with the destination_payment field in the transfer object when working with a PaymentIntent that includes connected account transfers. Here’s the context:
Setup:
• We’re using Stripe Connect with on_behalf_of and transfer_data.destination set to the connected account’s stripeAccountId.
• application_fee_amount is also being used to deduct a platform fee.
• The PaymentIntent is created successfully, and the transfer object is included in the response.
Issue:
• When retrieving the PaymentIntent and expanding the transfer object (via expand: ['charges.data.transfer']), the transfer object does not include a valid destination_payment field.
• Based on the documentation, the destination_payment field should contain the connected account’s Charge ID (e.g., ch_xxx), but it’s either missing or not properly populated.
Steps Tried:
• Confirmed that the merchant.stripeAccountId is correct and active.
• Ensured the PaymentIntent was created with transfer_data.destination and on_behalf_of parameters.
• Retrieved the PaymentIntent with the necessary expanded fields.
Expected Behavior:
• The destination_payment field should reference the connected account’s charge ID.
Actual Behavior:
• The destination_payment field is missing or invalid (e.g., not starting with ch_).
I have this code when stripe calls a webhook on my server
case 'payment_intent.succeeded': {
const { metadata, amount, latest_charge } = event.data.object;
if (latest_charge) {
try {
// Recuperar el charge con transferencia expandida
const charge = await stripeClient.charges.retrieve(latest_charge, {
expand: ['transfer'],
});
console1.log('charge.transfer:', JSON.stringify(charge.transfer));
if (
charge.transfer &&
typeof charge.transfer !== 'string' &&
typeof charge.transfer.destination_payment === 'string' &&
charge.transfer.destination_payment.startsWith('ch_') // Asegurarse de que es un ID de charge
) {
// Actualizar metadata en el destination_payment
const updatedCharge = await stripeClient.charges.update(
charge.transfer.destination_payment,
{ metadata }
);
console1.log('âś… Metadata actualizada:', updatedCharge.metadata);
} else {
console1.log('⚠️ No se encontró un destination_payment válido o no es un charge.');
}
} catch (error) {
console1.log('🚨 Error al procesar el charge:', error.message);
}
} else {
console1.log('⚠️ No se encontró latest_charge en el Payment Intent.');
}
Basically, what I’m doing is working with Connected Accounts and implementing Direct Charges. This is working, but what I’d like to do is update the metadata on the customer’s transaction so that I can access all the relevant information, specifically the details of who made the payment
Yes, Destination Charges
/* Gets merchant if set */
const merchant = await this.merchantInteractor.getMerchantByEventId(
eventId
)
if (merchant && merchant?.stripeAccountId) {
params.application_fee_amount = Math.ceil(trx.total - trx.donation)
params.transfer_data = {
destination: merchant.stripeAccountId,
}
params.on_behalf_of = merchant.stripeAccountId
}
if (!merchant || !merchant.stripeAccountId)
throw new Error(
'[PaymentIntent]: Merchant account must have a gateway Id.'
const paymentIntent = await stripeClient.paymentIntents.create({
...params,
description,
metadata,
})
Can you share the Transfer object contents that you see when you retrieve that object?
Sure
{
"id": "tr_3Qk5YdEsYIHxK4oE1AVEivG3",
"object": "transfer",
"amount": 11596,
"amount_reversed": 0,
"balance_transaction": "txn_3Qk5YdEsYIHxK4oE1KuUQFIA",
"created": 1737558572,
"currency": "eur",
"description": null,
"destination": "acct_1QjgKPGaXe5d9XgQ",
"destination_payment": "py_1Qk5YeGaXe5d9XgQJPaZfgkk",
"livemode": false,
"metadata": {},
"reversals": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/transfers/tr_3Qk5YdEsYIHxK4oE1AVEivG3/reversals"
},
"reversed": false,
"source_transaction": "ch_3Qk5YdEsYIHxK4oE1DNxuuzB",
"source_type": "card",
"transfer_group": "group_pi_3Qk5YdEsYIHxK4oE1RajA1vm"
}
I see both destination and destination_payment are populated there. So I'm not sure I'm grasping what you're trying to convey. Is there a problem with the contents of those fields?
py_ is a valid prefix for Charge object IDs. You should still be able to retrieve those objects using the Charge retrieval endpoints.
We are a platform that processes donations for organizations. The way it works right now is that we can see the transaction details, and our client, the organization, can also see the transaction. However, while we can see the donor’s information, they cannot
What I’ve been trying to do is update the transaction details once the transaction has been confirmed. Specifically, I want to update the transaction metadata so that our client can also see the donor’s information.
For instance, I can see this
But the client see this:
So the concern isn't with the contents of those fields?
What do you mean by "transaction". That isn't an object type in our ecosystem (unless you're using Issuing or Treasury, but that doesn't sound like it's the case here). metadata resides on a specific object, it isn't cascaded from one object to another (with some exceptions):
https://docs.stripe.com/metadata#copy-metadata
Ah ok, i'm talking about payments
for instance, this one
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
If you want the metadata to be present on the Charge object that your Connected Account's can see (the one with the py_ prefix), then you will need to update that Charge object.
This is the payment on the Connected Account https://dashboard.stripe.com/acct_1QjgKPGaXe5d9XgQ/test/payments/py_1Qk5YeGaXe5d9XgQJPaZfgkk
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
If you want the metadata to be present on the Charge object that your Connected Account's can see (the one with the py_ prefix), then you will need to update that Charge object.
How can I do that? Idelly, I'd like to update the metadata, and the Details and the Customer
You would make a request as your Connected Account:
https://docs.stripe.com/api/connected-accounts
to update that Charge object:
https://docs.stripe.com/api/charges/update
The list of supported fields that can be updated for a Charge object is shown in that second link.
Something like this?
const { metadata, amount, latest_charge, on_behalf_of } = event.data.object
console1.log('on_behalf_of', on_behalf_of)
console1.log('latest_charge', latest_charge)
try {
const updatedCharge = await stripeClient.charges.update(
latest_charge,
{
metadata: metadata,
},
{
stripeAccount: on_behalf_of,
}
)
console1.log(
'Charge updated successfully:',
JSON.stringify(updatedCharge)
)
} catch (error) {
console1.log('Error updating charge:', error.message)
}
No, you don't want to use latest_charge, since you're trying to update the Charge object on the Connected Account from the Transfer, rather than the Charge on your Platform Account from processing the Payment Intent.
You will want to use the Charge ID from the destination_payment field on the Transfer object.
The diagram in this section helps show the relationship between the objects involved, both on the Platform and Connected Account, for a Destination Charges flow:
https://docs.stripe.com/connect/destination-charges?platform=web&ui=stripe-hosted#flow-of-funds-app-fee
Ah ok, got it.
const { metadata, amount, latest_charge, on_behalf_of, transfer_data } = event.data.object
const transfer = await stripeClient.transfers.retrieve(
transfer_data.destination,
{
stripeAccount: on_behalf_of,
}
);
const destinationPayment = transfer.destination_payment;
const updatedCharge = await stripeClient.charges.update(
destinationPayment,
{
metadata: metadata,
},
{
stripeAccount: on_behalf_of,
}
);
That will likely lead to errors when you run it, unless there's surrounding code changing variables that I'm not seeing.
Retrieving a Transfer object requires providing the ID of the Transfer object. If transfer_data.destination is from the Event payload you shared, then that field will contain the ID of a Connected Account, not a Transfer.
Yes, I saw that... but , how can I get the transfer id?
This is the info that stripe sends to my platform
One way is the approach you said you're using earlier in the thread:
• When retrieving the PaymentIntent and expanding the transfer object (via expand: ['charges.data.transfer']), the transfer object does not include a valid destination_payment field.
(Though that may be outdated depending on the specific API version you're using, you'll likely want to use latest_charge.transfer instead)
Ok, Stripe is sending me...
"latest_charge": "ch_3Qk5YdEsYIHxK4oE1DNxuuzB",
So, I can get the charge using this
const charge = await stripeClient.charges.retrieve(latest_charge);
Right?
Then you can use ID provided in the transfer field on that Charge to find the ID of the Transfer to the Connected Account. Then the destination_payment field on that Transfer object will have the ID of the Charge on the Connected Account.
// I'm getting the charge of my organization
const charge = await stripeClient.charges.retrieve(
latest_charge,
{
stripeAccount: on_behalf_of // I'm not sure if this is correct
}
);
// I'm getting the transferId of that charge
const transferId = charge.transfer;
// I'm getting the transfer of the connected account
const transfer = await stripeClient.transfers.retrieve(
transferId,
{
stripeAccount: on_behalf_of,
}
);
// I'm getting the destination payment of that transfer
const destinationPayment = transfer.destination_payment;
// I'm updating the charge of the connected account
const updatedCharge = await stripeClient.charges.update(
destinationPayment,
{
metadata: metadata,
},
{
stripeAccount: on_behalf_of,
}
);
Something like this?
No, the first two requests, retrieving latest_charge and the Transfer, don't need the stripeAccount header, since those objects are on your Platform account.
Other than that, I think it's right.
Any time! Glad to hear that helped
I believe so, since it's listed as an updatable field in the API reference I linked to previously. I'm not exactly sure what happens if the Charge has already succeeded and you try that though.
ok, I'll try it
I'm doing this
const updatedCharge = await stripeClient.charges.update(destinationPayment, { metadata: metadata, customer: customerDetails.id }, { stripeAccount: on_behalf_of });
Where.. customer id is cus_QRXVtXc0wuAicd
and it exists on my the stripe of my company
because I'm doing this
const customerDetails = await stripeClient.customers.retrieve(customer);
And I can get the data
"Customer Details:"
"{\"id\":\"cus_QRXVtXc0wuAicd\",\"object\":\"customer\",\"address\":{\"city\":\"edinburgh\",\"country\":\"GB\",\"line1\":\"3/4 dunard garden\",\"line2\":null,\"postal_code\":\"EH9 2HZ\",\"state\":null},\"balance\":0,\"created\":1720532986,\"currency\":null,\"default_source\":null,\"delinquent\":false,\"description\":null,\"discount\":null,\"email\":\"cfontana0@gmail.com\",\"invoice_prefix\":\"B16F170D\",\"invoice_settings\":{\"custom_fields\":null,\"default_payment_method\":null,\"footer\":null,\"rendering_options\":null},\"livemode\":false,\"metadata\":{},\"name\":\"Carlos Fontana\",\"next_invoice_sequence\":1,\"phone\":null,\"preferred_locales\":[\"en-GB\"],\"shipping\":null,\"tax_exempt\":\"none\",\"test_clock\":null}"
But the error es
"Error updating charge:"
"No such customer: 'cus_QRXVtXc0wuAicd'"
Do you have the ID of the request throwing that error? (it should have an req_ prefix)
My suspicion is that you're trying to use the ID of a Customer from your Platform Account, which you can't do because that Customer object doesn't exist in your Connected Account so you can't associate it with a Charge that resides in your Connected Account.
yes, you're right
So, I have to get the customer first, if it doesn't exist, create one
Hello! Just checking in to make sure there are no outstanding questions?