Skip to content
  • Integrations
  • Webhooks

About webhooks

Webhooks are a way of monitoring events in Kinde, so that you can be notified and take action when something you’re monitoring happens.

How webhooks work

Link to this section

When you create a webhook, you register your own URL endpoints in Kinde and associate them with a Kinde event (e.g. when a user is created). When an endpoint is triggered, Kinde sends data about the event, so that you can initiate an action in your application or store the data.

A simple example would be setting up a webhook for when a new user is created in Kinde. This event can be set up to trigger an update to your database, enabling your system to automatically send a welcome email.

Webhooks terminology

Link to this section

You’ll come across these terms when you start using webhooks.

Endpoint - the URL called when an event occurs.

Event type - something that happens in Kinde, e.g. a user is created.

Event - an instance of an event type that happens in Kinde, e.g. Jane Doe just signed up.

Request - the request object sent to your endpoint that contains a JSON Web Token (JWT) with the event data and details about the event.

Attempt - an instance of an HTTP request attempt. Multiple request attempts may be made if Kinde does not receive a 200 response.

  1. Webhook endpoints are registered in Kinde.
  2. An event occurs in your account, e.g. user.created.
  3. Your endpoint will be called with a JWT containing the data object about that event, and details about the webhook.
    1. If a 200 response is received, the workflow is complete.
    2. If Kinde fails to receive a response, it will retry using a back-off policy (see Webhooks responses and retry policy below).
  4. In your application you should verify the authenticity of the webhook request, and decode the JWT (see Webhooks security below).
  5. Logic is triggered in your application using the event data.

Webhook request content-type

Link to this section

Kinde uses the application/jwt content-type for webhook requests.

The body of the request is a JWT token that is signed by Kinde.

eyJhbGciOiJSUzI1NiIsImtpZCI6IjJhOmUwOjRmO...

Example decoded payload

Link to this section

Here is an example decoded payload.

You can use the Kinde webhook package to decode and verify the JWT. You can also use the Kinde Online JWT decoder to view it online.

{
"data": {
"user": {
"email": "user@example.com",
"first_name": "Test",
"id": "kp_1234567890",
"is_password_reset_requested": false,
"is_suspended": false,
"last_name": "",
"organizations": [
{
"code": "org_1234567890",
"permissions": null,
"roles": null
}
],
"phone": null,
"username": null
}
},
"event_id": "event_1234567890",
"event_timestamp": "2026-02-03T12:00:00.000Z",
"source": "admin",
"timestamp": "2026-02-03T12:00:00.000Z",
"type": "user.created"
}

Webhooks identifiers

Link to this section

There are a number of unique IDs you will come across with webhooks.

  • Webhook ID: prefixed with webhook_, this refers to a webhook that you create in Kinde. Webhook IDs are exposed via the Kinde Management API webhook endpoints. You can get a list of webhooks via the endpoint GET /api/v1/webhooks
  • Event ID: prefixed with event_, this is the ID of an event that has occurred in your account, and is included as event_id in webhook request payloads. You can use this ID to retrieve an event from Kinde’s API using GET /api/v1/events/{event_id}
  • Webhook Request ID: found in webhook request headers as webhook-id, this is unique to a webhook and event, and will not change between attempts. You can use this as the idempotency key (see Webhooks security below).

Webhooks decoder

Link to this section

Kinde provides a webhooks decoder to help you decode and validate webhook tokens for easier implementation.

Here’s how to use it in a JavaScript application:

import { decodeWebhook } from "@kinde/webhooks";
const decodedToken = await decodeWebhook(
"eyJhbGciOiJSUzI1NiIsImtpZCI6IjJhOmUwOjRmO...",
"https://your-kinde-subdomain.kinde.com"); // KINDE_ISSUER_URL
if(!decodedToken) {
// return early if the webhook is not valid
// send a 400 response to Kinde
return;
}
if(decodedToken.type === "user.created") {
// send a 200 response to Kinde
// handle user created event
}

If you are using a different programming language, you will need the JWKS URL to verify the JWT. You can find the JWKS URL athttps://<your_subdomain>.kinde.com/.well-known/jwks.

Webhooks security

Link to this section

Idempotency key

Link to this section

Each webhook request has a webhook-id header that can be used to avoid reprocessing the same webhook request. This is referred to as the idempotency key, meaning that multiple requests will result in the same outcome.

Prevent Replay Attacks

Link to this section

A replay attack occurs when a payload is intercepted, potentially modified, and re-transmitted. Kinde webhooks contain a timestamp attribute in the payload, and the payload is a signed JSON Web Token (JWT). This allows you to verify that the request came from Kinde, and check the timestamp to prevent replay attacks.

Verify an event

Link to this section

You can request events by their event_id using the Kinde Management API via /api/v1/events/{event_id}. The event_id is provided in all webhook requests.

Webhooks best practices

Link to this section

Ensure webhooks are secure and optimized.

  • Handle duplicate request attempts by checking that the webhook-id header has not already been received and processed, making your processing idempotent
  • Verify the JWT to ensure that the request came from Kinde using your public JWKS file
  • Only subscribe to the events that your implementation requires; listening for all events creates unnecessary load on your server
  • Endpoints must use HTTPS
  • Return a 200 from your endpoint to indicate it has received the request

Webhooks responses and retry policy

Link to this section

If Kinde fails to receive a 200 response from your endpoint, Kinde operates a back-off retry policy, which roughly equates to the following attempts:

  • Immediately
  • After 5 seconds
  • After 30 seconds
  • After 2 minutes
  • After 10 minutes
  • After 1 hour
  • After 4 hours
  • Every 12 hours until 36 hours

Webhooks auto-disable policy

Link to this section

Webhooks that fail consistently for 72 hours are automatically disabled, and you’ll receive an email notification when this happens. This prevents runaway failures from impacting your system and keeps you informed so you can investigate and re-enable when ready.

Now that you know about webhooks, your next steps are to: