Webhooks organization.deleted event has stopped working

Hi Kinde team, Wanted to check if there are no incidents on your end. I have a webhook configured to send events on organization and user events. I'm receiving the created and updated events but there are no events being produced for organization.deleted. I have the events configured on the webhook properly. The user events seems to be working fine.
16 Replies
Abdiwak Bekele
Hi Maxom, Thanks for reaching out! Just to clarify before we investigate further: - Have you recently deleted an organization to trigger the organization.deleted event, or are you expecting past deletions to be retried? - Are you seeing any webhook delivery logs for organization.deleted (even failed ones), or is it completely missing from the logs? - Have there been any recent changes to your webhook configuration that might affect event delivery? Once we have this information, we can check if there are any issues on our end or if further troubleshooting is needed. Looking forward to your response
__maxom__
__maxom__OP2w ago
I’m currently writing the code to sync kinde events with my db. For this, I have created multiple dummy orgs and deleted them using the kinde management API. I’m not seeing any delivery logs. This is a new webhook that i have created. Previously to test the webhooks functionality I used another dummy endpoint using ngrok and in those tests, the organisations events worked fine.
Abdiwak Bekele
Hi there, This is Patrick from Kinde. I will take this over from Ages who is on a few days leave. Since you mentioned the webhooks worked previously with ngrok but not with your new endpoint, let's troubleshoot: 1. Verify your webhook configuration: - Check that organization.deleted is included in your event_types
(https://docs.kinde.com/integrate/webhooks/add-manage-webhooks/#manage-webhooks-via-the-kinde-api) - Verify your webhook endpoint is publicly accessible - Ensure your endpoint can validate the JWT tokens (webhook payloads are signed and sent as JWTs) 2. For local testing: - You can use localtunnel (recommended with the --subdomain attribute) or Ngrok to expose your local instance - Since Ngrok worked before, you might want to test with it again to verify if the issue is with your endpoint or with the events themselves 3. You can check your webhook configuration using the Management API: - Use GET /api/v1/webhooks to list your webhooks and verify the configuration - Use GET /api/v1/event_types to verify the available event types 4. Important security note: - Webhook request payloads are signed and sent as a JWT - You need the jwks file for JWT validation, available at: https://<your_subdomain>.kinde.com/.well-known/jwks If you're still not seeing delivery logs, I recommend: 1. Creating a new webhook with Ngrok to verify if events are being generated 2. If events work with Ngrok but not your endpoint, the issue likely lies with your endpoint configuration 3. If events don't work with either endpoint, there might be an issue with the event generation or webhook configuration Please let me know how you go with this.
__maxom__
__maxom__OP2w ago
Hi Patrick, I have created a new webhook with Ngrok and I can confirm that event is not being generated for organization.delete. TL;DR to your questions. I have everything setup properly and my API endpoint works as expected for the events which are actually being generated by Kinde. My endpoint can validate the JWT tokens and I can see the event data for the others and I can perform my downstream application logic for them. The issue right now is Kinde is not emitting the event for organization.deleted. Webhook endpoint is publicly accessible by exposing my local instance using ngrok and no issues with it. Works as expected. Note: I'm sharing the ngrok public URL in these messages but I'm going to terminate it after this post so it should be fine. In depth: Use GET /api/v1/webhooks: see attachment: organization.deleted is a part of the event_types Use GET /api/v1/event_types: see attachment: organization.deleted is a part of the event_types To troubleshoot, I have commented out my entire functionality and just logging the results:
app.post("/", async (c) => {
const token = await c.req.text();
const { header } = decode(token);
const secret = await getPublicKey(
c.env.KINDE_JWKS_URI,
header.kid!,
header.alg
);
const event = (await verify(token, secret, header.alg)) as any;

if (!event) {
return c.text("Unauthorized", 401);
}

console.log(JSON.stringify(event, null, 2));
app.post("/", async (c) => {
const token = await c.req.text();
const { header } = decode(token);
const secret = await getPublicKey(
c.env.KINDE_JWKS_URI,
header.kid!,
header.alg
);
const event = (await verify(token, secret, header.alg)) as any;

if (!event) {
return c.text("Unauthorized", 401);
}

console.log(JSON.stringify(event, null, 2));
__maxom__
__maxom__OP2w ago
Console Output:
npm run dev
Creating a new org
Request:
{
"name": "Test",
"handle": "test_ye22i9no",
"feature_flags": {},
"is_allow_registrations": true,
"sender_name": "Test"
}
Retrieving Kinde Management API Token from Cache
Token is still valid, returning cached token
Response:
{
"status": 200,
"statusText": "OK",
"message": {
"code": "OK",
"message": "Success",
"organization": {
"code": "org_4b95653655381"
}
}
}
[wrangler:inf] POST /v1/org 200 OK (575ms)
{
"data": {
"organization": {
"code": "org_4b95653655381",
"external_id": null,
"handle": "test_ye22i9no",
"name": "Test"
}
},
"event_id": "event_0195ec2c4c07a60a4157668e4d8058ce",
"event_timestamp": "2025-03-31T12:28:00.778346+00:00",
"source": "api",
"timestamp": "2025-03-31T12:28:01.139717285Z",
"type": "organization.created"
}
[wrangler:inf] POST /webhooks/kinde 200 OK (94ms)
Deleting org with id: org_4b95653655381
Retrieving Kinde Management API Token from Cache
Token is still valid, returning cached token
Response:
{
"status": 200,
"statusText": "OK",
"message": {
"code": "ORGANIZATION_DELETED",
"message": "Organization successfully deleted"
}
}
[wrangler:inf] DELETE /v1/org/org_4b95653655381 200 OK (143ms)
╭───────────────────────────╮
[b] open a browser │
[d] open devtools │
[l] turn off local mode │
[c] clear console │
[x] to exit │
╰───────────────────────────╯
npm run dev
Creating a new org
Request:
{
"name": "Test",
"handle": "test_ye22i9no",
"feature_flags": {},
"is_allow_registrations": true,
"sender_name": "Test"
}
Retrieving Kinde Management API Token from Cache
Token is still valid, returning cached token
Response:
{
"status": 200,
"statusText": "OK",
"message": {
"code": "OK",
"message": "Success",
"organization": {
"code": "org_4b95653655381"
}
}
}
[wrangler:inf] POST /v1/org 200 OK (575ms)
{
"data": {
"organization": {
"code": "org_4b95653655381",
"external_id": null,
"handle": "test_ye22i9no",
"name": "Test"
}
},
"event_id": "event_0195ec2c4c07a60a4157668e4d8058ce",
"event_timestamp": "2025-03-31T12:28:00.778346+00:00",
"source": "api",
"timestamp": "2025-03-31T12:28:01.139717285Z",
"type": "organization.created"
}
[wrangler:inf] POST /webhooks/kinde 200 OK (94ms)
Deleting org with id: org_4b95653655381
Retrieving Kinde Management API Token from Cache
Token is still valid, returning cached token
Response:
{
"status": 200,
"statusText": "OK",
"message": {
"code": "ORGANIZATION_DELETED",
"message": "Organization successfully deleted"
}
}
[wrangler:inf] DELETE /v1/org/org_4b95653655381 200 OK (143ms)
╭───────────────────────────╮
[b] open a browser │
[d] open devtools │
[l] turn off local mode │
[c] clear console │
[x] to exit │
╰───────────────────────────╯
As you can see there is no [wrangler:inf] POST /webhooks/kinde 200 OK after the DELETE In the console output you can see that the organization.created event timestamp is 2025-03-31T12:28:00.778346+00:00. This matches closely with the first request in the output. The second request in the output is a similar test of create + delete but you only see one event which was for create (The logs shared in my previous messages relate to the first request in the output) Below are my console outputs for ngrok:
Session Status online
Account Email
Version 3.22.0
Region Australia (au) Latency 16ms Web Interface http://127.0.0.1:4040 Forwarding https://01b8-159-196-168-111.ngrok-free.app -> http://localhost:8787

Connections ttl opn rt1 rt5 p50 p90
5 0 0.00 0.00 5.10 5.19
HTTP Requests
-------------
23:28:01.174 AEDT POST /webhooks/kinde 200 OK
23:25:56.271 AEDT POST /webhooks/kinde 200 OK
23:23:18.636 AEDT GET /apple-touch-icon.png 404 Not Found
23:23:18.636 AEDT GET /apple-touch-icon-precomposed.png 404 Not Found
23:23:18.814 AEDT GET /apple-touch-icon.png 404 Not Found
23:23:18.636 AEDT GET /favicon.ico 404 Not Found
Session Status online
Account Email
Version 3.22.0
Region Australia (au) Latency 16ms Web Interface http://127.0.0.1:4040 Forwarding https://01b8-159-196-168-111.ngrok-free.app -> http://localhost:8787

Connections ttl opn rt1 rt5 p50 p90
5 0 0.00 0.00 5.10 5.19
HTTP Requests
-------------
23:28:01.174 AEDT POST /webhooks/kinde 200 OK
23:25:56.271 AEDT POST /webhooks/kinde 200 OK
23:23:18.636 AEDT GET /apple-touch-icon.png 404 Not Found
23:23:18.636 AEDT GET /apple-touch-icon-precomposed.png 404 Not Found
23:23:18.814 AEDT GET /apple-touch-icon.png 404 Not Found
23:23:18.636 AEDT GET /favicon.ico 404 Not Found
Abdiwak Bekele
Thank you for providing the details. I will take a closer look at them. Is this Nodejs code or Nextjs code? I will get back to you as soon as possible.
__maxom__
__maxom__OP2w ago
This is Hono on CF Workers
Abdiwak Bekele
Okay, got it.
I passed this over to our engineering team and am trying to replicate it on my end as well. I will update you as soon as possible. In the meantime, please let me know if you have any other issues or need help. Hi there,
We've raised a fix for this, it seems the organization.deleted was only getting raised when called via the UI not the API. It needs to go through our review process but this should be available in prod in a few hours. Thanks for flagging the issue.
__maxom__
__maxom__OP2w ago
Hi David, Thanks for the update. As of around UTC time 2025-04-01T11:48:38.823038+00:00 where I tested organization creation, orgainzation.deleted is not yet working. I will wait for some more time to test this out. Based on this experience, I have an application design question for you guys. Kinde is the centre of my application to store the true information about users and orgs. My application is heavily dependant on Kinde providing me the necessary information as all my db tables are dependant on the user kp id and the org's org code . Up until now I had a decoupled process where user and org interactions from my application for the scenarios of creating/updating/deleting users/organizations is separate from the processes of populating my DB i.e., the calls to populate/update/delete rows of the users and orgs tables in my DB to keep it in sync with Kinde was via webhooks instead of my application API's With this issue, I'm sort of rethinking my choices as keeping my DB in sync with Kinde is like the most crucial part of my application working. Now due to my choice of offloading auth functionality to Kinde and its core dependancy to my application, is it wise for me to depend on Kinde webhooks (keeping in mind that in IT, there is always an assumption that things will fail, only a matter of when, similar to this issue) for populating the users and orgs table ? Is it better to handle these DB operations from my application API based on Kinde responses so that my DB is always in sync and I can deterministically handle errors instead of depending on webhooks ? I feel I need to change my implementation to leverage this approach instead of webhooks. This leads me to the question of how reliable are Kinde webhooks and what is the best use for them. Need some design suggestion around approach as Kinde is core to my application and I should have a deterministic way of handling things. Thanks for the help.
Abdiwak Bekele
Thank you for reaching out and sharing the details of your experience, as well as your thoughtful questions about the application design and Kinde integration. We completely understand the importance of keeping your database in sync with Kinde, especially given its central role in your application’s architecture. We’re taking your case very seriously, and I’ve escalated it to our team of experts. One of our specialists will reach out to you soon to discuss your concerns in depth, including the reliability of Kinde webhooks, best practices for their use, and design suggestions for ensuring deterministic handling of user and organization data. We’ll work with you to explore whether shifting DB operations to your application’s API based on Kinde responses might be a more robust solution, as well as address any other questions you have. In the meantime, if there’s anything else you’d like us to consider or additional context you’d like to provide, please feel free to let me know. We’re committed to helping you find the best approach for your application. Thanks again for your patience and trust in us. You’ll hear from our expert shortly! Just to confirm, this is now working in prod.

Great questions, our webhooks are generally very reliable with back-off retries over 2 days if we're unable to receive a 200 response code from your application. It's in our pipeline to extend our functionality for this feature so that you'd be able to do replays from Kinde if you ever missed anything.

I would suggest typically if you can immediately sync your data without webhooks, particularly for time-critical processes then using callbacks / api responses makes sense. For example, you can create a user in your application from the callback of a successful login, rather than waiting for a webhook, likewise if you're triggering a user update from your application to our api e.g. to change their role, you can update your database based on a 200 response. Our webhooks are typically delivered extremely fast but using callbacks / api responses is immediate and reduces risk if this is your concern.

Webhooks are useful for actions that occur outside your application, e.g. if you delete a user directly from within Kinde, webhooks offer the ability to keep your database in sync / trigger other processes e.g. deprovisioning (effectively like an inverted API). They're also useful for triggering processes in integrated applications (e.g. provisioning a user on another service on user creation) / updating a CRM.

I hope that's helpful, let us know if you have further questions.
__maxom__
__maxom__OP2w ago
Hi David, Thanks for your response. I've started implementing the changes to sync with DB from my application API's. Also my question around reliability of webhooks was mostly towards incidents where events are not being emitted similar to what happened in this chat and not in the scenarios of if the webhooks are actually working. When they work they are great. In retrospect, I should have reworded it better. My question was what checks and balances do you have in place to identify these issues like webhooks not emitting events and what remedies are in place to fix it with minimal downtime ? In this scenario, it looks like the faulty code made its way to prod without being detected in unit/integration tests/your review processes Also, I have a question regarding the callback especially after signup. In order to create a user in my DB, how do I identify if the event was a login or a signup. On both Signup and on login (with Google social provider signin), my onSuccess user object looks like:
{
"id": "kp_xxxx",
"givenName": "Name",
"email": "email",
"picture": "url"
}
{
"id": "kp_xxxx",
"givenName": "Name",
"email": "email",
"picture": "url"
}
My state is kinde:undefined
{}
{}
My context is:
{
"isAuthenticated": false,
"isLoading": true
}
{
"isAuthenticated": false,
"isLoading": true
}
My onError error is
{
"error": "ERR_CODE_EXCHANGE",
"errorDescription": "Token exchange failed: 500 - {\"error\":\"server_error\",\"error_description\":\"The authorization server encountered an unexpected condition that prevented it from fulfilling the request.\"}"
}
{
"error": "ERR_CODE_EXCHANGE",
"errorDescription": "Token exchange failed: 500 - {\"error\":\"server_error\",\"error_description\":\"The authorization server encountered an unexpected condition that prevented it from fulfilling the request.\"}"
}
state is
{
"kinde": {
"event": "login"
}
}
{
"kinde": {
"event": "login"
}
}
contex is
{
"isAuthenticated": false,
"isLoading": true
}
{
"isAuthenticated": false,
"isLoading": true
}
These values are same for both signup and login with Google (I've not tested email only auth flow btw and Google would be the preferred option anyways) How can I differentiate these events to write to my db only if it is a signup event ? On every auth attempt, do I have to check my DB every time if a user exists and if not create ? The webhooks are working fine for user events Additionally, my API layer interacts with the Kinde Management API with M2M tokens to perform actions. If I perform my DB operations for Kinde events from my API layer but also have webhooks enabled, then there would effectively be 2 write operations to my DB for the same event. To your point:
Webhooks are useful for actions that occur outside your application, e.g. if you delete a user directly from within Kinde, webhooks offer the ability to keep your database in sync / trigger other processes e.g. deprovisioning (effectively like an inverted API). They're also useful for triggering processes in integrated applications (e.g. provisioning a user on another service on user creation) / updating a CRM.
Webhooks are useful for actions that occur outside your application, e.g. if you delete a user directly from within Kinde, webhooks offer the ability to keep your database in sync / trigger other processes e.g. deprovisioning (effectively like an inverted API). They're also useful for triggering processes in integrated applications (e.g. provisioning a user on another service on user creation) / updating a CRM.
If webhooks are enabled and an action occurs inside my application, that will also trigger the webhook. So there is still overlap of functionality in this scenario. It feels like I either implement the DB operations based on API responses/callbacks from my API or use webhooks but not together. Is there a way to disable webhooks to create events if the call is from my management API but trigger them for actions outside of my application ? Similar to the error in this thread but provide it as a feature to end users. Because if I disable webhooks, I can manage the actions from my application API's but I lose the ability to manage outside actions. If I enable webhooks, I might face a similar issue discussed in this thread (do not know if/when this will happen again) So I think this is the help with direction I needed. Not sure if I have made it clearer or confused you with these messages
Abdiwak Bekele
Hi there, Sorry for not responding sooner. I will pass this over to our expert. Thank you. Hi there, Hope you had a good weekend. Currently, Kinde does not provide a direct way to selectively disable webhooks based on the source of the action (Management API vs external). However, there are a few approaches you can consider to handle this: 1. Use the Webhook Request ID for deduplication: Each webhook request contains a unique webhook-id header that can be used as an idempotency key
You can implement logic in your webhook handler to check if a request with that ID has already been processed through your API layer. 2. Event Verification: When receiving a webhook, you can verify the event using the event_id through the Management API endpoint /api/v1/events/{event_id} . This allows you to implement logic to determine if your API layer has already handled this event. 3. Selective Event Types: You can configure your webhooks to listen only for specific event types
The available triggers include events like: organization.created organization.updated user.created user.updated user.deleted user.authentication_failed user.authenticated organization.deleted role.created role.updated role.deleted permission.created permission.updated permission.deleted subscriber.created access_request.created 4. Webhook Management: You can manage webhooks programmatically using the Management API endpoints: - Create webhook: POST api/v1/webhooks - Update webhook: PATCH api/v1/webhook/{webhook_id} - Delete webhook: DELETE api/v1/webhook/{webhook_id} - List webhooks: GET api/v1/webhooks Best Practice Recommendation: To handle potential duplicate operations, implement idempotency checks using the webhook-id header
This ensures that even if you receive both an API response and a webhook for the same event, the operation will only be processed once. Please let me know if you have any other questions or need help.
__maxom__
__maxom__OP4d ago
Thanks Can you please provide some insight on the callback responses? Thanks
Abdiwak Bekele
Could you elaborate on your question, please? What kind of callback are you referring to? Ah sorry, I see what you are referring to. Kinde does not provide a direct way to distinguish between a sign-in and sign-up event
The recommended approach is to: 1. Map the Kinde user ID to your database user 2. When the token from Kinde is verified, check if : - User doesn't exist in your DB: Execute your onboarding logic - User exists in your DB: Execute login flow This is necessary because users can be created through multiple paths (API, admin UI, custom import), so a "registration" could appear like a login . For Google authentication specifically, when a user signs up with a trusted social provider (like Google): 1. The Kinde profile (first name, last name, picture) is populated from Google
. If Google is a trusted provider, Kinde creates both a social identity and an email identity 3. The user can sign in with either Google or their email (if email auth is enabled) Therefore, the recommended pattern is to: 1. Receive the authentication callback 2. Check if the user ID exists in your database 3. If not, treat it as a first-time signup and create the user record 4. If yes, treat it as a regular login Hope this finds you helpful. Please let me know if you have any more questions or need help.
__maxom__
__maxom__OP3d ago
Thanks Patrick for the detailed response.
Abdiwak Bekele
you are welcome. I am happy I could help you.
Btw our engineering team fixed an issue you experienced with Webhook.
Please let me know if you have any more questions or need help.

Did you find this page helpful?