About webhooks
Integrations
This guide will walk you through connecting Kinde webhooks to Loops via Zapier, allowing you to automatically sync your Kinde users to Loops for email marketing and automation. When events like user creation or authentication happen in Kinde, they can trigger automated actions to add or update contacts in Loops.
Log in to your Zapier account and select Create > Zaps
In the Trigger step, search for Webhooks and select it.
In the Event dropdown, select Catch Raw Hook, then select Continue
Catch Raw Hook is required for Kinde webhooks because Kinde sends webhook data as a JWT token string. The raw hook will capture the complete webhook payload including the JWT token.
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.
In your Kinde dashboard, go to Settings > Webhooks
Select Add webhook
Give your webhook a descriptive name (e.g., “Kinde Zapier Loops”)
Enter a description explaining what this webhook is for (e.g., “Sync users to Loops when created”)
In the Endpoint URL field, paste the Zapier webhook URL you copied in Step 2
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 use:
user.created - When a new user signs up for the first timeuser.updated - When user information is updateduser.authenticated - When a new or existing user logs inFor a complete list of available events, see Add and manage webhooks
Select Save to create the webhook
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.
Select Code by Zapier and from the Action event dropdown, select Run JavaScript as the action. Select Continue
In the Input Data field, add a field called jwt and map it to the Raw Body from the webhook trigger
In the Code field, paste the following JavaScript to decode the JWT, replacing the existing code:
// Function to decode a JWT tokenfunction decodeJWT(token) { if (!token) { throw new Error('JWT token is missing'); }
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 dataconst jwt = inputData?.jwt;
// Decode the JWT with error handlinglet decoded = null;try { decoded = decodeJWT(jwt);} catch (error) { return { error: error.message || 'Failed to decode JWT' };}
// Extract user data from the decoded payloadconst userData = decoded?.data?.user || {};
// Return the decoded datareturn { firstName: userData.first_name || '', lastName: userData.last_name || '', email: userData.email || '', fullName: `${userData.first_name || ''} ${userData.last_name || ''}`.trim(), userId: userData.id || '', orgCode: userData?.organizations?.[0]?.code || '', rawData: decoded};Select Continue, then Test step to verify the JWT is decoded correctly.
You should see the decoded user data including first name, last name, and email
Select Continue
The JWT payload structure from Kinde includes a data object containing the user information. The Code action extracts fields like first_name, last_name, and email from this data object. See the webhook payload example for more details.
Now that you have decoded the JWT, you can use the extracted data to add contacts to Loops. This will sync your Kinde users to Loops for email marketing and automation.
In Zapier, edit your Zap and select the plus icon + to add another step after the Code action
Search for Loops and select it
From the Action event dropdown, select Add Contact as the action
Connect your Loops account:
Map the fields from your decoded JWT to Loops:
Email field from the Code step output (required)First Name field from the Code step outputLast Name field from the Code step outputkinde or zapier (optional)true (default) to ensure users receive emailsSetting subscribed to true automatically opts users into marketing emails. Under GDPR and CAN-SPAM regulations, explicit consent is typically required before sending marketing communications.
Best practices:
subscribed to true if the user explicitly consentssubscribed to false and implement a double opt-in flow where users confirm their email address before receiving marketing emailsIf the user doesn’t consent, set subscribed to false.
Select Continue
Select Test step to verify the contact is created in Loops
Check your Loops dashboard to confirm the contact was added with the correct information
Select Publish to activate your Zap
Tip: If you want to update existing contacts instead of creating duplicates, use the Update Contact action instead. Loops will update the contact if the email already exists, or create a new one if it doesn’t.
You can import all your Kinde users to Loops using Kinde’s export user feature. Follow these steps:
In your Kinde dashboard, go to Settings > Business > Details
Scroll down to the Export data section and select Export
In the pop-up window, select All data (except passwords), then select Next
Enter the one-time verification code sent to your email and select Next
You will be able to download the kinde_export.zip file
Unzip the file and you will see the users.ndjson file with all your Kinde users data
Create a new .csv file with the following columns: First Name, Last Name, Email, User Group.
Copy the user data from the users.ndjson file to this .csv file
You can use the following Python script to convert users.ndjson to .csv file:
#!/usr/bin/env python3"""Convert users.ndjson to CSV with columns:First Name, Last Name, Email, User Group"""
import jsonimport csvimport os
def extract_user_groups(user_data): """Extract user groups from organizations field.""" if 'organizations' in user_data and user_data['organizations']: # Extract organization codes and join them with comma org_codes = [org.get('code', '') for org in user_data['organizations'] if isinstance(org, dict)] return ', '.join(org_codes) return ''
def convert_ndjson_to_csv(input_file, output_file): """Convert NDJSON file to CSV.""" rows = []
# Read and parse NDJSON file with open(input_file, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if not line: continue
try: user_data = json.loads(line)
# Extract fields with fallback to empty string first_name = user_data.get('first_name', '') last_name = user_data.get('last_name', '') email = user_data.get('email', '') user_group = extract_user_groups(user_data)
rows.append({ 'First Name': first_name, 'Last Name': last_name, 'Email': email, 'User Group': user_group }) except json.JSONDecodeError as e: print(f"Warning: Skipping invalid JSON line: {e}") continue
# Write to CSV if rows: fieldnames = ['First Name', 'Last Name', 'Email', 'User Group'] with open(output_file, 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(rows)
print(f"Successfully converted {len(rows)} users to {output_file}") else: print("No data found to convert")
if __name__ == '__main__': # Get the directory of this script script_dir = os.path.dirname(os.path.abspath(__file__)) input_file = os.path.join(script_dir, 'users.ndjson') output_file = os.path.join(script_dir, 'users_output.csv')
convert_ndjson_to_csv(input_file, output_file)Run the script using the following command (You will need Python 3.x installed):
python3 convert_users_to_csv.pyGo to Loops > Audience, and select Import. A pop-up opens
Select CSV and select Upload CSV
On the new screen, upload your .csv file you created earlier and select Next
Map the CSV columns and select Import contacts
You will see the imported users in Loops Audience page
Now that you’ve successfully connected Kinde webhooks to Loops via Zapier, you can automate your email marketing and keep your user base synchronized. This integration enables you to:
For more information about Loops features and capabilities, visit the Loops documentation.