diff --git a/src/content/docs/integrate/webhooks/about-webhooks.mdx b/src/content/docs/integrate/webhooks/about-webhooks.mdx
index a96ef2c6c..c5b9f3fe2 100644
--- a/src/content/docs/integrate/webhooks/about-webhooks.mdx
+++ b/src/content/docs/integrate/webhooks/about-webhooks.mdx
@@ -7,6 +7,9 @@ sidebar:
relatedArticles:
- 7fe91aba-930c-4a63-8996-85af6bb605a7
- 95bf5e04-3415-4dc8-9ff6-953171df3f8b
+prev: false
+tableOfContents:
+ maxHeadingLevel: 3
topics:
- integrate
- webhooks
@@ -27,7 +30,7 @@ keywords:
- security
- retry policy
- endpoints
-updated: 2026-01-30
+updated: 2026-02-04
featured: false
deprecated: false
ai_summary: Comprehensive guide to Kinde webhooks including event monitoring, security best practices, JWT handling, and retry policies for real-time notifications.
@@ -35,7 +38,7 @@ ai_summary: Comprehensive guide to Kinde webhooks including event monitoring, se
@@ -43,7 +46,7 @@ Webhooks are a way of monitoring events in Kinde, so that you can be notified an
@@ -53,41 +56,124 @@ When you create a webhook, you register your own URL endpoints in Kinde and asso
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
+
+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.
+
+
## Webhooks flow
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 it fails to receive a response, it will retry using a back-off policy (see **Webhooks responses and retry policy** below).
+ 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
+
+Kinde uses the `application/jwt` content-type for webhook requests.
+
+The body of the request is a JWT token that is signed by Kinde.
+
+```text
+eyJhbGciOiJSUzI1NiIsImtpZCI6IjJhOmUwOjRmO...
+```
+
+### Example decoded payload
+
+Here is an example decoded payload.
+
+You can use the [Kinde webhook package](https://www.npmjs.com/package/@kinde/webhooks) to decode and verify the JWT. You can also use the [Kinde Online JWT decoder](https://www.kinde.com/tools/online-jwt-decoder/) to view it online.
+
+```json
+{
+ "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
There are a number of unique IDs you will come across with webhooks.
-- **Webhook ID**: prefixed with `webhook_`, this refers to the webhooks 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`
+- **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 the webhook 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).
+- **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
-Kinde provides a [webhooks decoder](https://github.com/kinde-oss/webhook) to help you decode and validate webhook tokens, for an easier implementation.
+Kinde provides a [webhooks decoder](https://www.npmjs.com/package/@kinde/webhooks) to help you decode and validate webhook tokens for easier implementation.
+
+Here's how to use it in a JavaScript application:
+
+```javascript
+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 at`https://.kinde.com/.well-known/jwks`.
## Webhooks security
### Idempotency key
-Each webhook 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.
+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
-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.
+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
-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.
+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
@@ -95,13 +181,13 @@ 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 add the events to your endpoint that your implementation requires, listening for all events creates unnecessary load on your server
+- 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
-If we fail to receive a 200 response from your endpoint, Kinde operates a back-off retry policy, this roughly equates to the following attempts:
+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
@@ -114,18 +200,11 @@ If we fail to receive a 200 response from your endpoint, Kinde operates a back-o
## Webhooks auto-disable policy
-Webhooks that fail consistently for 72 hours are now 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.
-
-## Webhooks terminology
+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.
-You’ll come across these terms when you start using webhooks.
+## Next steps
-**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.
+Now that you know about webhooks, your next steps are to:
-**Attempt** - an instance of a request making an http request, multiple request attempts may be made if we do not receive a 200 response.
+- [Add and manage webhooks](/integrate/webhooks/add-manage-webhooks)
+- [Set up webhooks using Next.js](/integrate/webhooks/webhooks-nextjs)
\ No newline at end of file
diff --git a/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx b/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx
index 3b4bc208f..43df1ac5d 100644
--- a/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx
+++ b/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx
@@ -7,6 +7,8 @@ sidebar:
relatedArticles:
- 84581694-59d6-4a02-ab8b-c7a2889713d5
- 95bf5e04-3415-4dc8-9ff6-953171df3f8b
+tableOfContents:
+ maxHeadingLevel: 3
app_context:
- m: settings
s: webhooks
@@ -31,7 +33,7 @@ keywords:
- local testing
- ngrok
- localtunnel
-updated: 2024-01-15
+updated: 2026-02-03
featured: false
deprecated: false
ai_summary: Guide to adding and managing webhooks in Kinde including security setup, trigger configuration, API management, and local testing with proxy tools.
@@ -43,7 +45,7 @@ If you are experiencing issues with webhooks, it could be because the webhook re
-Webhooks are outbound calls that are sent from Kinde when a specified events occurs. Calls are sent using HTTPS REST calls to a verified external URL you specify.
+Webhooks are outbound calls that are sent from Kinde when a specified event occurs. Calls are sent using HTTPS REST calls to a verified external URL you specify.
Use Kinde’s webhooks to create triggers and push event data to your other systems and applications.
@@ -57,13 +59,13 @@ Webhook limits apply if you are on the Kinde free plan. [See all plans](https://
Webhook request payloads are signed and sent as a JSON Web Token (JWT) from Kinde.
-You’re probably using a library to validate your JWTs and they will require the url for your public JSON Web Key (also known as a `jwks` file).
+If you’re using a library to validate your JWTs, it will require the URL for your public JSON Web Key (also known as a `JWKS` file). The JWKS file can be found at `https://.kinde.com/.well-known/jwks`
-The jwks file can be found at `https://.kinde.com/.well-known/jwks`
+If you are using a JavaScript backend, you can use the [Kinde webhooks decoder](https://www.npmjs.com/package/@kinde/webhooks) to decode and verify the JWT, outlined in the [webhooks decoder](/integrate/webhooks/about-webhooks#webhooks-decoder) section.
## Add a webhook
-1. Go to **Settings > Environment > Webhooks**.
+1. Go to **Settings > Webhooks**.
2. Select **Add webhook**.
3. Give the webhook a name and enter a description so it’s clear what it’s for.
4. Enter the external URL.
@@ -71,15 +73,15 @@ The jwks file can be found at `https://.kinde.com/.well-known/jw
## Edit a webhook
-1. Go to **Settings > Environment > Webhooks**.
+1. Go to **Settings > Webhooks**.
2. Select the webhook name to open the details window.
3. Update events and triggers.
4. Select **Save**.
## Delete a webhook
-1. Go to **Settings > Environment > Webhooks**.
-2. Select the three dots menu next to the webhook you want to delete.
+1. Go to **Settings > Webhooks**.
+2. Select the three-dot menu next to the webhook you want to delete.
3. Select **Delete webhook**. A confirmation message appears.
4. Confirm you want to delete the webhook.
@@ -151,7 +153,13 @@ In order to use webhooks, you need a publicly available URL. To test locally you
Here are a couple of free tools to help you to do this.
-- [localtunnel](https://theboroer.github.io/localtunnel-www/) - fast and easy, we recommend using the `—subdomain` attribute to fix the issued subdomain.
+- [localtunnel](https://theboroer.github.io/localtunnel-www/) - fast and easy, we recommend using the `--subdomain` attribute to fix the issued subdomain.
- [Ngrok](https://ngrok.com/) - for intermediate users, requires some dev experience to get set up.
-Each of these services exposes a local port though a public URL that can be set as your web socket.
+Each of these services exposes a local port through a public URL that can be set as your webhook endpoint.
+
+You can also use the [webhook.site](https://webhook.site/) to check the webhook request payload and headers.
+
+## Next steps
+
+- [Set up webhooks using Next.js](/integrate/webhooks/webhooks-nextjs)
\ No newline at end of file
diff --git a/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx b/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx
index 983b655db..0951e0672 100644
--- a/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx
+++ b/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx
@@ -29,134 +29,193 @@ keywords:
- local development
- ngrok
- localtunnel
-updated: 2024-01-15
+updated: 2026-02-03
featured: false
deprecated: false
ai_summary: Step-by-step guide to implementing Kinde webhooks in Next.js including JWT verification, API route setup, and local development testing.
---
-While webhooks will work with any Next.js setup, this guide uses [Next.js 14 with app router](/developer-tools/sdks/backend/nextjs-sdk/) and the `app` directory. You may need to alter some code samples if you have a different setup, but the core instructions remain the same.
+In this guide, we will set up a webhook in Kinde and configure it with a Next.js application.
+
+### What you need
+
+- A [Kinde](https://www.kinde.com/register) account with an available webhook slot (Sign up for free)
+- A running Next.js application such as the [Next.js starter kit](/developer-tools/sdks/backend/nextjs-sdk/)
+- A proxy service for local endpoint testing such as [localtunnel](https://theboroer.github.io/localtunnel-www/) or [Ngrok](https://ngrok.com/)
+
+## Step 1: Create the Kinde webhook route
+
+1. Install the Kinde webhook decoder package with the following command in your terminal:
+ ```bash
+ npm install @kinde/webhooks
+ ```
+
+2. Create the webhook route endpoint `app/api/webhook/route.ts` and add the following code:
+
+ ```bash
+ mkdir -p app/api/webhook
+ touch app/api/webhook/route.ts
+ ```
+
+
+
+ ```typescript
+ // app/api/webhook/route.ts
+ import { NextResponse } from "next/server";
+ import { decodeWebhook } from "@kinde/webhooks";
+
+ export async function POST(req: Request) {
+ try {
+ // Get the token from the request
+ const token = await req.text();
+
+ // Decode the token
+ const decodedToken = await decodeWebhook(
+ token,
+ process.env.KINDE_ISSUER_URL
+ );
+
+ if (!decodedToken) {
+ return NextResponse.json({ message: "Invalid token" }, { status: 400 });
+ }
+
+ const {
+ data,
+ type,
+ event_id,
+ event_timestamp,
+ timestamp,
+ source
+ } = decodedToken;
+
+ // Run further validation if needed based on:
+ // - event_id
+ // - event_timestamp
+ // - timestamp
+ // - source
+
+ // Handle the event based on the type
+ switch (type) {
+ case "user.updated":
+ // handle user updated event
+ // e.g. update database with data.user.email
+ console.log(data);
+ return NextResponse.json({ status: 200, statusText: "success" });
+ break;
+ case "user.created":
+ // handle user created event
+ // e.g. add user to database with data.user.email
+ console.log(data);
+ return NextResponse.json({ status: 200, statusText: "success" });
+ break;
+ default:
+ // other events that we don't handle
+ return NextResponse.json({ status: 200, statusText: "success" });
+ break;
+ }
+
+ } catch (err) {
+ if (err instanceof Error) {
+ console.error(err.message);
+ return NextResponse.json({ message: err.message }, { status: 400 });
+ }
+ }
+ return NextResponse.json({ status: 200, statusText: "success" });
+ }
+ ```
+
+ Whenever an event occurs in Kinde, a POST request is sent to this route endpoint, so that your project can react to the event. For example, refreshing a token or updating data in your database.
-## Set up local development
+ Note that the endpoint needs to be publicly available, with no route protection.
-In order to use webhooks, you need a publicly available URL. To test locally you need to use a proxy to expose your local instance on the internet. Here are a couple of free tools to help you to do this.
+
-## Create the Kinde webhook route
+3. Deploy your application to the public internet and get a public URL. Your webhook endpoint becomes: `https://your-website.com/api/webhook`
-Kinde sends webhooks as JWT’s to make them both easy and secure. In this example we will leverage 2 libraries to parse the JWT and verify the signature.
+ See our deployment guides on [Netlify](/developer-tools/guides/deploy-on-netlify) and [Vercel](/developer-tools/guides/deploy-on-vercel/) for more information.
-1. Create the file `app/api/kinde-webhook/route.ts`. The `route.ts` file is a specific file convention in Next.js that marks the route as an API route, rather than a page.
+ If you are testing locally, you can follow the local proxy service setup step below.
- ```jsx
- // app/api/kinde-webhook/route.ts
+## Step 2: (Alternative path) Set up local proxy service
- import { NextResponse } from "next/server";
+For this example, we will use localtunnel to create a public proxy URL.
- export async function POST(req: Request) {
- return NextResponse.json({ status: 200, statusText: "success" });
- }
- ```
+1. Start your development server with the following command:
- Whenever an event occurs in Kinde, a POST request is sent via this route to the specified endpoint, so that your project can react to the event. For example, refreshing a token or updating data in your database.
+ ```bash
+ npm run dev
+ ```
- Note that the endpoint needs to be publicly available, with no route protection.
+2. Open a new terminal window and install the localtunnel package with the following command:
-2. Install the dependencies.
-
-
-
-3. Update your file as follows:
-
- ```jsx
- // app/api/kinde-webhook/route.ts
-
- import { NextResponse } from "next/server";
- import jwksClient from "jwks-rsa";
- import jwt from "jsonwebtoken";
-
- // The Kinde issuer URL should already be in your `.env` file
- // from when you initially set up Kinde. This will fetch your
- // public JSON web keys file
- const client = jwksClient({
- jwksUri: `${process.env.KINDE_ISSUER_URL}/.well-known/jwks.json`,
- });
-
- export async function POST(req: Request) {
- try {
- // Get the token from the request
- const token = await req.text();
-
- // Decode the token
- const { header } = jwt.decode(token, { complete: true });
- const { kid } = header;
-
- // Verify the token
- const key = await client.getSigningKey(kid);
- const signingKey = key.getPublicKey();
- const event = await jwt.verify(token, signingKey);
-
- // Handle various events
- switch (event?.type) {
- case "user.updated":
- // handle user updated event
- // e.g update database with event.data
- console.log(event.data);
- break;
- case "user.created":
- // handle user created event
- // e.g add user to database with event.data
- console.log(event.data);
- break;
- default:
- // other events that we don't handle
- break;
- }
-
- } catch (err) {
- if (err instanceof Error) {
- console.error(err.message);
- return NextResponse.json({ message: err.message }, { status: 400 });
- }
- }
- return NextResponse.json({ status: 200, statusText: "success" });
- }
- ```
-
- As per the sample above, the JWKs file is fetched from Kinde, the token is decoded, and the signature is compared against your keys file. This is how you know you can trust the request has come from Kinde.
+ ```bash
+ npm install -g localtunnel
+ ```
+ This will install the localtunnel package globally on your computer.
-
+ ```text
+ your URL is: https://.loca.lt
+ ```
-4. Start your server so it’s ready and listening out for the next step. With most Next.js applications, run `npm run dev` in the terminal.
+ Keep this service running during the testing process.
-## Set up the webhook in Kinde
+ For more setup instructions, see the [localtunnel documentation](https://theboroer.github.io/localtunnel-www/).
-1. In the Kinde, go to **Settings > Environment > Webhooks**.
-2. Select **Add webhook**.
-3. Give the webhook a name and description.
-4. Enter the Next.js endpoint we set up earlier in your project. For example `/api/kinde-webhook`. If you are using an external tool to test the endpoint locally, enter the endpoint URL specified in the tool.
+## Step 3: Create the webhook in Kinde
-
+5. Select **Add event**. A pop-up dialog opens
+6. In the dialog that opens, select the events you want to subscribe to. (e.g., `user.created`, `user.updated`, etc.) Select **Save**
+7. Select **Save** to create the webhook
+
+## Step 4: Test the webhook
+
+1. Go to your Kinde dashboard > **Users**
+2. Create a new user or update an existing one to trigger the webhook
+3. Switch back to the terminal where your server is running and you should see the data in your server console
+
+ ```bash
+ POST /api/webhook 200 in 000ms
+ {
+ user: {
+ email: null,
+ first_name: 'test',
+ id: 'kp_1234567890',
+ is_password_reset_requested: false,
+ is_suspended: false,
+ last_name: 'test',
+ organizations: [ [Object] ],
+ phone: null,
+ username: null
+ }
+ }
+ ```
+
+You have successfully set up a webhook in Kinde and tested it.
-5. Select **Add events.**
-6. In the dialog that opens, select the events you want. For example, user events, organization events, etc.
-7. Select **Save**.
-8. In the webhook window, select **Save**.
+## Next steps
-## Test the webhook
+Add Kinde users to your database using the following tutorials:
-1. Either create a new user or update an existing one in Kinde.
-2. Switch back to where your server is running and you should see the data in your server console.
-3. Done! Have a tasty beverage.
+- [Kinde and Prisma](/integrate/third-party-tools/kinde-nextjs-prisma/)
+- [Kinde and Drizzle](/integrate/third-party-tools/kinde-nextjs-drizzle/)
\ No newline at end of file
diff --git a/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx b/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx
index 28c9c7c5b..31eaa6d3e 100644
--- a/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx
+++ b/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx
@@ -1,15 +1,17 @@
---
page_id: c9e65865-caac-45ed-a71c-2a5dd2ecd4d8
title: Connect Zapier to Kinde
-description: Guide to connecting Zapier with Kinde for automation and event-driven workflows using webhooks and event hooks
+description: Step-by-step guide to connecting Kinde webhooks with Zapier for automation and event-driven workflows using webhooks and event hooks
sidebar:
order: 4
relatedArticles:
- - 4cf32822-c02b-41d1-9396-f292bdbe5577
- - f1ba22b9-b35f-478a-be09-4524d060fe36
+ - 7fe91aba-930c-4a63-8996-85af6bb605a7
+ - 95bf5e04-3415-4dc8-9ff6-953171df3f8b
+ - 84581694-59d6-4a02-ab8b-c7a2889713d5
+next: false
app_context:
- m: settings
- s: event_hooks
+ s: webhooks
topics:
- integrate
- webhooks
@@ -25,14 +27,172 @@ keywords:
- automation
- integration
- webhooks
-updated: 2024-01-15
+ - catch hook
+updated: 2026-02-04
featured: false
deprecated: false
-ai_summary: Guide to connecting Zapier with Kinde for automation and event-driven workflows using webhooks and event hooks.
+ai_summary: Step-by-step guide to connecting Kinde webhooks with Zapier for automation and event-driven workflows using webhooks and event hooks.
---
-When we first introduced a Zapier connection, it was to offer approximate webhooks functionality, until we had [actual webhooks](/integrate/webhooks/about-webhooks/).
+This guide will walk you through connecting Kinde webhooks to Zapier, allowing you to automate workflows based on events that occur in your Kinde account. When events like user creation or authentication happen in Kinde, they can trigger automated actions in Zapier.
-Now that we have webhooks, you can still integrate with Zapier, it just works a bit different. Here’s how:
+### What you need
+
+- A [Kinde](https://www.kinde.com/register) account with an available webhook slot (Sign up for free)
+- A [Zapier](https://zapier.com/) account (Professional plan or higher required for webhook triggers)
+- A [Google account](https://accounts.google.com/) with access to Google Sheets (Sign up for free)
+
+## Step 1: Create a Zap in Zapier
+
+1. Log in to your Zapier account and select **Create** > **Zaps**
+2. In the **Trigger** step, search for **Webhooks** and select it.
+3. In the **Event** dropdown, select **Catch Raw Hook**, then select **Continue**
+
+
+
+4. In the **Test** tab, Zapier will generate a unique webhook URL for your Zap. The URL will look like: `https://hooks.zapier.com/hooks/catch/1234567/abcdefg/`
+
+ Copy this URL - you'll need it in the next step.
+
+ Keep this Zap open - you'll return to it after configuring the webhook in Kinde.
+
+## Step 2: Create a webhook in Kinde
+
+1. In your Kinde dashboard, go to **Settings > Webhooks**
+2. Select **Add webhook**
+3. Give your webhook a descriptive name (e.g., "Kinde Zapier Google Sheets")
+4. Enter a description explaining what this webhook is for (e.g., "When user is created")
+5. In the **Endpoint URL** field, paste the Zapier webhook URL you copied in Step 1
+6. Select **Add event** to select which events you want to trigger this webhook
+
+ For this example, select `user.created` to trigger the webhook when a new user is created
+
+ Common events you might want to monitor:
+ - `user.created` - When a new user signs up
+ - `user.updated` - When user information is updated
+ - `user.authenticated` - When a user logs in
+ - `organization.created` - When a new organization is created
+
+ For a complete list of available events, see [Add and manage webhooks](/integrate/webhooks/add-manage-webhooks#webhook-triggers)
+
+7. Select **Save** to create the webhook
+
+## Step 3: Test the webhook trigger
+
+1. In your Kinde dashboard, create a test user to trigger the webhook:
+ - Go to **Users** and select **Add user**
+ - Enter test user details (e.g., name: "Test User", email: "test@example.com")
+ - Select **Save**
+2. Return to Zapier and select **Test trigger** in the trigger step
+3. You should see the webhook data appear (request A). The data will be a raw JWT token string in the body
+4. Select **Continue with selected record** to proceed to the next step
+5. Zapier will open a new popup. Search for **Code** and select it
+
+## Step 4: Decode the JWT using Zapier Code action
+
+Since Kinde sends webhook data as a JWT token, you'll need to decode it to access the user information. Zapier's Code action allows you to run JavaScript to decode the JWT.
+
+1. Select **Code by Zapier** and from the Action event dropdown, select **Run JavaScript** as the action. Select **Continue**
+2. In the **Input Data** field, add a field called `jwt` and map it to the **Raw Body** from the webhook trigger
+
+ 
+
+3. In the **Code** field, paste the following JavaScript to decode the JWT, replacing the existing code:
+
+ ```javascript
+ // Function to decode a JWT token
+ function decodeJWT(token) {
+ const parts = token.split('.');
+ if (parts.length !== 3) {
+ throw new Error('Invalid JWT token');
+ }
+
+ const payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');
+ const padded = payload + '='.repeat((4 - (payload.length % 4)) % 4);
+ const decoded = JSON.parse(Buffer.from(padded, 'base64').toString('utf-8'));
+ return decoded;
+ }
+
+ // Get the JWT from input data
+ const jwt = inputData.jwt;
+
+ // Decode the JWT
+ const decoded = decodeJWT(jwt);
+
+ // Extract user data from the decoded payload
+ const userData = decoded.data.user || {};
+
+ // Return the decoded data
+ return {
+ firstName: userData.first_name || '',
+ lastName: userData.last_name || '',
+ email: userData.email || '',
+ fullName: `${userData.first_name || ''} ${userData.last_name || ''}`.trim(),
+ userId: userData.id || '',
+ rawData: decoded
+ };
+ ```
+
+4. Select **Continue**, then **Test step** to verify the JWT is decoded correctly.
+5. You should see the decoded user data including first name, last name, and email
+6. Select **Publish**
+
+
+
+## Step 5: Add Google Sheets action
+
+Now that you have decoded the JWT, you can use the extracted data in your Zap action. For this example, we'll add the user to a Google Sheet.
+
+1. In Google Sheets, create a new spreadsheet (e.g. "Kinde Zapier") with the following columns:
+ - firstname
+ - lastname
+ - email
+
+2. In Zapier, edit your Zap and select the plus icon **+** to add another step after the Code action
+3. Search for **Google Sheets** and select it
+4. From the Action event dropdown select **Create Spreadsheet Row** as the action
+5. Connect your Google account and allow permissions to access your Google Sheets. Select **Continue**
+6. Select the drive, spreadsheet, and worksheet where you want to add the user data
+7. Map the fields by selecting the plus icon **+** next to the fields
+ - **firstname**: Use the `First Name` field from the Code step output
+ - **lastname**: Use the `Last Name` field from the Code step output
+ - **email**: Use the `Email` field from the Code step output
+
+ 
+
+8. Select **Continue**
+9. Select **Test step** to see the Google Sheet populated with the user data
+
+ 
+
+10. Select **Publish** to activate your Zap
+
+## Step 6: Test the complete integration
+
+1. In your Kinde dashboard, go to **Users** and select **Add user**
+2. Create a new user with a name and email address
+3. Select **Save** to create the user
+4. The webhook will automatically trigger, sending the user data to Zapier
+5. Zapier will decode the JWT, extract the user information, and add it to your Google Sheet
+6. Check your Google Sheet to verify the user was added with the correct name and email
+7. You can also check Zapier's **Task History** to see if your Zap ran successfully
+
+## Watch the video
+
+### Conclusion
+
+Now that you've successfully connected Kinde webhooks to Zapier, you can extend this integration to automate many other workflows:
+
+- Send team alerts to Slack or Discord channels when important events occur
+- Automatically create contacts in Salesforce, HubSpot, or Pipedrive when users are created or updated
+- Add user records to Airtable, Notion databases, or MySQL databases
\ No newline at end of file