diff --git a/n8n-skool/ai-termimal-skool-config-reference.md b/n8n-skool/ai-termimal-skool-config-reference.md deleted file mode 100644 index 1fa4da3..0000000 --- a/n8n-skool/ai-termimal-skool-config-reference.md +++ /dev/null @@ -1,496 +0,0 @@ -# Skool + n8n Configuration Reference - -**VPS**: ai-termimal -**Created**: 2025-11-29 - -## Quick Configuration Checklist - -Use this as a quick reference when setting up or updating your workflow. - -### Required Values to Extract from Browser - -| Value | Where to Find | Used In | Notes | -|-------|--------------|---------|-------| -| Cookie | Network > request-bulk-action > Headers > Request Headers | Nodes 2, 3, 4 | Very long string, expires periodically | -| User-Agent | Network > request-bulk-action > Headers > Request Headers | Nodes 2, 3, 4 | Your browser identifier | -| X-AWS-WAF-Token | Network > request-bulk-action > Headers > Request Headers | Nodes 2, 3 | Security token, expires | -| Request Payload | Network > request-bulk-action > Payload | Node 2 | JSON body for export request | -| Expires | Network > Doc > Downloaded file URL | Node 4 | Query parameter for file download | -| Signature | Network > Doc > Downloaded file URL | Node 4 | Query parameter for file download | -| Key-Pair-Id | Network > Doc > Downloaded file URL | Node 4 | Query parameter for file download | - ---- - -## Customization Points - -### 1. Schedule Frequency - -**Location**: Schedule Trigger Node -**Default**: Every 2 hours -**Customization**: -``` -Hours: 1, 2, 4, 6, 12, 24 -Minutes: 15, 30, 45, 60 -``` - -**Decision Guide**: -- **Active community** (>10 joins/day): Every 1-2 hours -- **Medium activity** (3-10 joins/day): Every 4-6 hours -- **Low activity** (<3 joins/day): Every 12-24 hours - -### 2. Member Limit - -**Location**: Limit Node -**Default**: 15 members -**Formula**: `(Expected joins/hour × Hours between triggers) × 1.5` - -**Examples**: -- If you get 5 members/day and run every 2 hours: `(5/12 × 2) × 1.5 ≈ 2` → Set to 5 (minimum safe) -- If you get 50 members/day and run every 2 hours: `(50/12 × 2) × 1.5 ≈ 12` → Set to 15 -- If you get 200 members/day and run every 2 hours: `(200/12 × 2) × 1.5 ≈ 50` → Set to 50 - -**Why 1.5x multiplier?**: Safety buffer for spikes in signups - -### 3. Email Platform Integration - -This is the most variable part of the workflow. Here are examples for popular platforms: - ---- - -## Email Platform Examples - -### ConvertKit - -#### Search for Subscriber -```json -Node Type: HTTP Request -Method: GET -URL: https://api.convertkit.com/v3/subscribers -Query Parameters: - - api_secret: YOUR_API_SECRET - - email_address: {{ $json.email }} - -Response: Returns subscriber if exists, empty if not -``` - -#### Create Subscriber -```json -Node Type: HTTP Request -Method: POST -URL: https://api.convertkit.com/v3/forms/YOUR_FORM_ID/subscribe -Headers: - - Content-Type: application/json -Body: -{ - "api_key": "YOUR_API_KEY", - "email": "{{ $json.email }}", - "first_name": "{{ $json.first_name }}", - "tags": ["Skool Member"] -} -``` - -#### Tag Subscriber -```json -Node Type: HTTP Request -Method: POST -URL: https://api.convertkit.com/v3/tags/YOUR_TAG_ID/subscribe -Body: -{ - "api_secret": "YOUR_API_SECRET", - "email": "{{ $json.email }}" -} -``` - ---- - -### Mailchimp - -#### Search for Subscriber -```json -Node Type: Mailchimp -Operation: Get Member -Audience ID: YOUR_AUDIENCE_ID -Email: {{ $json.email }} - -If exists: Returns member info -If not exists: Returns error (handle with error workflow) -``` - -#### Create Subscriber -```json -Node Type: Mailchimp -Operation: Create or Update Member -Audience ID: YOUR_AUDIENCE_ID -Email: {{ $json.email }} -Status: subscribed -Merge Fields: - FNAME: {{ $json.first_name }} - LNAME: {{ $json.last_name }} -Tags: Skool Member, New Member -``` - ---- - -### ActiveCampaign - -#### Search for Contact -```json -Node Type: ActiveCampaign -Operation: Get Contact -Email: {{ $json.email }} -``` - -#### Create Contact -```json -Node Type: ActiveCampaign -Operation: Create or Update Contact -Email: {{ $json.email }} -First Name: {{ $json.first_name }} -Last Name: {{ $json.last_name }} -Tags: Skool Member -Lists: YOUR_LIST_ID -``` - ---- - -### SendGrid - -#### Search for Contact -```json -Node Type: HTTP Request -Method: POST -URL: https://api.sendgrid.com/v3/marketing/contacts/search -Headers: - - Authorization: Bearer YOUR_API_KEY - - Content-Type: application/json -Body: -{ - "query": "email = '{{ $json.email }}'" -} -``` - -#### Create Contact -```json -Node Type: HTTP Request -Method: PUT -URL: https://api.sendgrid.com/v3/marketing/contacts -Headers: - - Authorization: Bearer YOUR_API_KEY - - Content-Type: application/json -Body: -{ - "contacts": [ - { - "email": "{{ $json.email }}", - "first_name": "{{ $json.first_name }}", - "last_name": "{{ $json.last_name }}" - } - ] -} -``` - ---- - -### Generic HTTP Request Template - -For any email platform with API access: - -#### Search Pattern -```json -Method: GET or POST -URL: [PLATFORM_API_URL]/search or /subscribers or /contacts -Authentication: API Key / Bearer Token (check platform docs) -Query/Body: { "email": "{{ $json.email }}" } -``` - -#### Create Pattern -```json -Method: POST or PUT -URL: [PLATFORM_API_URL]/create or /subscribe or /add -Authentication: API Key / Bearer Token -Body: -{ - "email": "{{ $json.email }}", - "first_name": "{{ $json.first_name }}", - "last_name": "{{ $json.last_name }}", - "tags": ["Skool Member"], - "custom_fields": { ... } -} -``` - ---- - -## CSV Field Mapping - -The CSV export from Skool typically contains these fields (may vary): - -| Skool Field | Description | Use In Email Platform | -|-------------|-------------|---------------------| -| email | Member's email | Primary identifier | -| first_name | First name | Personalization | -| last_name | Last name | Personalization | -| joined_at | Join timestamp | Segmentation | -| status | active/inactive | Filter | -| profile_url | Skool profile link | Custom field | -| member_id | Unique ID | Reference | - -**Access in n8n**: `{{ $json.field_name }}` - -**Example**: -- Email: `{{ $json.email }}` -- Name: `{{ $json.first_name }} {{ $json.last_name }}` -- Join Date: `{{ $json.joined_at }}` - ---- - -## Advanced Customizations - -### 1. Filter by Join Date - -Add a filter node after CSV extraction to only process members who joined in the last X hours: - -```javascript -// In a Function node -const hoursAgo = 2; // Match your schedule frequency -const cutoffTime = new Date(Date.now() - (hoursAgo * 60 * 60 * 1000)); -const joinedAt = new Date($json.joined_at); - -return joinedAt > cutoffTime; -``` - -### 2. Add Custom Fields - -Map Skool data to custom fields in your email platform: - -```json -{ - "email": "{{ $json.email }}", - "custom_fields": { - "skool_join_date": "{{ $json.joined_at }}", - "skool_profile": "{{ $json.profile_url }}", - "skool_member_id": "{{ $json.member_id }}", - "source": "Skool Community" - } -} -``` - -### 3. Conditional Tagging - -Tag members based on Skool data: - -```javascript -// In a Function node before adding to email platform -const tags = ['Skool Member']; - -// Check if joined recently (within 24 hours) -const joinedRecently = (Date.now() - new Date($json.joined_at)) < 86400000; -if (joinedRecently) { - tags.push('New Member'); -} - -// Add to return object -return { - ...$json, - tags: tags -}; -``` - -### 4. Segment by Activity Level - -If your Skool export includes activity data: - -```javascript -// Assuming there's an activity_score field -if ($json.activity_score > 50) { - tags.push('Highly Engaged'); -} else if ($json.activity_score > 20) { - tags.push('Moderately Engaged'); -} else { - tags.push('Low Engagement'); -} -``` - -### 5. Welcome Email Sequences - -After adding to email platform, trigger different sequences: - -```javascript -// Based on member type or interests -if ($json.interests && $json.interests.includes('AI')) { - sequenceId = 'AI_WELCOME_SEQUENCE'; -} else if ($json.interests && $json.interests.includes('Marketing')) { - sequenceId = 'MARKETING_WELCOME_SEQUENCE'; -} else { - sequenceId = 'GENERAL_WELCOME_SEQUENCE'; -} -``` - ---- - -## Error Handling - -### Recommended Error Workflow - -Add an "Error Trigger" node to handle failures: - -1. **Error Trigger Node**: Catches any workflow errors -2. **IF Node**: Check error type -3. **Notification Node**: Send alert (email, Slack, Discord) - -**Common Errors**: -- `401 Unauthorized`: Tokens expired → Re-extract from browser -- `404 Not Found`: URL changed → Check Skool API structure -- `429 Too Many Requests`: Rate limited → Reduce frequency -- `CSV Parse Error`: Format changed → Check CSV structure - -### Error Notification Template - -```json -{ - "subject": "Skool Sync Error", - "message": "Workflow failed at {{ $json.node }}\nError: {{ $json.error.message }}\nTime: {{ $now }}" -} -``` - ---- - -## Performance Optimization - -### Reduce n8n Executions - -**Current Cost** (example): -- Runs every 2 hours = 12 executions/day -- Checks 15 members each = 180 checks/day -- With native integrations ≈ 200 operations/day - -**Optimization**: -- Use native nodes when available (count as 1 operation vs HTTP = multiple) -- Increase schedule interval if acceptable latency -- Use conditional logic to skip unnecessary API calls - -### Batch Processing - -For high-volume communities, consider batching: - -```javascript -// Instead of loop, batch add members -const newMembers = $input.all().map(item => ({ - email: item.json.email, - first_name: item.json.first_name, - last_name: item.json.last_name -})); - -// Send as array to email platform (if supported) -return [{ json: { contacts: newMembers } }]; -``` - ---- - -## Security Best Practices - -### 1. Use n8n Credentials - -Don't hardcode tokens in nodes: -1. Go to **Credentials** in n8n -2. Create new credential for each service -3. Select credential in nodes instead of pasting values - -### 2. Environment Variables - -For self-hosted n8n, use environment variables: -```bash -export SKOOL_COOKIE="your_cookie" -export CONVERTKIT_API_KEY="your_key" -``` - -Access in workflow: `{{ $env.SKOOL_COOKIE }}` - -### 3. Rotate Tokens Regularly - -Set a reminder to refresh Skool tokens: -- Weekly for high-security requirements -- Bi-weekly for normal use -- When workflow fails (reactive) - -### 4. Monitor for Unauthorized Access - -Check your email platform for: -- Unusual subscription patterns -- Failed authentication attempts -- Unexpected data changes - ---- - -## Testing Checklist - -Before activating your workflow: - -- [ ] Test Schedule Trigger manually -- [ ] Verify HTTP Request 1 returns `fileId` -- [ ] Verify HTTP Request 2 returns download URL -- [ ] Verify HTTP Request 3 downloads CSV -- [ ] Check CSV extraction produces member objects -- [ ] Confirm Limit node returns expected count -- [ ] Test email platform search (existing member) -- [ ] Test email platform create (new member) -- [ ] Verify tags are applied correctly -- [ ] Check welcome sequence triggers -- [ ] Test complete workflow end-to-end -- [ ] Monitor first scheduled execution -- [ ] Verify no duplicate additions after 24 hours - ---- - -## Maintenance Schedule - -### Weekly -- [ ] Check workflow execution history -- [ ] Verify no failed executions -- [ ] Spot-check email platform for new members - -### Monthly -- [ ] Review member limit vs actual joins -- [ ] Optimize schedule frequency if needed -- [ ] Audit email platform for data accuracy -- [ ] Update tokens if experiencing auth issues - -### Quarterly -- [ ] Review automation ROI (time saved) -- [ ] Consider additional automations -- [ ] Update documentation with learnings - ---- - -## Troubleshooting Decision Tree - -``` -Workflow Failed? -├─ Authentication Error (401) -│ └─ Re-extract cookies and tokens -├─ No fileId returned -│ └─ Check request payload structure -├─ CSV download failed -│ └─ Re-extract download URL parameters -├─ No new members found -│ └─ Normal if no one joined (check Skool) -├─ Duplicates in email list -│ └─ Check IF node logic (should check existence) -└─ Email platform error - └─ Check API credentials and rate limits -``` - ---- - -## Support Resources - -- **n8n Community**: https://community.n8n.io -- **n8n Documentation**: https://docs.n8n.io -- **Your Email Platform API Docs**: [Insert link] -- **Original Tutorial**: https://www.youtube.com/watch?v=vZaYYzb4y5Y - ---- - -## Version History - -- **v1.0** (2025-11-29): Initial configuration based on Sant Kala's tutorial -- Document updated for VPS: ai-termimal diff --git a/n8n-skool/ai-termimal-skool-n8n-detailed-setup.md b/n8n-skool/ai-termimal-skool-n8n-detailed-setup.md deleted file mode 100644 index e540198..0000000 --- a/n8n-skool/ai-termimal-skool-n8n-detailed-setup.md +++ /dev/null @@ -1,364 +0,0 @@ -# Skool + n8n Integration - Detailed Step-by-Step Setup - -**VPS**: ai-termimal -**Created**: 2025-11-29 - -## Part 1: Extract Authentication Tokens from Skool - -### Step 1: Open Skool and Browser DevTools - -1. Log into your Skool community admin panel -2. Navigate to the Members section -3. **Right-click** anywhere on the page -4. Click **"Inspect"** (or press F12) -5. Click on the **"Network"** tab in DevTools -6. Make sure it's recording (red circle should be active) - -### Step 2: Trigger the Export Action - -1. In the Network tab, click on **"All"** filter -2. **Do NOT click Export button yet** -3. With Network tab open and recording, click the **"Export"** button in Skool -4. You'll see many network requests appear -5. Look for a request called **"request-bulk-action"** (usually has a yellow icon) - -### Step 3: Extract Required Headers - -Click on the **"request-bulk-action"** request: - -#### A. Get the Request URL -1. Click on **"Headers"** tab -2. Find **"Request URL"** at the top -3. Copy everything up to (and including) `/request-bulk-action` -4. Example: `https://api.school.com/api/request-bulk-action` - -#### B. Get the Cookie -1. Scroll down to **"Request Headers"** section -2. Find the **"cookie:"** header -3. Copy the ENTIRE cookie value (will be very long) -4. Save this in a secure note - you'll need it multiple times - -#### C. Get the User-Agent -1. In the same Request Headers section -2. Find **"user-agent:"** -3. Copy the value -4. Example: `Mozilla/5.0 (X11; Linux x86_64)...` - -#### D. Get the X-AWS-WAF-Token -1. In the same Request Headers section -2. Find **"x-aws-waf-token:"** -3. Copy the entire token value -4. This is usually a long alphanumeric string - -#### E. Get the Request Payload -1. Click on the **"Payload"** tab -2. You'll see JSON data - copy it exactly -3. Should look like: -```json -{ - "action": "bulk-export", - "filters": {...} -} -``` - -### Step 4: Extract Download URL Parameters - -After clicking Export, Skool downloads a CSV file: - -1. In the Network tab, click on **"Doc"** filter (or "Document") -2. Find a request that shows the downloaded file -3. Click on it and go to **"Headers"** -4. In the Request URL, you'll see query parameters: - - `Expires=...` - - `Signature=...` - - `Key-Pair-Id=...` -5. Copy each of these values - -**Note**: These values change with each export, but you need them for the n8n workflow structure - ---- - -## Part 2: Create n8n Workflow - -### Node 1: Schedule Trigger - -1. In n8n, add a **"Schedule Trigger"** node -2. Configure: - - **Trigger Interval**: Hours - - **Hours Between Triggers**: 2 - -**Explanation**: Runs every 2 hours to check for new members - -### Node 2: HTTP Request - Export Members - -1. Add an **"HTTP Request"** node -2. Connect it to the Schedule Trigger -3. Configure: - -**Authentication**: None - -**Method**: POST - -**URL**: -``` -https://api.school.com/api/request-bulk-action -``` - -**Send Query Parameters**: ON -- Name: `type` | Value: `bulk-export-csv` -- Name: `all-members-selected` | Value: `true` -- Name: `members-status` | Value: `active` - -**Send Headers**: ON -- Name: `accept` | Value: `*/*` -- Name: `accept-encoding` | Value: `gzip, deflate, br` -- Name: `accept-language` | Value: `en-US,en;q=0.9` -- Name: `cache-control` | Value: `no-cache` -- Name: `content-type` | Value: `application/json` -- Name: `Cookie` | Value: `[PASTE YOUR COOKIE HERE]` -- Name: `origin` | Value: `https://www.school.com` -- Name: `referer` | Value: `https://www.school.com` -- Name: `user-agent` | Value: `[PASTE YOUR USER-AGENT HERE]` -- Name: `x-aws-waf-token` | Value: `[PASTE YOUR TOKEN HERE]` -- Name: `cookie` | Value: `[PASTE YOUR COOKIE HERE]` (lowercase, same value) - -**Send Body**: ON -- Body Content Type: JSON -- Paste the payload JSON you copied earlier - -**Expected Output**: A JSON response with a `fileId` - -### Node 3: HTTP Request - Get Download URL - -1. Add another **"HTTP Request"** node -2. Connect it to Node 2 -3. Configure: - -**Method**: GET - -**URL**: -``` -https://api.school.com/api/files/{{ $json.fileId }}/download-url -``` -(Use expression editor to insert `{{ $json.fileId }}` from previous node) - -**Send Headers**: ON -- Use the **exact same headers** as Node 2 - -**Send Body**: OFF - -**Expected Output**: A JSON response with a `data` field containing download URL - -### Node 4: HTTP Request - Download CSV File - -1. Add another **"HTTP Request"** node -2. Connect it to Node 3 -3. Configure: - -**Method**: GET - -**URL**: -``` -{{ $json.data }} -``` -(Use expression editor to insert the data field from previous node) - -**Send Query Parameters**: ON -- Name: `Expires` | Value: `[YOUR EXPIRES VALUE]` -- Name: `Signature` | Value: `[YOUR SIGNATURE VALUE]` -- Name: `Key-Pair-Id` | Value: `[YOUR KEY-PAIR-ID VALUE]` - -**Note**: These values need to be extracted each time OR you can try to parse them from the download URL dynamically - -**Send Headers**: ON -- Use the same headers as before - -**Expected Output**: Binary data (the CSV file) named something like `community-members.csv` - -### Node 5: Extract from File (CSV) - -1. Add an **"Extract from File"** node -2. Connect it to Node 4 -3. Configure: - -**Operation**: Extract from Binary Data -**Binary Property**: `data` -**File Format**: CSV -**Input Binary Field Name**: `community-members.csv` - -**Expected Output**: Array of objects with member data (email, name, joined date, etc.) - -### Node 6: Limit - -1. Add a **"Limit"** node -2. Connect it to Node 5 -3. Configure: - -**Max Items**: `15` (adjust based on expected new members per time interval) -**Keep**: First items - -**Explanation**: Since members are sorted by join date (newest first), this grabs only the most recent 15 members. Adjust based on your community growth rate. - -### Node 7: Loop Over Items - -1. Add a **"Loop Over Items"** node -2. Connect it to Node 6 - -**Explanation**: This will process each of the 15 members one at a time - -### Node 8: Email Platform Integration (Example with ConvertKit) - -**This part varies based on your email platform. Below is the general logic:** - -#### Option A: Using Native Integration (if available) - -1. Add your email platform node (e.g., "ConvertKit", "Mailchimp", "ActiveCampaign") -2. Configure: - - **Operation**: Search Subscriber (or similar) - - **Email**: `{{ $json.email }}` from the loop - -#### Option B: Using HTTP Request - -If your platform doesn't have native n8n integration: - -1. Add **"HTTP Request"** node -2. Configure based on your email platform's API documentation -3. Typically: GET request to search for subscriber by email - -### Node 9: IF Condition - -1. Add an **"IF"** node -2. Connect it to Node 8 -3. Configure: - -**Condition**: Check if subscriber exists -- **Value 1**: `{{ $json.subscribers }}` or similar (field from email platform) -- **Operation**: Is Empty (or Length = 0) -- **Logic**: If TRUE (subscriber doesn't exist), proceed to add them - -### Node 10: Add Subscriber (True Branch) - -1. Add your email platform node on the **TRUE** branch -2. Configure: - - **Operation**: Create Subscriber - - **Email**: `{{ $json.email }}` - - **First Name**: `{{ $json.first_name }}` (adjust field names) - - **Tags**: Add appropriate tag (e.g., "Skool Member", "New Member") - -### Node 11: Return to Loop (False Branch) - -1. Connect the **FALSE** branch back to the Loop Over Items node -2. This skips existing members - ---- - -## Part 3: Testing & Deployment - -### Test the Workflow - -1. **Manually trigger** the workflow (don't wait for schedule) -2. Check each node's output: - - Node 2 should return a `fileId` - - Node 3 should return a download URL - - Node 4 should show binary CSV data - - Node 5 should show parsed member data - - Node 6 should show limited results - -3. **Verify email platform**: - - Check if test members were added - - Verify tags are applied correctly - - Test email sequences trigger properly - -### Activate the Workflow - -1. Click **"Active"** toggle in n8n -2. The workflow will now run on schedule -3. Monitor the executions tab for errors - -### Monitoring - -Set up monitoring for: -- **Failed executions**: Likely due to expired tokens -- **No new members**: Expected behavior if no one joined -- **Duplicate additions**: Check your IF logic - ---- - -## Part 4: Maintenance - -### Token Refresh - -When the workflow fails with authentication errors: - -1. Repeat Part 1 to extract new tokens -2. Update Node 2, 3, and 4 headers -3. Re-test the workflow - -**Recommendation**: Document the refresh process and set a reminder to check weekly - -### Adjusting the Limit - -Monitor your community growth: -- If you're missing new members: Increase the limit -- If you're wasting operations: Decrease the limit -- Formula: `Limit = (Expected joins per hour × Hours between triggers) × 1.5` - -### Scaling Considerations - -As your community grows: -- Consider increasing schedule frequency (e.g., every 1 hour) -- Adjust limit accordingly -- Monitor n8n execution costs (if using cloud) - ---- - -## Troubleshooting - -### Issue: "Authentication Failed" -**Solution**: Re-extract cookies and tokens from browser - -### Issue: "No fileId returned" -**Solution**: Check the request payload matches Skool's current format - -### Issue: "CSV file empty" -**Solution**: Verify query parameters and download URL format - -### Issue: "Subscribers added multiple times" -**Solution**: Check IF node logic - should skip if subscriber exists - -### Issue: "Missing recent members" -**Solution**: Increase the Limit node value - ---- - -## Security Considerations - -1. **Never share your cookies or tokens** - they provide full access to your Skool account -2. Store tokens securely in n8n credentials (not in node configuration) -3. Use environment variables for sensitive data -4. Regularly rotate tokens by re-extracting from browser -5. Monitor for unauthorized access to your email platform - ---- - -## Next Steps - -- Customize email welcome sequence in your email platform -- Set up tags for segmentation (e.g., "Skool Members", "Welcome Sequence Completed") -- Create broadcast campaigns targeting specific tags -- Consider adding additional automations (e.g., member activity tracking) - ---- - -## Resources - -- n8n Documentation: https://docs.n8n.io -- Skool Community: https://www.skool.com -- Original Tutorial: https://www.youtube.com/watch?v=vZaYYzb4y5Y - -## Support - -If you need help setting this up, you can: -- Hire the original tutorial creator (link in video description) -- Post in n8n community forums -- Consult with an n8n automation specialist diff --git a/n8n-skool/ai-termimal-skool-n8n-setup.md b/n8n-skool/ai-termimal-skool-n8n-setup.md deleted file mode 100644 index 0060162..0000000 --- a/n8n-skool/ai-termimal-skool-n8n-setup.md +++ /dev/null @@ -1,122 +0,0 @@ -# Skool + n8n Integration Setup Guide - -**Purpose**: Automatically sync new Skool community members to your email list -**Method**: Unofficial API method (educational purposes only) -**VPS**: ai-termimal -**Created**: 2025-11-29 - -## Overview - -This integration watches for new members in your Skool community and automatically adds them to your email marketing platform. Since Skool doesn't provide an official API, this uses HTTP requests to mimic the member export functionality. - -**Important Disclaimers:** -- This is an **unofficial method** and may stop working if Skool changes their system -- Use for **educational purposes only** -- This method requires extracting authentication tokens from your browser - -## How It Works - -1. **Schedule Trigger**: Runs every 2 hours (configurable) -2. **Export Member List**: Makes HTTP request to export members as CSV -3. **Get Download URL**: Extracts the file download link -4. **Download CSV**: Retrieves the member list file -5. **Parse CSV**: Extracts member data -6. **Limit Results**: Takes only the top N members (based on expected new joins) -7. **Check & Add**: Loops through members and adds new ones to your email list - -## Architecture - -``` -Schedule (2hrs) → Export Request → Get File URL → Download CSV → Parse Data - ↓ -Email Platform ← Add New Member ← Check if Exists ← Limit Top N ← Extract -``` - -## Prerequisites - -- n8n instance running (cloud or self-hosted) -- Skool community with admin access -- Email marketing platform account (ConvertKit, Mailchimp, etc.) -- Chrome/Firefox browser for extracting authentication tokens - -## Key Components - -### 1. Schedule Trigger -- **Interval**: 2 hours (adjust based on your needs) -- **Logic**: More frequent = lower limit needed, less frequent = higher limit - -### 2. Authentication Requirements - -You'll need to extract these from your browser: - -- **Cookie** (from request headers) -- **X-AWS-WAF-Token** (from request headers) -- **User-Agent** (from request headers) -- **URL parameters** (expires, signature, key-pair-id) - -### 3. HTTP Nodes Configuration - -**Node 1 - Export Request:** -- Method: POST -- URL: `https://api.school.com/request-bulk-action` -- Query Parameters: - - `type`: `bulk-export-csv` - - `all-members-selected`: `true` - - `members-status`: `active` - -**Node 2 - Get Download URL:** -- Method: GET -- URL: `https://api.school.com/files/{fileId}/download-url` - -**Node 3 - Download File:** -- Method: GET -- URL: From previous step's data field -- Query Parameters: expires, signature, key-pair-id - -### 4. Member Limit Calculation - -**Critical Logic:** -- If automation runs every 2 hours and you expect max 15 new members per 2 hours → Set limit to 15 -- If automation runs every 6 hours and you expect max 50 new members per 6 hours → Set limit to 50 -- This prevents checking all members (which could be thousands) every time - -### 5. Email Integration - -The workflow checks if each member exists in your email platform: -- **If exists**: Skip (continue to next member) -- **If new**: Add to email list and tag appropriately - -## Rate Limiting Considerations - -- **n8n pricing advantage**: Much cheaper than Zapier for high-volume operations -- **Execution frequency**: Balance between timeliness and resource usage -- **Member limit**: Prevents unnecessary API calls to email platform - -## Next Steps - -See `ai-termimal-skool-n8n-detailed-setup.md` for step-by-step implementation instructions. - -## Troubleshooting - -### Common Issues - -1. **Authentication Fails**: Tokens expire, need to re-extract from browser -2. **No Members Found**: Check limit value and sort order in CSV -3. **Duplicate Members**: Adjust schedule frequency or limit value -4. **CSV Download Fails**: Re-extract AWS WAF token and cookies - -### Token Expiration - -- Cookies and tokens expire periodically -- You'll need to re-extract them when the workflow fails -- Consider monitoring workflow for failures - -## Related Files - -- `ai-termimal-skool-n8n-detailed-setup.md` - Step-by-step setup instructions -- `ai-termimal-skool-workflow-template.json` - n8n workflow template -- `ai-termimal-skool-config-reference.md` - Configuration parameter reference - -## Credits - -Based on tutorial by Sant Kala: https://www.youtube.com/watch?v=vZaYYzb4y5Y diff --git a/n8n-skool/ai-termimal-skool-workflow-template.json b/n8n-skool/ai-termimal-skool-workflow-template.json deleted file mode 100644 index 5a12b86..0000000 --- a/n8n-skool/ai-termimal-skool-workflow-template.json +++ /dev/null @@ -1,379 +0,0 @@ -{ - "name": "Skool to Email List Sync", - "nodes": [ - { - "parameters": { - "rule": { - "interval": [ - { - "field": "hours", - "hoursInterval": 2 - } - ] - } - }, - "name": "Schedule Trigger", - "type": "n8n-nodes-base.scheduleTrigger", - "typeVersion": 1, - "position": [250, 300] - }, - { - "parameters": { - "method": "POST", - "url": "https://api.school.com/api/request-bulk-action", - "sendQuery": true, - "queryParameters": { - "parameters": [ - { - "name": "type", - "value": "bulk-export-csv" - }, - { - "name": "all-members-selected", - "value": "true" - }, - { - "name": "members-status", - "value": "active" - } - ] - }, - "sendHeaders": true, - "headerParameters": { - "parameters": [ - { - "name": "accept", - "value": "*/*" - }, - { - "name": "accept-encoding", - "value": "gzip, deflate, br" - }, - { - "name": "accept-language", - "value": "en-US,en;q=0.9" - }, - { - "name": "cache-control", - "value": "no-cache" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "Cookie", - "value": "YOUR_COOKIE_HERE" - }, - { - "name": "origin", - "value": "https://www.school.com" - }, - { - "name": "referer", - "value": "https://www.school.com" - }, - { - "name": "user-agent", - "value": "YOUR_USER_AGENT_HERE" - }, - { - "name": "x-aws-waf-token", - "value": "YOUR_AWS_WAF_TOKEN_HERE" - }, - { - "name": "cookie", - "value": "YOUR_COOKIE_HERE" - } - ] - }, - "sendBody": true, - "bodyParameters": { - "parameters": [] - }, - "jsonParameters": true, - "body": "{\"action\":\"bulk-export\",\"filters\":{}}" - }, - "name": "Export Members Request", - "type": "n8n-nodes-base.httpRequest", - "typeVersion": 1, - "position": [450, 300], - "notes": "Requests CSV export of all members" - }, - { - "parameters": { - "method": "GET", - "url": "=https://api.school.com/api/files/{{ $json.fileId }}/download-url", - "sendHeaders": true, - "headerParameters": { - "parameters": [ - { - "name": "accept", - "value": "*/*" - }, - { - "name": "Cookie", - "value": "YOUR_COOKIE_HERE" - }, - { - "name": "user-agent", - "value": "YOUR_USER_AGENT_HERE" - }, - { - "name": "x-aws-waf-token", - "value": "YOUR_AWS_WAF_TOKEN_HERE" - }, - { - "name": "cookie", - "value": "YOUR_COOKIE_HERE" - } - ] - } - }, - "name": "Get Download URL", - "type": "n8n-nodes-base.httpRequest", - "typeVersion": 1, - "position": [650, 300], - "notes": "Retrieves the download URL for the CSV file" - }, - { - "parameters": { - "method": "GET", - "url": "={{ $json.data }}", - "sendQuery": true, - "queryParameters": { - "parameters": [ - { - "name": "Expires", - "value": "YOUR_EXPIRES_VALUE" - }, - { - "name": "Signature", - "value": "YOUR_SIGNATURE_VALUE" - }, - { - "name": "Key-Pair-Id", - "value": "YOUR_KEY_PAIR_ID" - } - ] - }, - "sendHeaders": true, - "headerParameters": { - "parameters": [ - { - "name": "Cookie", - "value": "YOUR_COOKIE_HERE" - }, - { - "name": "user-agent", - "value": "YOUR_USER_AGENT_HERE" - } - ] - }, - "options": {} - }, - "name": "Download CSV", - "type": "n8n-nodes-base.httpRequest", - "typeVersion": 1, - "position": [850, 300], - "notes": "Downloads the actual CSV file" - }, - { - "parameters": { - "binaryPropertyName": "data", - "fileFormat": "csv", - "options": {} - }, - "name": "Extract CSV Data", - "type": "n8n-nodes-base.extractFromFile", - "typeVersion": 1, - "position": [1050, 300], - "notes": "Parses CSV into JSON objects" - }, - { - "parameters": { - "maxItems": 15, - "keep": "firstItems" - }, - "name": "Limit to Recent Members", - "type": "n8n-nodes-base.limit", - "typeVersion": 1, - "position": [1250, 300], - "notes": "Only check the most recent 15 members (adjust based on your needs)" - }, - { - "parameters": {}, - "name": "Loop Over Members", - "type": "n8n-nodes-base.splitInBatches", - "typeVersion": 1, - "position": [1450, 300], - "notes": "Process each member one by one" - }, - { - "parameters": { - "conditions": { - "boolean": [], - "number": [], - "string": [ - { - "value1": "={{ $json.email }}", - "operation": "isNotEmpty" - } - ] - } - }, - "name": "Check if Member Has Email", - "type": "n8n-nodes-base.if", - "typeVersion": 1, - "position": [1650, 300], - "notes": "Basic validation - customize based on your email platform API" - }, - { - "parameters": { - "mode": "passThrough", - "options": {} - }, - "name": "Add to Email List", - "type": "n8n-nodes-base.noOp", - "typeVersion": 1, - "position": [1850, 200], - "notes": "REPLACE THIS: Add your email platform node here (ConvertKit, Mailchimp, etc.)" - }, - { - "parameters": { - "mode": "passThrough", - "options": {} - }, - "name": "Skip - Already Exists", - "type": "n8n-nodes-base.noOp", - "typeVersion": 1, - "position": [1850, 400], - "notes": "Member already in system, skip to next" - } - ], - "connections": { - "Schedule Trigger": { - "main": [ - [ - { - "node": "Export Members Request", - "type": "main", - "index": 0 - } - ] - ] - }, - "Export Members Request": { - "main": [ - [ - { - "node": "Get Download URL", - "type": "main", - "index": 0 - } - ] - ] - }, - "Get Download URL": { - "main": [ - [ - { - "node": "Download CSV", - "type": "main", - "index": 0 - } - ] - ] - }, - "Download CSV": { - "main": [ - [ - { - "node": "Extract CSV Data", - "type": "main", - "index": 0 - } - ] - ] - }, - "Extract CSV Data": { - "main": [ - [ - { - "node": "Limit to Recent Members", - "type": "main", - "index": 0 - } - ] - ] - }, - "Limit to Recent Members": { - "main": [ - [ - { - "node": "Loop Over Members", - "type": "main", - "index": 0 - } - ] - ] - }, - "Loop Over Members": { - "main": [ - [ - { - "node": "Check if Member Has Email", - "type": "main", - "index": 0 - } - ] - ] - }, - "Check if Member Has Email": { - "main": [ - [ - { - "node": "Add to Email List", - "type": "main", - "index": 0 - } - ], - [ - { - "node": "Skip - Already Exists", - "type": "main", - "index": 0 - } - ] - ] - }, - "Add to Email List": { - "main": [ - [ - { - "node": "Loop Over Members", - "type": "main", - "index": 0 - } - ] - ] - }, - "Skip - Already Exists": { - "main": [ - [ - { - "node": "Loop Over Members", - "type": "main", - "index": 0 - } - ] - ] - } - }, - "settings": {}, - "staticData": null, - "tags": [], - "meta": { - "instanceId": "skool-sync-template" - } -}