Add 5 n8n CRM automation workflows
- 01: Contact intake webhook → Twenty CRM - 02: Lead nurturing 3-email sequence via Resend - 03: Daily CRM → Listmonk newsletter sync - 04: Weekly stale contact follow-up reminders - 05: Gitea/GitHub webhook events → CRM activity log Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
acd874924f
commit
5b87103fdb
|
|
@ -0,0 +1,207 @@
|
|||
{
|
||||
"name": "Contact Intake — Form to CRM",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"httpMethod": "POST",
|
||||
"path": "contact-intake",
|
||||
"responseMode": "responseNode",
|
||||
"options": {}
|
||||
},
|
||||
"id": "webhook-trigger",
|
||||
"name": "Webhook — Contact Form",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [240, 300],
|
||||
"webhookId": "contact-intake"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "check-email",
|
||||
"leftValue": "={{ $json.body.email }}",
|
||||
"rightValue": "",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "isNotEmpty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "check-name",
|
||||
"leftValue": "={{ $json.body.name }}",
|
||||
"rightValue": "",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "isNotEmpty"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "validate-input",
|
||||
"name": "Validate Input",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [460, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "=https://crm.cosmolocal.world/api/v1/objects/people",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"name\": {\n \"firstName\": \"{{ $json.body.name.split(' ')[0] }}\",\n \"lastName\": \"{{ $json.body.name.split(' ').slice(1).join(' ') || '' }}\"\n },\n \"emails\": {\n \"primaryEmail\": \"{{ $json.body.email }}\"\n },\n \"phones\": {\n \"primaryPhone\": \"{{ $json.body.phone || '' }}\"\n }\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "create-crm-contact",
|
||||
"name": "Create Contact in Twenty CRM",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [680, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "=https://crm.cosmolocal.world/api/v1/objects/notes",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"title\": \"Contact Form Submission\",\n \"body\": \"{{ $('Webhook — Contact Form').item.json.body.message || 'No message provided' }}\",\n \"noteTargets\": [{\n \"personId\": \"{{ $json.data.id }}\"\n }]\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "add-note",
|
||||
"name": "Add Note to Contact",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [900, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"respondWith": "json",
|
||||
"responseBody": "={ \"success\": true, \"message\": \"Contact created successfully\" }",
|
||||
"options": {
|
||||
"responseCode": 200
|
||||
}
|
||||
},
|
||||
"id": "respond-success",
|
||||
"name": "Respond — Success",
|
||||
"type": "n8n-nodes-base.respondToWebhook",
|
||||
"typeVersion": 1.1,
|
||||
"position": [1120, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"respondWith": "json",
|
||||
"responseBody": "={ \"success\": false, \"message\": \"Missing required fields: name and email\" }",
|
||||
"options": {
|
||||
"responseCode": 400
|
||||
}
|
||||
},
|
||||
"id": "respond-error",
|
||||
"name": "Respond — Validation Error",
|
||||
"type": "n8n-nodes-base.respondToWebhook",
|
||||
"typeVersion": 1.1,
|
||||
"position": [680, 420]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Webhook — Contact Form": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Validate Input",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Validate Input": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Create Contact in Twenty CRM",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Respond — Validation Error",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Create Contact in Twenty CRM": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Add Note to Contact",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Add Note to Contact": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Respond — Success",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"staticData": null,
|
||||
"tags": [
|
||||
{
|
||||
"name": "cosmolocal"
|
||||
},
|
||||
{
|
||||
"name": "crm"
|
||||
}
|
||||
],
|
||||
"pinData": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
{
|
||||
"name": "Lead Nurturing — Welcome Email Sequence",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"httpMethod": "POST",
|
||||
"path": "new-contact-created",
|
||||
"options": {}
|
||||
},
|
||||
"id": "webhook-new-contact",
|
||||
"name": "Webhook — New Contact Created",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [240, 300],
|
||||
"webhookId": "new-contact-created"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "set-email",
|
||||
"name": "email",
|
||||
"value": "={{ $json.body.email || $json.body.emails?.primaryEmail }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "set-first-name",
|
||||
"name": "firstName",
|
||||
"value": "={{ $json.body.firstName || $json.body.name?.firstName || 'there' }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "set-contact-id",
|
||||
"name": "contactId",
|
||||
"value": "={{ $json.body.id || $json.body.contactId }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "extract-fields",
|
||||
"name": "Extract Contact Fields",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [460, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://api.resend.com/emails",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.RESEND_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"from\": \"Cosmolocal Foundation <***REDACTED_EMAIL***>\",\n \"to\": [\"{{ $json.email }}\"],\n \"subject\": \"Welcome to the Cosmolocal Foundation\",\n \"html\": \"<h2>Welcome, {{ $json.firstName }}!</h2><p>Thank you for connecting with the Cosmolocal Foundation. We're building a world where local communities thrive within regenerative economies, connected through global knowledge-sharing and commons-based collaboration.</p><p><strong>\\\"What is heavy should be local, and what is light should be global and shared.\\\"</strong></p><p>Here's what we're working on:</p><ul><li><strong>Decentralized Governance</strong> — Transparent, community-led decision-making</li><li><strong>Open Knowledge Commons</strong> — Sharing sustainable production methods globally</li><li><strong>Commons-Compatible Capital</strong> — Financing transformative local projects</li><li><strong>Cosmolocal Coordination</strong> — Connecting local efforts into a global network</li></ul><p>We'll be in touch with updates on our progress and opportunities to get involved.</p><p>Warm regards,<br/>The Cosmolocal Foundation Team</p><p style='color:#78716c;font-size:12px;'>cosmolocal.world</p>\"\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "send-welcome-email",
|
||||
"name": "Send Welcome Email (Day 0)",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [680, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"amount": 3,
|
||||
"unit": "days"
|
||||
},
|
||||
"id": "wait-3-days",
|
||||
"name": "Wait 3 Days",
|
||||
"type": "n8n-nodes-base.wait",
|
||||
"typeVersion": 1.1,
|
||||
"position": [900, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://api.resend.com/emails",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.RESEND_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"from\": \"Cosmolocal Foundation <***REDACTED_EMAIL***>\",\n \"to\": [\"{{ $('Extract Contact Fields').item.json.email }}\"],\n \"subject\": \"Our Strategic Priorities — How We're Building Change\",\n \"html\": \"<h2>Hi {{ $('Extract Contact Fields').item.json.firstName }},</h2><p>We wanted to share more about our strategic approach to systemic transformation.</p><p>The Cosmolocal Foundation is executing on eight key initiatives:</p><ol><li><strong>Mapping Regenerative Communities</strong> — Cataloging eco-villages, circular economy hubs, and governance initiatives worldwide</li><li><strong>Web3 Funding</strong> — Quadratic funding, DAOs, and Collaborative Finance for local projects</li><li><strong>Open Resources</strong> — A global knowledge commons of governance models and production blueprints</li><li><strong>Education & Advocacy</strong> — Engaging policymakers to scale cosmolocal principles</li><li><strong>Pilots & Grants</strong> — Funding projects that demonstrate scalable solutions</li><li><strong>Cosmolocal Certification</strong> — Blockchain-verified standards for cosmolocal initiatives</li><li><strong>Global Alliances</strong> — Bioregional collaboration on governance and mutual aid</li><li><strong>Impact Research</strong> — Evidence-based scaling through the Cosmolocal Research Institute</li></ol><p>Want to learn more or get involved? Reply to this email — we'd love to hear from you.</p><p>Best,<br/>The Cosmolocal Foundation Team</p>\"\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "send-followup-email",
|
||||
"name": "Send Follow-up Email (Day 3)",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1120, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"amount": 7,
|
||||
"unit": "days"
|
||||
},
|
||||
"id": "wait-7-days",
|
||||
"name": "Wait 7 Days",
|
||||
"type": "n8n-nodes-base.wait",
|
||||
"typeVersion": 1.1,
|
||||
"position": [1340, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://api.resend.com/emails",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.RESEND_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"from\": \"Cosmolocal Foundation <***REDACTED_EMAIL***>\",\n \"to\": [\"{{ $('Extract Contact Fields').item.json.email }}\"],\n \"subject\": \"Join the Movement — Ways to Participate\",\n \"html\": \"<h2>Hi {{ $('Extract Contact Fields').item.json.firstName }},</h2><p>We believe in the power of collaboration. Here are ways you can participate in the cosmolocal movement:</p><ul><li><strong>Subscribe to our newsletter</strong> — Stay updated on projects, pilots, and governance experiments</li><li><strong>Join a working group</strong> — Contribute your expertise to research, technology, or community building</li><li><strong>Support a pilot project</strong> — Help fund or participate in cosmolocal demonstrations</li><li><strong>Spread the word</strong> — Share our vision with your network</li></ul><p>Visit <a href='https://cosmolocal.world'>cosmolocal.world</a> to explore our work, or simply reply to this email to start a conversation.</p><p>Together we can build regenerative economies that serve communities and the planet.</p><p>In solidarity,<br/>The Cosmolocal Foundation Team</p>\"\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "send-engagement-email",
|
||||
"name": "Send Engagement Email (Day 10)",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1560, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "PATCH",
|
||||
"url": "=https://crm.cosmolocal.world/api/v1/objects/people/{{ $('Extract Contact Fields').item.json.contactId }}",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"stage\": \"NURTURE_COMPLETE\"\n}",
|
||||
"options": {
|
||||
"ignore_ssl_issues": false
|
||||
}
|
||||
},
|
||||
"id": "update-crm-stage",
|
||||
"name": "Update CRM — Nurture Complete",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1780, 300]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Webhook — New Contact Created": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Extract Contact Fields",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Extract Contact Fields": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send Welcome Email (Day 0)",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Send Welcome Email (Day 0)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Wait 3 Days",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Wait 3 Days": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send Follow-up Email (Day 3)",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Send Follow-up Email (Day 3)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Wait 7 Days",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Wait 7 Days": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send Engagement Email (Day 10)",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Send Engagement Email (Day 10)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Update CRM — Nurture Complete",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"staticData": null,
|
||||
"tags": [
|
||||
{
|
||||
"name": "cosmolocal"
|
||||
},
|
||||
{
|
||||
"name": "email"
|
||||
}
|
||||
],
|
||||
"pinData": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
{
|
||||
"name": "Newsletter Sync — CRM to Listmonk",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"rule": {
|
||||
"interval": [
|
||||
{
|
||||
"triggerAtHour": 6,
|
||||
"triggerAtMinute": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "schedule-trigger",
|
||||
"name": "Daily Sync (6 AM)",
|
||||
"type": "n8n-nodes-base.scheduleTrigger",
|
||||
"typeVersion": 1.2,
|
||||
"position": [240, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "GET",
|
||||
"url": "https://crm.cosmolocal.world/api/v1/objects/people",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendQuery": true,
|
||||
"queryParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "limit",
|
||||
"value": "100"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "fetch-crm-contacts",
|
||||
"name": "Fetch CRM Contacts",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [460, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"fieldToSplitOut": "data.people",
|
||||
"options": {}
|
||||
},
|
||||
"id": "split-contacts",
|
||||
"name": "Split Into Items",
|
||||
"type": "n8n-nodes-base.splitOut",
|
||||
"typeVersion": 1,
|
||||
"position": [680, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "has-email",
|
||||
"leftValue": "={{ $json.emails?.primaryEmail }}",
|
||||
"rightValue": "",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "isNotEmpty"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "filter-with-email",
|
||||
"name": "Filter — Has Email",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [900, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "GET",
|
||||
"url": "=http://listmonk-cosmolocal:9000/api/subscribers",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Basic {{ Buffer.from('admin:***REDACTED_LISTMONK_PASS***').toString('base64') }}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendQuery": true,
|
||||
"queryParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "query",
|
||||
"value": "=subscribers.email = '{{ $json.emails.primaryEmail }}'"
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"name": "per_page",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "check-listmonk-exists",
|
||||
"name": "Check If Subscriber Exists",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1120, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "not-exists",
|
||||
"leftValue": "={{ $json.data?.total }}",
|
||||
"rightValue": 0,
|
||||
"operator": {
|
||||
"type": "number",
|
||||
"operation": "equals"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "if-new-subscriber",
|
||||
"name": "If New Subscriber",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [1340, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "http://listmonk-cosmolocal:9000/api/subscribers",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Basic {{ Buffer.from('admin:***REDACTED_LISTMONK_PASS***').toString('base64') }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"email\": \"{{ $('Filter — Has Email').item.json.emails.primaryEmail }}\",\n \"name\": \"{{ $('Filter — Has Email').item.json.name?.firstName || '' }} {{ $('Filter — Has Email').item.json.name?.lastName || '' }}\",\n \"status\": \"enabled\",\n \"lists\": [1],\n \"preconfirm_subscriptions\": true,\n \"attribs\": {\n \"source\": \"twenty-crm-sync\",\n \"crm_id\": \"{{ $('Filter — Has Email').item.json.id }}\"\n }\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "create-subscriber",
|
||||
"name": "Create Listmonk Subscriber",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1560, 180]
|
||||
},
|
||||
{
|
||||
"parameters": {},
|
||||
"id": "no-op-exists",
|
||||
"name": "Already Subscribed — Skip",
|
||||
"type": "n8n-nodes-base.noOp",
|
||||
"typeVersion": 1,
|
||||
"position": [1560, 360]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Daily Sync (6 AM)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Fetch CRM Contacts",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Fetch CRM Contacts": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Split Into Items",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Split Into Items": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Filter — Has Email",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Filter — Has Email": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Check If Subscriber Exists",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[]
|
||||
]
|
||||
},
|
||||
"Check If Subscriber Exists": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "If New Subscriber",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"If New Subscriber": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Create Listmonk Subscriber",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Already Subscribed — Skip",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"staticData": null,
|
||||
"tags": [
|
||||
{
|
||||
"name": "cosmolocal"
|
||||
},
|
||||
{
|
||||
"name": "newsletter"
|
||||
}
|
||||
],
|
||||
"pinData": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
{
|
||||
"name": "Follow-up Reminders — Stale Contacts",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"rule": {
|
||||
"interval": [
|
||||
{
|
||||
"triggerAtHour": 9,
|
||||
"triggerAtMinute": 0,
|
||||
"triggerAtDay": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "weekly-schedule",
|
||||
"name": "Weekly Check (Monday 9 AM)",
|
||||
"type": "n8n-nodes-base.scheduleTrigger",
|
||||
"typeVersion": 1.2,
|
||||
"position": [240, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "GET",
|
||||
"url": "https://crm.cosmolocal.world/api/v1/objects/people",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendQuery": true,
|
||||
"queryParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "limit",
|
||||
"value": "100"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "fetch-all-contacts",
|
||||
"name": "Fetch All Contacts",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [460, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"fieldToSplitOut": "data.people",
|
||||
"options": {}
|
||||
},
|
||||
"id": "split-contacts",
|
||||
"name": "Split Into Items",
|
||||
"type": "n8n-nodes-base.splitOut",
|
||||
"typeVersion": 1,
|
||||
"position": [680, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const items = $input.all();\nconst staleItems = [];\nconst now = new Date();\nconst STALE_DAYS = 14;\n\nfor (const item of items) {\n const updatedAt = new Date(item.json.updatedAt);\n const daysSinceUpdate = Math.floor((now - updatedAt) / (1000 * 60 * 60 * 24));\n \n if (daysSinceUpdate >= STALE_DAYS) {\n staleItems.push({\n json: {\n ...item.json,\n daysSinceUpdate,\n email: item.json.emails?.primaryEmail || 'N/A',\n fullName: `${item.json.name?.firstName || ''} ${item.json.name?.lastName || ''}`.trim() || 'Unknown'\n }\n });\n }\n}\n\nreturn staleItems.length > 0 ? staleItems : [{ json: { noStaleContacts: true } }];"
|
||||
},
|
||||
"id": "filter-stale",
|
||||
"name": "Filter Stale Contacts (14+ days)",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [900, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "has-stale",
|
||||
"leftValue": "={{ $json.noStaleContacts }}",
|
||||
"rightValue": true,
|
||||
"operator": {
|
||||
"type": "boolean",
|
||||
"operation": "notTrue"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "if-has-stale",
|
||||
"name": "Any Stale Contacts?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [1120, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const items = $input.all();\nconst contactList = items.map(item => \n `- **${item.json.fullName}** (${item.json.email}) — ${item.json.daysSinceUpdate} days since last update`\n).join('\\n');\n\nconst count = items.length;\n\nreturn [{\n json: {\n subject: `[Cosmolocal CRM] ${count} contact${count !== 1 ? 's' : ''} need${count === 1 ? 's' : ''} follow-up`,\n htmlBody: `<h2>Stale Contact Report</h2><p>The following ${count} contact${count !== 1 ? 's have' : ' has'} not been updated in 14+ days:</p><table style=\"border-collapse:collapse;width:100%\"><tr style=\"background:#f5f5f4\"><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Name</th><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Email</th><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Days Stale</th></tr>${items.map(i => `<tr><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.fullName}</td><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.email}</td><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.daysSinceUpdate}</td></tr>`).join('')}</table><p style=\"margin-top:16px\"><a href=\"https://crm.cosmolocal.world\">Open CRM</a> to follow up.</p><p style=\"color:#78716c;font-size:12px\">Automated by n8n — automate.cosmolocal.world</p>`,\n count\n }\n}];"
|
||||
},
|
||||
"id": "build-report",
|
||||
"name": "Build Report Email",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [1340, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://api.resend.com/emails",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.RESEND_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"from\": \"CRM Bot <automate@cosmolocal.world>\",\n \"to\": [\"***REDACTED_EMAIL***\"],\n \"subject\": \"{{ $json.subject }}\",\n \"html\": \"{{ $json.htmlBody }}\"\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "send-reminder-email",
|
||||
"name": "Send Reminder to Team",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1560, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {},
|
||||
"id": "no-stale-contacts",
|
||||
"name": "No Stale Contacts — Done",
|
||||
"type": "n8n-nodes-base.noOp",
|
||||
"typeVersion": 1,
|
||||
"position": [1340, 420]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Weekly Check (Monday 9 AM)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Fetch All Contacts",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Fetch All Contacts": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Split Into Items",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Split Into Items": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Filter Stale Contacts (14+ days)",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Filter Stale Contacts (14+ days)": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Any Stale Contacts?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Any Stale Contacts?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Build Report Email",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "No Stale Contacts — Done",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Build Report Email": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send Reminder to Team",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"staticData": null,
|
||||
"tags": [
|
||||
{
|
||||
"name": "cosmolocal"
|
||||
},
|
||||
{
|
||||
"name": "crm"
|
||||
}
|
||||
],
|
||||
"pinData": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,347 @@
|
|||
{
|
||||
"name": "Webhook Events — Gitea/GitHub to CRM",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"httpMethod": "POST",
|
||||
"path": "git-events",
|
||||
"options": {}
|
||||
},
|
||||
"id": "webhook-git",
|
||||
"name": "Webhook — Git Events",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [240, 300],
|
||||
"webhookId": "git-events"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const body = $input.first().json.body;\nconst headers = $input.first().json.headers;\n\n// Detect source (Gitea vs GitHub)\nconst isGitea = headers['x-gitea-event'] !== undefined;\nconst isGitHub = headers['x-github-event'] !== undefined;\n\nconst eventType = isGitea \n ? headers['x-gitea-event'] \n : headers['x-github-event'] || 'unknown';\n\nlet result = {\n source: isGitea ? 'gitea' : isGitHub ? 'github' : 'unknown',\n eventType,\n repo: body.repository?.full_name || body.repository?.name || 'unknown',\n action: body.action || 'push',\n sender: body.sender?.login || body.pusher?.name || 'unknown',\n senderEmail: body.sender?.email || body.pusher?.email || '',\n url: '',\n title: '',\n description: ''\n};\n\nswitch (eventType) {\n case 'push':\n const commits = body.commits || [];\n result.title = `Push: ${commits.length} commit(s) to ${result.repo}`;\n result.description = commits.map(c => `- ${c.message}`).join('\\n');\n result.url = body.compare_url || body.compare || '';\n break;\n case 'issues':\n result.title = `Issue ${body.action}: ${body.issue?.title}`;\n result.description = body.issue?.body || '';\n result.url = body.issue?.html_url || '';\n break;\n case 'pull_request':\n result.title = `PR ${body.action}: ${body.pull_request?.title}`;\n result.description = body.pull_request?.body || '';\n result.url = body.pull_request?.html_url || '';\n break;\n case 'create':\n result.title = `Created ${body.ref_type}: ${body.ref}`;\n result.description = `New ${body.ref_type} created in ${result.repo}`;\n break;\n case 'star':\n case 'watch':\n result.title = `${result.sender} starred ${result.repo}`;\n result.description = `Repository now has ${body.repository?.stars_count || body.repository?.stargazers_count || '?'} stars`;\n break;\n default:\n result.title = `${eventType} event on ${result.repo}`;\n result.description = JSON.stringify(body).substring(0, 500);\n}\n\nreturn [{ json: result }];"
|
||||
},
|
||||
"id": "parse-event",
|
||||
"name": "Parse Git Event",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [460, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "is-significant",
|
||||
"leftValue": "={{ $json.eventType }}",
|
||||
"rightValue": "push,issues,pull_request,star",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "contains"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "filter-significant",
|
||||
"name": "Filter Significant Events",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [680, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://crm.cosmolocal.world/api/v1/objects/notes",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"title\": \"[{{ $json.source }}] {{ $json.title }}\",\n \"body\": \"**Event**: {{ $json.eventType }}\\n**Repo**: {{ $json.repo }}\\n**By**: {{ $json.sender }}\\n\\n{{ $json.description }}\\n\\n{{ $json.url ? '[View on ' + $json.source + '](' + $json.url + ')' : '' }}\"\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "log-to-crm",
|
||||
"name": "Log Activity to CRM",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [900, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "has-email",
|
||||
"leftValue": "={{ $('Parse Git Event').item.json.senderEmail }}",
|
||||
"rightValue": "",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "isNotEmpty"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "has-sender-email",
|
||||
"name": "Sender Has Email?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [1120, 240]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "GET",
|
||||
"url": "https://crm.cosmolocal.world/api/v1/objects/people",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendQuery": true,
|
||||
"queryParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "filter",
|
||||
"value": "={\"emails\":{\"primaryEmail\":{\"eq\":\"{{ $('Parse Git Event').item.json.senderEmail }}\"}}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "find-contact",
|
||||
"name": "Find Contact by Email",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1340, 180]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "contact-found",
|
||||
"leftValue": "={{ $json.data?.people?.length }}",
|
||||
"rightValue": 0,
|
||||
"operator": {
|
||||
"type": "number",
|
||||
"operation": "gt"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "contact-exists",
|
||||
"name": "Contact Found?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [1560, 180]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "PATCH",
|
||||
"url": "=https://crm.cosmolocal.world/api/v1/objects/people/{{ $json.data.people[0].id }}",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"updatedAt\": \"{{ new Date().toISOString() }}\"\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "touch-contact",
|
||||
"name": "Touch Contact — Update Timestamp",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1780, 120]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://crm.cosmolocal.world/api/v1/objects/people",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "Bearer {{ $env.TWENTY_API_KEY }}"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"name\": {\n \"firstName\": \"{{ $('Parse Git Event').item.json.sender }}\",\n \"lastName\": \"\"\n },\n \"emails\": {\n \"primaryEmail\": \"{{ $('Parse Git Event').item.json.senderEmail }}\"\n }\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "create-contributor-contact",
|
||||
"name": "Create Contributor Contact",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1780, 280]
|
||||
},
|
||||
{
|
||||
"parameters": {},
|
||||
"id": "no-op-skip",
|
||||
"name": "Skip — Not Significant",
|
||||
"type": "n8n-nodes-base.noOp",
|
||||
"typeVersion": 1,
|
||||
"position": [900, 420]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Webhook — Git Events": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse Git Event",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse Git Event": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Filter Significant Events",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Filter Significant Events": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Log Activity to CRM",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Skip — Not Significant",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Log Activity to CRM": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Sender Has Email?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Sender Has Email?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Find Contact by Email",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[]
|
||||
]
|
||||
},
|
||||
"Find Contact by Email": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Contact Found?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Contact Found?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Touch Contact — Update Timestamp",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Create Contributor Contact",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"staticData": null,
|
||||
"tags": [
|
||||
{
|
||||
"name": "cosmolocal"
|
||||
},
|
||||
{
|
||||
"name": "git"
|
||||
},
|
||||
{
|
||||
"name": "crm"
|
||||
}
|
||||
],
|
||||
"pinData": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
# Cosmolocal n8n Workflows
|
||||
|
||||
Import these JSON files into [automate.cosmolocal.world](https://automate.cosmolocal.world) via **Settings > Import Workflow**.
|
||||
|
||||
## Setup Requirements
|
||||
|
||||
Before activating workflows, configure these environment variables in n8n (**Settings > Variables**):
|
||||
|
||||
| Variable | Description | Where to find |
|
||||
|----------|-------------|---------------|
|
||||
| `TWENTY_API_KEY` | Twenty CRM API key | crm.cosmolocal.world > Settings > API Keys |
|
||||
| `RESEND_API_KEY` | Resend email API key | `ssh netcup "cat ~/.resend_credentials"` |
|
||||
|
||||
The Listmonk credentials are hardcoded for internal Docker network access (no external exposure).
|
||||
|
||||
## Workflows
|
||||
|
||||
### 01 — Contact Intake (Form to CRM)
|
||||
**Trigger:** Webhook POST to `/webhook/contact-intake`
|
||||
**Flow:** Validate input > Create contact in Twenty CRM > Add note with message > Respond
|
||||
|
||||
Use this webhook URL in your website contact form:
|
||||
```
|
||||
https://automate.cosmolocal.world/webhook/contact-intake
|
||||
```
|
||||
|
||||
POST body:
|
||||
```json
|
||||
{
|
||||
"name": "Jane Doe",
|
||||
"email": "jane@example.com",
|
||||
"phone": "+1234567890",
|
||||
"message": "Interested in collaborating"
|
||||
}
|
||||
```
|
||||
|
||||
### 02 — Lead Nurturing (Welcome Email Sequence)
|
||||
**Trigger:** Webhook POST to `/webhook/new-contact-created`
|
||||
**Flow:** Day 0: Welcome email > Day 3: Strategic priorities > Day 10: Ways to participate > Update CRM stage
|
||||
|
||||
Chain this from workflow 01 or call it when a new contact is created in the CRM.
|
||||
|
||||
### 03 — Newsletter Sync (CRM to Listmonk)
|
||||
**Trigger:** Daily at 6:00 AM
|
||||
**Flow:** Fetch CRM contacts > Check if already in Listmonk > Create new subscribers
|
||||
|
||||
Syncs all CRM contacts with email addresses to Listmonk list #1. Adjust the list ID if needed.
|
||||
|
||||
### 04 — Follow-up Reminders (Stale Contacts)
|
||||
**Trigger:** Weekly on Monday at 9:00 AM
|
||||
**Flow:** Fetch contacts > Filter those not updated in 14+ days > Email report to team
|
||||
|
||||
Sends an HTML table report to `***REDACTED_EMAIL***` with stale contacts and a link to the CRM.
|
||||
|
||||
### 05 — Webhook Events (Git to CRM)
|
||||
**Trigger:** Webhook POST to `/webhook/git-events`
|
||||
**Flow:** Parse Gitea/GitHub event > Log as CRM note > Find or create contributor contact
|
||||
|
||||
Add this webhook URL to Gitea/GitHub repos:
|
||||
```
|
||||
https://automate.cosmolocal.world/webhook/git-events
|
||||
```
|
||||
|
||||
Supports: push, issues, pull_request, star/watch events. Auto-detects Gitea vs GitHub from headers.
|
||||
Loading…
Reference in New Issue