From 942618fbbb05dc641174aad211fbbd131c4705b4 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Tue, 3 Feb 2026 17:14:52 +0600 Subject: [PATCH 1/7] update about webhook doc with details --- .../integrate/webhooks/about-webhooks.mdx | 120 ++++++++++++++---- 1 file changed, 97 insertions(+), 23 deletions(-) diff --git a/src/content/docs/integrate/webhooks/about-webhooks.mdx b/src/content/docs/integrate/webhooks/about-webhooks.mdx index a96ef2c6c..6b54cb0b7 100644 --- a/src/content/docs/integrate/webhooks/about-webhooks.mdx +++ b/src/content/docs/integrate/webhooks/about-webhooks.mdx @@ -7,6 +7,8 @@ sidebar: relatedArticles: - 7fe91aba-930c-4a63-8996-85af6bb605a7 - 95bf5e04-3415-4dc8-9ff6-953171df3f8b +tableOfContents: + maxHeadingLevel: 3 topics: - integrate - webhooks @@ -35,7 +37,7 @@ ai_summary: Comprehensive guide to Kinde webhooks including event monitoring, se @@ -43,7 +45,7 @@ Webhooks are a way of monitoring events in Kinde, so that you can be notified an @@ -53,41 +55,120 @@ 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 + return; + } + +if(decodedToken.type === "user.created") { + // handle user created event +} +``` ## 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 +176,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 +195,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 From 404b63bc3e200fec61efe732dcfa8591219e0399 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Tue, 3 Feb 2026 20:37:47 +0600 Subject: [PATCH 2/7] update the jwks decoding section --- .../integrate/webhooks/about-webhooks.mdx | 2 ++ .../webhooks/add-manage-webhooks.mdx | 28 ++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/content/docs/integrate/webhooks/about-webhooks.mdx b/src/content/docs/integrate/webhooks/about-webhooks.mdx index 6b54cb0b7..c82c3da6d 100644 --- a/src/content/docs/integrate/webhooks/about-webhooks.mdx +++ b/src/content/docs/integrate/webhooks/about-webhooks.mdx @@ -156,6 +156,8 @@ if(decodedToken.type === "user.created") { } ``` +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 diff --git a/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx b/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx index 3b4bc208f..a91f73efe 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 **Environment > 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 **Environment > 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 **Environment > 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 From e75956a63ad0506a33c6fba09e4f11152e62b6d3 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Tue, 3 Feb 2026 22:53:47 +0600 Subject: [PATCH 3/7] update nextjs webhook tutorial doc --- .../integrate/webhooks/webhooks-nextjs.mdx | 202 +++++++++++------- 1 file changed, 128 insertions(+), 74 deletions(-) diff --git a/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx b/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx index 983b655db..4c3b58861 100644 --- a/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx +++ b/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx @@ -29,62 +29,38 @@ 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. -## Set up local development +### What you need -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. +- 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/) -- [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. +## Step 1: Create the Kinde webhook route -Each of these services expose a local port though a public URL that can be set as your web socket. Follow their instructions to run your local Next.js application and you will receive a URL that you need later in this guide. +1. Install the Kinde webhook decoder package with the following command in your terminal: + ```bash + npm install @kinde/webhooks + ``` -## Create the Kinde webhook route +2. Create the webhook route endpoint `app/api/webhook/route.ts` and add the following code: -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. - -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. - - ```jsx - // app/api/kinde-webhook/route.ts + ```bash + mkdir -p app/api/webhook + touch app/api/webhook/route.ts + ``` + ```typescript + // app/api/webhook/route.ts import { NextResponse } from "next/server"; - - export async function POST(req: Request) { - return NextResponse.json({ status: 200, statusText: "success" }); - } - ``` - - 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. - - Note that the endpoint needs to be publicly available, with no route protection. - -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`, - }); + import { decodeWebhook } from "@kinde/webhooks"; export async function POST(req: Request) { try { @@ -92,29 +68,48 @@ Kinde sends webhooks as JWT’s to make them both easy and secure. In this examp const token = await req.text(); // Decode the token - const { header } = jwt.decode(token, { complete: true }); - const { kid } = header; + const decodedToken = await decodeWebhook( + token, + process.env.KINDE_ISSUER_URL + ); - // Verify the token - const key = await client.getSigningKey(kid); - const signingKey = key.getPublicKey(); - const event = await jwt.verify(token, signingKey); + if (!decodedToken) { + return NextResponse.json({ message: "Invalid token" }, { status: 400 }); + } - // Handle various events - switch (event?.type) { + 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 event.data - console.log(event.data); + // 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 event.data - console.log(event.data); + // 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 - break; + return NextResponse.json({ status: 200, statusText: "success" }); + break; } } catch (err) { @@ -127,7 +122,9 @@ Kinde sends webhooks as JWT’s to make them both easy and secure. In this examp } ``` - 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. + 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. + + Note that the endpoint needs to be publicly available, with no route protection. -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. +3. Deploy your application to the public internet and get a public URL. Your webhook endpoint becomes: `https://your-website.com/api/webhook` -## Set up the webhook in Kinde + See our deployment guides on [Netlify](/developer-tools/guides/deploy-on-netlify) and [Vercel](/developer-tools/guides/deploy-on-vercel/) for more information. -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. + If you are testing locally, you can follow the local proxy service setup step below. - +1. Start your development server with the following command: + + ```bash + npm run dev + ``` + +2. Install the localtunnel package with the following command: + + ```bash + npm install -g localtunnel + ``` + This will install the localtunnel package globally on your computer. + +3. Open a new terminal window and start the localtunnel server with the following command: + + ```bash + lt --port 3000 + ``` + + Replace `3000` with the port number of your development server. This will start the localtunnel server and you will receive a public URL. + + ```text + your URL is: https://.loca.lt + ``` + + Keep this service running during the testing process. + + For more setup instructions, see the [localtunnel documentation](https://theboroer.github.io/localtunnel-www/). + +## Step 3: Create the webhook in Kinde + +1. In Kinde, go to **Environment > Settings > Webhooks** +2. Select **Add webhook** +3. Give the webhook a name and description +4. Enter the Next.js public endpoint we set up earlier in your project. For example, `https://your-website.com/api/webhook` + + If you are using an external proxy service to test the endpoint locally, enter the endpoint URL you created in the previous step (e.g., `https://.loca.lt/api/webhook`) + +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. Create a new user or update an existing one in Kinde. +2. 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 1680ms + { + 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 From 21c4cc3e60aac7d23b884615d67a8c06e42f82bc Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Tue, 3 Feb 2026 23:51:59 +0600 Subject: [PATCH 4/7] update the nextjs doc guide --- .../integrate/webhooks/about-webhooks.mdx | 2 + .../integrate/webhooks/webhooks-nextjs.mdx | 129 +++++++++--------- 2 files changed, 69 insertions(+), 62 deletions(-) diff --git a/src/content/docs/integrate/webhooks/about-webhooks.mdx b/src/content/docs/integrate/webhooks/about-webhooks.mdx index c82c3da6d..1820bb2b7 100644 --- a/src/content/docs/integrate/webhooks/about-webhooks.mdx +++ b/src/content/docs/integrate/webhooks/about-webhooks.mdx @@ -148,10 +148,12 @@ const decodedToken = await decodeWebhook( 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 } ``` diff --git a/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx b/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx index 4c3b58861..503e9b00d 100644 --- a/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx +++ b/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx @@ -57,70 +57,74 @@ In this guide, we will set up a webhook in Kinde and configure it with a Next.js 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 { + + + ```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); + } = 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" }); - } - ``` + 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. @@ -148,14 +152,14 @@ For this example, we will use localtunnel to create a public proxy URL. npm run dev ``` -2. Install the localtunnel package with the following command: +2. Open a new terminal window and install the localtunnel package with the following command: ```bash npm install -g localtunnel ``` This will install the localtunnel package globally on your computer. -3. Open a new terminal window and start the localtunnel server with the following command: +3. Start the localtunnel server with the following command: ```bash lt --port 3000 @@ -186,11 +190,12 @@ For this example, we will use localtunnel to create a public proxy URL. ## Step 4: Test the webhook -1. Create a new user or update an existing one in Kinde. -2. Switch back to the terminal where your server is running and you should see the data in your server console. +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 1680ms + POST /api/webhook 200 in 000ms { user: { email: null, From 6c502f4f536a8ee1ae95cb7e5d4f28153823eabd Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Wed, 4 Feb 2026 16:51:26 +0600 Subject: [PATCH 5/7] update the zapier page with step instructions --- .../webhooks/add-manage-webhooks.mdx | 6 +- .../integrate/webhooks/webhooks-nextjs.mdx | 2 +- .../integrate/webhooks/zapier-event-hooks.mdx | 171 +++++++++++++++++- 3 files changed, 166 insertions(+), 13 deletions(-) diff --git a/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx b/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx index a91f73efe..43df1ac5d 100644 --- a/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx +++ b/src/content/docs/integrate/webhooks/add-manage-webhooks.mdx @@ -65,7 +65,7 @@ If you are using a JavaScript backend, you can use the [Kinde webhooks decoder]( ## Add a webhook -1. Go to **Environment > Settings > 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. @@ -73,14 +73,14 @@ If you are using a JavaScript backend, you can use the [Kinde webhooks decoder]( ## Edit a webhook -1. Go to **Environment > Settings > 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 **Environment > Settings > Webhooks**. +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. diff --git a/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx b/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx index 503e9b00d..0951e0672 100644 --- a/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx +++ b/src/content/docs/integrate/webhooks/webhooks-nextjs.mdx @@ -177,7 +177,7 @@ For this example, we will use localtunnel to create a public proxy URL. ## Step 3: Create the webhook in Kinde -1. In Kinde, go to **Environment > Settings > Webhooks** +1. In Kinde, go to **Settings > Webhooks** 2. Select **Add webhook** 3. Give the webhook a name and description 4. Enter the Next.js public endpoint we set up earlier in your project. For example, `https://your-website.com/api/webhook` diff --git a/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx b/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx index 28c9c7c5b..f4bedc903 100644 --- a/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx +++ b/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx @@ -1,15 +1,16 @@ --- 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 app_context: - m: settings - s: event_hooks + s: webhooks topics: - integrate - webhooks @@ -25,14 +26,166 @@ 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 a Google Sheets (Sign up for free) + +## Step 1: Create a Zap in Zapier + +1. Log in to your Zapier account and click **Create Zap**. +2. In the **Trigger** step, search for **Webhooks by Zapier**. +3. Select **Webhooks by Zapier** from the results. +4. In the **Event** dropdown, select **Catch Raw Hook**. + + + +5. Click **Continue**. + +## Step 2: Get your Zapier webhook URL + +1. In the **Test** tab, Zapier will generate a unique webhook URL for your Zap. +2. The URL will look like: `https://hooks.zapier.com/hooks/catch/1234567/abcdefg/` +3. **Copy this URL** - you'll need it in the next step. + + + +4. Keep this Zap open - you'll return to it after configuring the webhook in Kinde. + +## Step 3: Create a webhook in Kinde + +1. In your Kinde dashboard, go to **Settings > Webhooks**. +2. Click **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 2. +6. Click **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. Click **Save** to create the webhook. + +## Step 4: Test the webhook trigger + +1. Return to your Zap in Zapier. +2. In your Kinde dashboard, create a test user to trigger the webhook: + - Go to **Users** and click **Add user** + - Enter test user details (e.g., name: "Test User", email: "test@example.com") + - Click **Save** +3. Return to Zapier and click **Test trigger** in the trigger step. +4. You should see the webhook data appear. The data will be a raw JWT token string in the body. +5. Click **Continue** to proceed to the next step. + +## Step 5: 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. In your Zap, click **+** to add a new step. +2. Search for **Code by Zapier** and select it. +3. Choose **Run JavaScript** as the action. +4. In the **Input Data** field, add a field called `jwt` and map it to the raw body from the webhook trigger. +5. In the **Code** field, paste the following JavaScript to decode the JWT: + +```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]; + const decoded = JSON.parse(Buffer.from(payload, '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 || {}; + +// Return the decoded data +return { + firstName: userData.given_name || '', + lastName: userData.family_name || '', + email: userData.email || '', + fullName: `${userData.given_name || ''} ${userData.family_name || ''}`.trim(), + userId: userData.id || '', + rawData: decoded +}; +``` + +6. Click **Continue** and then **Test step** to verify the JWT is decoded correctly. +7. You should see the decoded user data including first name, last name, and email. + + + +## Step 6: Configure your Zap 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. Click **+** to add another step after the Code action. +2. Search for **Google Sheets** and select it. +3. Choose **Create Spreadsheet Row** as the action. +4. Connect your Google account if prompted. +5. Select the spreadsheet and worksheet where you want to add the user data. +6. Map the fields: + - **Name**: Use the `fullName` field from the Code step output + - **Email**: Use the `email` field from the Code step output + - Or create separate columns for first name and last name using `firstName` and `lastName` +7. Click **Continue** and then **Test step** to verify it works. +8. Click **Publish** to activate your Zap. + +## Step 7: Test the complete integration + +1. In your Kinde dashboard, go to **Users**. +2. Create a new user with a name and email address. +3. Click **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 + + \ No newline at end of file From c9047c466fb4adf8d9e9dc866edab77efa437dc3 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Wed, 4 Feb 2026 21:10:21 +0600 Subject: [PATCH 6/7] update zapier guide --- .../integrate/webhooks/about-webhooks.mdx | 3 +- .../integrate/webhooks/zapier-event-hooks.mdx | 204 +++++++++--------- 2 files changed, 107 insertions(+), 100 deletions(-) diff --git a/src/content/docs/integrate/webhooks/about-webhooks.mdx b/src/content/docs/integrate/webhooks/about-webhooks.mdx index 1820bb2b7..c5b9f3fe2 100644 --- a/src/content/docs/integrate/webhooks/about-webhooks.mdx +++ b/src/content/docs/integrate/webhooks/about-webhooks.mdx @@ -7,6 +7,7 @@ sidebar: relatedArticles: - 7fe91aba-930c-4a63-8996-85af6bb605a7 - 95bf5e04-3415-4dc8-9ff6-953171df3f8b +prev: false tableOfContents: maxHeadingLevel: 3 topics: @@ -29,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. diff --git a/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx b/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx index f4bedc903..a1297de74 100644 --- a/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx +++ b/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx @@ -8,6 +8,7 @@ relatedArticles: - 7fe91aba-930c-4a63-8996-85af6bb605a7 - 95bf5e04-3415-4dc8-9ff6-953171df3f8b - 84581694-59d6-4a02-ab8b-c7a2889713d5 +next: false app_context: - m: settings s: webhooks @@ -39,14 +40,13 @@ This guide will walk you through connecting Kinde webhooks to Zapier, allowing y - 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 a Google Sheets (Sign up for free) +- 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 click **Create Zap**. -2. In the **Trigger** step, search for **Webhooks by Zapier**. -3. Select **Webhooks by Zapier** from the results. -4. In the **Event** dropdown, select **Catch Raw Hook**. +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** -5. Click **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/` -## Step 2: Get your Zapier webhook URL + Copy this URL - you'll need it in the next step. -1. In the **Test** tab, Zapier will generate a unique webhook URL for your Zap. -2. The URL will look like: `https://hooks.zapier.com/hooks/catch/1234567/abcdefg/` -3. **Copy this URL** - you'll need it in the next step. - - - -4. Keep this Zap open - you'll return to it after configuring the webhook in Kinde. + Keep this Zap open - you'll return to it after configuring the webhook in Kinde. -## Step 3: Create a webhook in Kinde +## Step 2: Create a webhook in Kinde -1. In your Kinde dashboard, go to **Settings > Webhooks**. -2. Click **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 2. -6. Click **Add event** to select which events you want to trigger this webhook. +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. + 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 @@ -87,105 +77,121 @@ This guide will walk you through connecting Kinde webhooks to Zapier, allowing y - `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). + For a complete list of available events, see [Add and manage webhooks](/integrate/webhooks/add-manage-webhooks#webhook-triggers) -7. Click **Save** to create the webhook. +7. Select **Save** to create the webhook -## Step 4: Test the webhook trigger +## Step 3: Test the webhook trigger -1. Return to your Zap in Zapier. -2. In your Kinde dashboard, create a test user to trigger the webhook: - - Go to **Users** and click **Add user** +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") - - Click **Save** -3. Return to Zapier and click **Test trigger** in the trigger step. -4. You should see the webhook data appear. The data will be a raw JWT token string in the body. -5. Click **Continue** to proceed to the next step. + - 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 5: Decode the JWT using Zapier Code action +## 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. In your Zap, click **+** to add a new step. -2. Search for **Code by Zapier** and select it. -3. Choose **Run JavaScript** as the action. -4. In the **Input Data** field, add a field called `jwt` and map it to the raw body from the webhook trigger. -5. In the **Code** field, paste the following 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 + + ![zapier custom code](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/fd811428-ac35-4807-f625-ea108c25e500/socialsharingimage) -```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]; - const decoded = JSON.parse(Buffer.from(payload, 'base64').toString('utf-8')); - return decoded; -} +3. In the **Code** field, paste the following JavaScript to decode the JWT, replacing the existing code: -// Get the JWT from input data -const jwt = inputData.jwt; + ```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]; + const decoded = JSON.parse(Buffer.from(payload, 'base64').toString('utf-8')); + return decoded; + } -// Decode the JWT -const decoded = decodeJWT(jwt); + // Get the JWT from input data + const jwt = inputData.jwt; -// Extract user data from the decoded payload -const userData = decoded.data || {}; + // Decode the JWT + const decoded = decodeJWT(jwt); -// Return the decoded data -return { - firstName: userData.given_name || '', - lastName: userData.family_name || '', - email: userData.email || '', - fullName: `${userData.given_name || ''} ${userData.family_name || ''}`.trim(), - userId: userData.id || '', - rawData: decoded -}; -``` + // Extract user data from the decoded payload + const userData = decoded.data.user || {}; -6. Click **Continue** and then **Test step** to verify the JWT is decoded correctly. -7. You should see the decoded user data including first name, last name, and email. + // 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 + }; + ``` - + +## 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. Click **+** to add another step after the Code action. -2. Search for **Google Sheets** and select it. -3. Choose **Create Spreadsheet Row** as the action. -4. Connect your Google account if prompted. -5. Select the spreadsheet and worksheet where you want to add the user data. -6. Map the fields: - - **Name**: Use the `fullName` field from the Code step output - - **Email**: Use the `email` field from the Code step output - - Or create separate columns for first name and last name using `firstName` and `lastName` -7. Click **Continue** and then **Test step** to verify it works. -8. Click **Publish** to activate your Zap. +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 + + ![zapier google sheets](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/29d05068-4c95-4822-841c-f0150c2e0a00/socialsharingimage) -## Step 7: Test the complete integration +8. Select **Continue** +9. Select **Test step** to see the Google Sheet populated with the user data -1. In your Kinde dashboard, go to **Users**. -2. Create a new user with a name and email address. -3. Click **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. + ![zapier google sheets sample data](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/4bf73e32-a2f4-412c-a002-b0071d299d00/socialsharingimage) - +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 - \ No newline at end of file + + +### 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 From fed667e5f603ad2271902312411b297d2dacc1fe Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Thu, 5 Feb 2026 00:39:34 +0600 Subject: [PATCH 7/7] update coderabbit changes --- src/content/docs/integrate/webhooks/zapier-event-hooks.mdx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx b/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx index a1297de74..31eaa6d3e 100644 --- a/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx +++ b/src/content/docs/integrate/webhooks/zapier-event-hooks.mdx @@ -111,8 +111,9 @@ Since Kinde sends webhook data as a JWT token, you'll need to decode it to acces throw new Error('Invalid JWT token'); } - const payload = parts[1]; - const decoded = JSON.parse(Buffer.from(payload, 'base64').toString('utf-8')); + 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; } @@ -142,7 +143,7 @@ Since Kinde sends webhook data as a JWT token, you'll need to decode it to acces