#drewbie-webhook-cli

1 messages ยท Page 1 of 1 (latest)

inland crowBOT
fallow tree
#

That may be something specific to the CLI events but I thought that you should be able to retrieve them. Depending on what you are trying to test, you might have better luck making that event happen once and then resending the event when you need to get it?

bright osprey
#

Should they be showing in the logs? I see a file.created event in the logs when I run stripe trigger account.updated, but no account.updated --> This is what it looks like locally as well. It shows the file and account event.

fallow tree
#

Thank you for the clarification. I will check in to whether these should show up in your logs. It looks like they may not be intended to based on the behavior that you are seeing

#

Can you tell me a bit more about what you are trying to do/how you are trying to test this here? Is this just a normal test of your webhook event handler and you need to look up the events themselves at some point?

bright osprey
#

I am trying to add capabilities to an Express Connected account - and after someone goes through the stripe onboarding, I want to know whether they have certain capabilities on their Stripe Connected account (eg transfers) so that I know within my own application if I can attempt to transfer them money, or if I need to prompt them to verify their account first

#

I am using code that handles webhooks for other events, and thats been working fine so far. Its just the account.updated event thats causing troubles.

fallow tree
#

And this is for just CLI events or ones that you trigger by going through the onboarding process as well?

iron grail
#

๐Ÿ‘‹ stepping in

#

Can you provide the Event ID from your screenshot above in text?

nocturne gust
#

drewbie-webhook-cli

bright osprey
#

evt_1MP7PmQ9HyQXAu0EaVKPyiRI

iron grail
#

Thanks

#

Hmm that is a capability.updated event

#

I see an account.updated event in your terminal screenshot above

#

But you are saying you can't locate that Event in your Dashboard?

bright osprey
#

I am trying to trigger the event locally with the Stripe CLI - and have access to that event in my webhook handler.

#

Even with a purely Stripe CLI fabricated account event, there is no data. Seeing the same thing when I actually go through the onboarding flow manually and see the events come back after I add account info

iron grail
#

What does "no data" mean exactly?

bright osprey
iron grail
#

Like you aren't seeing the Event in your Webhook handler?

bright osprey
#

In the webhook handler, I try to retrieve that event by that ID and it says it cant be found

iron grail
#

Okay so in the above CLI screenshot we can see a 400 so something seems to be going wrong when you attempt to receive the event

#

Are you seeing an error in your server logs?

#

Can you post that Event ID or trigger a new one and provide the Event here?

bright osprey
#

The 400 is because the webook handler is trying to retrieve that event, and its failing

#

Error: No such notification: 'evt_1MP7PmQ9HyQXAu0EaVKPyiRI'

iron grail
#

Hmm okay but you are throwing that 400 from your handler.

#

Can you share your webhook code?

bright osprey
#

stripe trigger account.updated
Setting up fixture for: account
Running fixture for: account
Setting up fixture for: update_account
Running fixture for: update_account
Trigger succeeded! Check dashboard for event details.

webhook forward process
connect account.updated [evt_1MP7lBQ2rRr9VhzTBzqLazGZ]

webhook handler
Error: No such notification: 'evt_1MP7lBQ2rRr9VhzTBzqLazGZ'
#
  const signature = req.headers.get("stripe-signature");
  if (!signature) {
    throw new Error("No signature in request");
  }

  const requestData = await req.text();
  // This is needed in order to use the Web Crypto API in Deno.
  const cryptoProvider = Stripe.createSubtleCryptoProvider();

  let receivedEvent;
  try {
    receivedEvent = await stripeClient.webhooks.constructEventAsync(
      requestData,
      signature,
      endpointSecret,
      undefined,
      cryptoProvider
    );
  } catch (err) {
    return new Response(err.message, { status: 400 });
  }

  // Secondly, we use this event to query the Stripe API in order to avoid
  // handling any forged event. If available, we use the idempotency key.
  const requestOptions: Stripe.RequestOptions =
    receivedEvent.request && receivedEvent.request.idempotency_key
      ? {
          idempotencyKey: receivedEvent.request.idempotency_key,
        }
      : {};

  let retrievedEvent;
  try {
    retrievedEvent = await stripeClient.events.retrieve(receivedEvent.id, requestOptions);
  } catch (err) {
    console.log("Here in retrievedEvent err", err);
    return new Response(err.message, { status: 400 });
  }
iron grail
#

Okay so in your server logs are you seeing that Here in retrievedEvent?

#

Doesn't seem so, correct?

#

Ah okay

#

So let's pause

bright osprey
#

Its retrievedEvent = await stripeClient.events.retrieve(receivedEvent.id, requestOptions); that cant retrieve the event.

iron grail
#

In your handler you are attempting to retrieve the event via the API

#

That's not going to work here

bright osprey
#

If it provides any more clarity - this is the same logic used for other webhook events

iron grail
#

Can you also show me what constructEventAsync is? That isn't one of our methods

#

It should just be constructEvent

bright osprey
#

There is a switch statement that looks at the event type here is the entire file

import { corsHeaders } from "../_shared/cors.ts";
import { stripeClient } from "../_shared/clients/stripe.ts";
import { handleConnectedAccountUpdated } from "../_shared/helpers/stripe.ts";
import Stripe from "stripe";

if (!Deno.env.get("STRIPE_WEBHOOK_SECRET")) {
  throw new Error("No Stripe Webhook Secret set");
}

const endpointSecret = Deno.env.get("STRIPE_WEBHOOK_SECRET")!;

export async function handler(req: Request) {
  console.log("IN CONNECT WEBHOOK");
  const signature = req.headers.get("stripe-signature");
  if (!signature) {
    throw new Error("No signature in request");
  }

  const requestData = await req.text();
  // This is needed in order to use the Web Crypto API in Deno.
  const cryptoProvider = Stripe.createSubtleCryptoProvider();

  let receivedEvent;
  try {
    receivedEvent = await stripeClient.webhooks.constructEventAsync(
      requestData,
      signature,
      endpointSecret,
      undefined,
      cryptoProvider
    );
  } catch (err) {
    return new Response(err.message, { status: 400 });
  }

  // Secondly, we use this event to query the Stripe API in order to avoid
  // handling any forged event. If available, we use the idempotency key.
  const requestOptions: Stripe.RequestOptions =
    receivedEvent.request && receivedEvent.request.idempotency_key
      ? {
          idempotencyKey: receivedEvent.request.idempotency_key,
        }
      : {};

  let retrievedEvent;
  try {
    console.log("before fetch", receivedEvent);
    retrievedEvent = await stripeClient.events.retrieve(receivedEvent.id, requestOptions);
  } catch (err) {
    console.log("Here in retrievedEvent err", err);
    return new Response(err.message, { status: 400 });
  }

  switch (receivedEvent.type) {
    case "account.updated":
      await handleConnectedAccountUpdated(receivedEvent);
      return new Response(JSON.stringify(retrievedEvent.type), {
        headers: { ...corsHeaders, "Content-Type": "application/json" },
        status: 200,
      });
    default:
      return new Response(null, {
        headers: { ...corsHeaders, "Content-Type": "application/json" },
        status: 200,
      });
  }
}
#

That exact code works for other events if thats helpful. I can trigger a charge.succeeded event for example, and it finds the event.

iron grail
#

Okay so at the bottom of those logs is your account.updated

#

So you are receiving it successfully?

#

So I'm confused at what the issue is at this point

#

Can you clarify?

bright osprey
#

Yes - the handler code I believe convoluted some things, sorry about that

#

When I try to call retrievedEvent = await stripeClient.events.retrieve(receivedEvent.id, requestOptions);

#

It cannot find the account.updated event by the ID provided by the CLI triggered event

#

Any other event besides account.updated, retrievedEvent finds the event by the ID and the bottom switch statement is good to handle it

#

Can confirm that the error is legit considering there are no events in the logs on the dashboard for account.updated - so the CLI is triggering the event, fabricating the data etc, but when I try to retrieve that event to get its info, it doesnt exist

iron grail
#

Ahhhhh okay

#

So those account.updated events occur on the Connected Account

#

So are your requestOptions properly passing the Connected Account ID?

#

Can you log that out?

bright osprey
#

Ah they are not

 const requestOptions: Stripe.RequestOptions =
    receivedEvent.request && receivedEvent.request.idempotency_key
      ? {
        
          idempotencyKey: receivedEvent.request.idempotency_key,
        }
      : {};
iron grail
#

Gotcha

#

So yeah that's the problem

bright osprey
#

Does the event trigger need to pass any info along as well?

#

Appreciate your help on this

iron grail
#

Nope

#

It should not

bright osprey
#

But the event will need to be an event associated to that connected account id im assuming? Eg I cant just hard code in a Stripe connected account id into the requestOptions and trigger the webhook?

iron grail
#

Ah yes you can. Just thought you meant did you have to do this

#

Let me grab the syntax

bright osprey
#

Thanks, I was down that path and got this error?

stripe trigger account.updated --stripe-account=acct_1MP7PbQ1fJBbSzG0
Setting up fixture for: account
Running fixture for: account
Trigger failed: Request failed, status=403, body={
  "error": {
    "message": "Connect platforms cannot create new accounts on behalf of their connected accounts.",
    "request_log_url": "https://dashboard.stripe.com/acct_1MP7PbQ1fJBbSzG0/test/logs/req_nYfCD8PLMwC9PK?t=1673458824",
    "type": "invalid_request_error"
  }
}
iron grail
#

Ugh yeah I wasn't sure if that was going to happen. I actually don't think this is going to be possible via stripe trigger... what you will have to do here is actually make a POST request via the CLI to update something like metadata on a specific test Connected Account to trigger the account.updated

#

The reason is that when you set --stripe-account it tries to run that fixture on that set Account ID

#

And in that case the fixture tries to create a Connected Account for that account

bright osprey
#

Hey I got it!

iron grail
#

Oh?

#

With stripe trigger?

bright osprey
#

No not with stripe trigger... yet

#

Just with performing something locally that triggers the event

iron grail
#

Yep

bright osprey
#

signed in as that account

iron grail
#

That is the better way

bright osprey
#

Appreciate your help on this - was banging my head on it for a while

iron grail
#

Not to use stripe trigger since you want to know the Account ID

#

That said... this is going to be an issue in production here where you will need to know the account ID to retrieve the Event

#

So you may want to move that retrieval into your handler where you have you switch statement and then you can see the Account ID

#

Though it just becomes repetitive at that point

bright osprey
#

The event gives back the account_id in the event before trying to retrieve it, should that be an issue?

iron grail
#

Right, no it shouldn't

#

I'm still a little confused as to why you are retrieving the Event ๐Ÿ˜…

bright osprey
#

If I dont need to? You're saying just use constructEventAsync with it having the same data as trying to fetch the event by id?

iron grail
#

What is the purpose of retrieving the Event if you get that same data in your handler?

bright osprey
#

An oversight really - I followed along with docs somewhere on setting up the event and didnt realize until now that they both give back the same data

iron grail
#

Gotcha

bright osprey
#

I think I was fetching them cause whatever I was looking at says to fetch the event again to prevent any forged events?

#

But if thats not a concern I can cut out the fetching of events entirely