#lexumi_webhooks

1 messages · Page 1 of 1 (latest)

ornate flowerBOT
#

👋 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/1397721652779024585

📝 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.

storm minnow
#

Hello 👋

Taxes aren't collected on Payment Intents unless you explicitly collect them

#

Oh, wait this was coming from Checkout.

#

Nope, tax still isn't collected.

#

Because this is a Direct Charge (made using the Stripe Account header), the Connected Account is also assessed the Stripe fees

humble fiber
#

Yes, thats exactly what i want. The Connected Account should get the stripe fees taken from aswell as the platform fees.

Btw i cant open the link u send to the request log

storm minnow
#

Sorry fixed it

#

Yes, thats exactly what i want. The Connected Account should get the stripe fees taken from aswell as the platform fees.

That is what is happening

humble fiber
#

Hmm so do i get it right from the diagram.

I would need to get the charge object from the id in the paymentIntent -> "latest_charge":
"ch_3RoBtPIhqKh0OnYl0eLnMaip"
,

then get from the charge the balance transaction and there get the fee

then: recieved_amount - fee - application_fee

storm minnow
#

Bingo

humble fiber
#

oh haha what i wrote pretty much

#

U was faster xD

#

Okay thanks, will try that :)

storm minnow
#

In Python, it would look like

# Assuming you have the Payment Intent loaded in a variable payment_intent
charge = stripe.Charge.retrieve(payment_intent.latest_charge, expand=['balance_transaction'])
humble fiber
#
      const chargeId = paymentIntent.latest_charge as string;

      // get charge object
      const charge = await stripe.charges.retrieve(chargeId, {
        expand: ['balance_transaction'],
      });

      const applicationFee = paymentIntent.application_fee_amount;
      const stripeFee = (
        charge.balance_transaction as Stripe.BalanceTransaction
      ).fee;
#

testing rn

#

btw can i resend a failed webhook?

storm minnow
#

Yes you can use the CLI for this or trigger it from your Dashboard

humble fiber
#

ye tried that

 % stripe events resend evt_3RoCQ9IhqKh0OnYl1Jfc3Zk7
{
  "error": {
    "code": "resource_missing",
    "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
    "message": "No such notification: 'evt_3RoCQ9IhqKh0OnYl1Jfc3Zk7'",
    "param": "id",
    "type": "invalid_request_error"
  }
}
#

dashboard doesnt have a resend button. Im in sandbox rn

storm minnow
#

Are you logged in to the right account in your CLI?

humble fiber
#

should be, listen for local works

storm minnow
#

That event belongs on an Express Account that is also a Sandbox

#

You will likely need to use the --account flag to trigger a resend

#

Local listening forwards both webhook events on your account and webhook events on Connected Accounts

#

But that's not how most of stripe behaves

humble fiber
#

having a little verification issue rn

@Post('webhook')
  @Public()
  async handleStripeWebhook(
    @Req() req: Request,
    @Res() res: Response,
    @Headers('stripe-signature') signature: string,
  ) {
    const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, {
      apiVersion: '2025-06-30.basil',
    });
    const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET as string;
    let event: Stripe.Event;
    try {
      // req.body is a Buffer because of the raw body parser
      event = stripe.webhooks.constructEvent(
        req.body,
        signature,
        webhookSecret,
      );
    } catch (err) {
      this.logger.error('Stripe webhook signature verification failed', { error: err });
      return res.status(400).send(`Webhook Error: ${err.message}`);
    }
[PlantPort API] 67520 7/24/2025, 1:57:15 AM   ERROR  Stripe webhook signature verification failed - {
  error: {
    type: 'StripeSignatureVerificationError',
    raw: {
      message: 'Webhook payload must be provided as a string or a Buffer (https://nodejs.org/api/buffer.html) instance representing the _raw_ request body.Payload was provided as a parsed JavaScript object instead. \n' +
        'Signature verification is impossible without access to the original signed material. \n' +
        '\n' +
        'Learn more about webhook signing and explore webhook integration examples for various frameworks at https://docs.stripe.com/webhooks/signature\n'
    },
    header: 't=1753315035,v1=58afaa00fd102c9245bae252c97ffd9767de5fe05cdd78ca7964ad6f6a319e9a,v0=1eaff9c57bd98a074d4b358a10c23265df6ae76af992f497a8dbf907ba0d6f70',
    payload: {

trying to fix this first

storm minnow
#

Looks like you're using NodeJs, correct?

humble fiber
#

yep with a nestjs backend

#
  app.setGlobalPrefix("v1");
  // Stripe webhook must use raw body parser
  app.use('v1/stripe/webhook', bodyParser.raw({ type: '*/*' }));
ornate flowerBOT
storm minnow
humble fiber
#

Ive fixed it: https://wanago.io/2021/07/05/api-nestjs-stripe-events-webhooks/

tho now i am getting a
[PlantPort API] 70619 7/24/2025, 2:10:04 AM ERROR Transaction rolled back due to error - {
method: 'POST',
url: '/v1/stripe/webhook',
error: "No such charge: 'ch_3RoCjWIhqKh0OnYl1NUwdX3p'",
stack: "Error: No such charge: 'ch_3RoCjWIhqKh0OnYl1NUwdX3p'\n" +
' at generateV1Error (/Users/lucaberhard/Documents/pflanzanzeigen/api/node_modules/stripe/cjs/Error.js:11:20)\n' +
' at res.toJSON.then.Error_js_1.StripeAPIError.message (/Users/lucaberhard/Documents/pflanzanzeigen/api/node_modules/stripe/cjs/RequestSender.js:108:62)\n' +
' at process.processTicksAndRejections (node:internal/process/task_queues:105:5)'
} +97ms

In this article, we learn how to react to events that Stripe sends us. We do that by learning what webhooks are and how to use them.

#

maybe again the issue with the express account?

#

so will have to do a

      // get charge object
      const charge = await stripe.charges.retrieve(chargeId, {
        expand: ['balance_transaction'],
      }, {stripeAccount: accountId });
hybrid girder
humble fiber
#

yep worked, but balance_transaction is not returned

#

thats the charge request: req_QaPiC1jte2qFQT

#

But returned

{
    "id": "ch_3RoCoWIhqKh0OnYl1oe7YVDv",
    "object": "charge",
    "amount": 1000,
    "amount_captured": 1000,
    "amount_refunded": 0,
    "application": "ca_SivQzCyR6RgTjtZ3dNnVw2MD5Ll6K1os",
    "application_fee": null,
    "application_fee_amount": 100,
    "balance_transaction": null,
...
}

so balance_transaction is null

hybrid girder
#

so the thing here is starting from API version 2024-04-10 [0], PaymentIntents now has automatic_async as the default capture method when capture method is not specified. In short, the balance transaction will only be available later.

You can see find out more about why you would want to use automatic_async and how to be notified when the balance transaction is available here :  https://docs.stripe.com/payments/payment-intents/asynchronous-capture

You made the request to retrieve the charge, prior to the balance transaction being available. Maybe try retrieving the Charge again now? See if you can see the balance_transaction now
 
[0]  https://docs.stripe.com/upgrades#2024-04-10

Use Asynchronous Capture to enable faster PaymentIntent confirmations.

Keep track of changes and upgrades to the Stripe API.

humble fiber
#

yep its filled now

{
  id: 'ch_3RoCoWIhqKh0OnYl1oe7YVDv',
  object: 'charge',
  amount: 1000,
  amount_captured: 1000,
  amount_refunded: 0,
  application: 'ca_SivQzCyR6RgTjtZ3dNnVw2MD5Ll6K1os',
  application_fee: 'fee_1RoCoZIhqKh0OnYlZwsuEjQm',
  application_fee_amount: 100,
  balance_transaction: {
    id: 'txn_3RoCoWIhqKh0OnYl1jtxX8f4',
    object: 'balance_transaction',
    amount: 1000,
    available_on: 1753920000,
    balance_type: 'payments',
    created: 1753316113,
    currency: 'eur',
    description: null,
    exchange_rate: null,
    fee: 158,
    fee_details: [ [Object], [Object] ],
    net: 842,
    reporting_category: 'charge',
    source: 'ch_3RoCoWIhqKh0OnYl1oe7YVDv',
    status: 'pending',
    type: 'charge'
  },
  billing_details: {
    address: {
...
#

hmm so ill have to also listen to the charge.updated event and then calaculate the recieved amount after fees

hybrid girder
#

yep, that's right

humble fiber
#

Okay good, i can work with that :) Thansk for the help you guys are amazing <3

hybrid girder
#

happy to have been able to help!

humble fiber
#

<3

#

wasnt there a resolved command?

hybrid girder
#

ah, no, we'll close the thread after a while usually, feel free to just drop off and enjoy the rest of your day

humble fiber
#

or am i mixing up a different server 😅 Its getting late haha

hybrid girder
#

there's no resolved command 🙂

humble fiber
#

Okay good :D Have a good day/night