#drewbie-webhook-cli
1 messages ยท Page 1 of 1 (latest)
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?
Ive opened a GH Issue with some more context, https://github.com/stripe/stripe-cli/issues/1017
The event is firing, theres just no event with event data behind it
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.
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?
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.
And this is for just CLI events or ones that you trigger by going through the onboarding process as well?
drewbie-webhook-cli
evt_1MP7PmQ9HyQXAu0EaVKPyiRI
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?
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
What does "no data" mean exactly?
Im pretty sure account.updated is what I need per the docs? https://stripe.com/docs/connect/webhooks
Like you aren't seeing the Event in your Webhook handler?
In the webhook handler, I try to retrieve that event by that ID and it says it cant be found
correct
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?
The 400 is because the webook handler is trying to retrieve that event, and its failing
Error: No such notification: 'evt_1MP7PmQ9HyQXAu0EaVKPyiRI'
Hmm okay but you are throwing that 400 from your handler.
Can you share your webhook code?
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 });
}
Okay so in your server logs are you seeing that Here in retrievedEvent?
Doesn't seem so, correct?
Ah okay
So let's pause
Its retrievedEvent = await stripeClient.events.retrieve(receivedEvent.id, requestOptions); that cant retrieve the event.
In your handler you are attempting to retrieve the event via the API
That's not going to work here
If it provides any more clarity - this is the same logic used for other webhook events
You want to handle the Event as it comes in with a switch statement like we show here: https://stripe.com/docs/webhooks/quickstart
Can you also show me what constructEventAsync is? That isn't one of our methods
It should just be constructEvent
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,
});
}
}
In that example - I get both console logs to print with
That exact code works for other events if thats helpful. I can trigger a charge.succeeded event for example, and it finds the event.
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?
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
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?
Ah they are not
const requestOptions: Stripe.RequestOptions =
receivedEvent.request && receivedEvent.request.idempotency_key
? {
idempotencyKey: receivedEvent.request.idempotency_key,
}
: {};
Gotcha
So yeah that's the problem
The Event is actually occurring on the Connected Account, so you need the Stripe Account header: https://stripe.com/docs/connect/authentication
Does the event trigger need to pass any info along as well?
Appreciate your help on this
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?
Ah yes you can. Just thought you meant did you have to do this
Let me grab the syntax
Yeah I believe the --stripe-account flag should do this: https://stripe.com/docs/cli/trigger#trigger-stripe_account
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"
}
}
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
Hey I got it!
No not with stripe trigger... yet
Just with performing something locally that triggers the event
Yep
signed in as that account
That is the better way
Appreciate your help on this - was banging my head on it for a while
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
The event gives back the account_id in the event before trying to retrieve it, should that be an issue?
Right, no it shouldn't
I'm still a little confused as to why you are retrieving the Event ๐
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?
What is the purpose of retrieving the Event if you get that same data in your handler?
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
Gotcha