Freshdesk-Linear 브리지
이것은Content Creation, Multimodal AI분야의자동화 워크플로우로, 22개의 노드를 포함합니다.주로 If, Webhook, Function, HttpRequest 등의 노드를 사용하며. Freshdesk 与 Linear 之间의双向工单동기화,包含错误日志记录
- •HTTP Webhook 엔드포인트(n8n이 자동으로 생성)
- •대상 API의 인증 정보가 필요할 수 있음
사용된 노드 (22)
{
"name": "Freshdesk-Linear Bridge",
"tags": [],
"nodes": [
{
"id": "dee7aabb-d434-45f3-8a13-9f4f75c96895",
"name": "Webhook 트리거 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
1712
],
"parameters": {
"width": 322,
"height": 736,
"content": "## 🎣 Webhook Triggers & Data Entry\n\n*Entry points that initiate the synchronization workflow:*\n\n• **New Ticket Webhook** - Captures newly created Freshdesk tickets via POST endpoint\n• **Update Ticket Webhook** - Handles modifications to existing Freshdesk tickets\n\n*These webhooks serve as the primary triggers that start the Freshdesk-to-Linear synchronization process, automatically routing incoming ticket data to the field mapping stage.*"
},
"typeVersion": 1
},
{
"id": "3a2f18c2-4c61-440e-85ca-4957bd9d10ba",
"name": "데이터 변환 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
720,
1712
],
"parameters": {
"color": 2,
"width": 210,
"height": 736,
"content": "## 📄 Data Transformation & Field Mapping\n\n*Critical Data Processing (Field Mapping):\n• Freshdesk → Linear — Converts ticket data into Linear-ready format, including priority (Low/Medium/High/Urgent ↔ 4/3/2/1) and status (Open/Pending/Resolved/Closed ↔ todo/in_progress/done/canceled), with proper title/description formatting.*"
},
"typeVersion": 1
},
{
"id": "6f04cd1c-77e6-4e4b-89c3-a671be46f916",
"name": "API 운영 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
944,
1712
],
"parameters": {
"color": 3,
"width": 434,
"height": 734,
"content": "## 🎯 API Operations & External Integration\n\n*Direct communication with external platforms:*\n\n• **Create Linear Issue** - Makes GraphQL mutation calls to Linear API for issue creation\n• **Check Linear Creation Success** - Validates successful API response before proceeding\n• **Link Freshdesk with Linear ID** - Updates Freshdesk ticket with Linear issue reference for bidirectional linking\n\n*These nodes handle the core integration logic, ensuring reliable data exchange between platforms with proper authentication and error validation.*"
},
"typeVersion": 1
},
{
"id": "0daec925-562a-43d9-92d6-5501f3567460",
"name": "로깅 관리 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
1392,
1712
],
"parameters": {
"color": 5,
"width": 450,
"height": 736,
"content": "## 📊 Logging & Operation Management\n\n*Comprehensive monitoring and audit trail system:*\n\n• **Log Linear Creation Success** - Records successful operations with timestamps and IDs\n• **Log Linear Creation Error** - Captures detailed failure information for debugging\n\n*This logging system provides complete visibility into sync operations, enabling easy troubleshooting and maintaining audit trails for all ticket-to-issue creation processes.*"
},
"typeVersion": 1
},
{
"id": "90550747-96c5-4c2f-9db1-6f9b69e357ba",
"name": "🗺️ Freshdesk 필드를 Linear에 매핑",
"type": "n8n-nodes-base.function",
"position": [
768,
2176
],
"parameters": {
"functionCode": "// Map Freshdesk priority to Linear priority\nconst freshdeskPriority = items[0].json.priority;\nlet linearPriority = 0;\n\nswitch(freshdeskPriority) {\n case 1: // Low\n linearPriority = 4;\n break;\n case 2: // Medium\n linearPriority = 3;\n break;\n case 3: // High\n linearPriority = 2;\n break;\n case 4: // Urgent\n linearPriority = 1;\n break;\n default:\n linearPriority = 3;\n}\n\n// Map Freshdesk status to Linear state\nconst freshdeskStatus = items[0].json.status;\nlet linearStateId = 'todo'; // Default to todo state\n\nswitch(freshdeskStatus) {\n case 2: // Open\n linearStateId = 'todo';\n break;\n case 3: // Pending\n linearStateId = 'in_progress';\n break;\n case 4: // Resolved\n linearStateId = 'done';\n break;\n case 5: // Closed\n linearStateId = 'canceled';\n break;\n}\n\nreturn [{\n json: {\n ...items[0].json,\n linearPriority: linearPriority,\n linearStateId: linearStateId,\n linearTitle: items[0].json.subject || 'Freshdesk Ticket #' + items[0].json.id,\n linearDescription: items[0].json.description_text || items[0].json.description || 'No description provided'\n }\n}];"
},
"typeVersion": 1
},
{
"id": "3b240bad-52b3-4d2f-87de-62ed8594ce53",
"name": "🎯 Linear 이슈 생성",
"type": "n8n-nodes-base.httpRequest",
"position": [
992,
2176
],
"parameters": {
"url": "https://api.linear.app/graphql",
"options": {},
"sendBody": true,
"sendHeaders": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{}
]
},
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Authorization",
"value": "={{ $vars.LINEAR_API_KEY }}"
}
]
}
},
"typeVersion": 4
},
{
"id": "b1beacfa-51d9-45e1-8e30-14c63cd6d4a2",
"name": "✅ Linear 생성 성공 확인",
"type": "n8n-nodes-base.if",
"position": [
1216,
2176
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "success_condition",
"operator": {
"type": "boolean",
"operation": "equal"
},
"leftValue": "={{ $json.data.issueCreate.success }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "ee9c5ce0-8ed7-4042-8920-f2b1eeee78c3",
"name": "🔗 Freshdesk와 Linear ID 연결",
"type": "n8n-nodes-base.httpRequest",
"position": [
1440,
2080
],
"parameters": {
"url": "=https://{{ $vars.FRESHDESK_DOMAIN }}.freshdesk.com/api/v2/tickets/{{ $('🗺️ Map Freshdesk Fields to Linear').item.json.id }}",
"options": {},
"sendBody": true,
"sendHeaders": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{}
]
},
"genericAuthType": "httpBasicAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4
},
{
"id": "58b14ee7-9633-41c9-abf4-b1019a026681",
"name": "❌ Linear 생성 오류 로깅",
"type": "n8n-nodes-base.function",
"position": [
1440,
2272
],
"parameters": {
"functionCode": "// Log error details\nconst errorData = {\n timestamp: new Date().toISOString(),\n workflow: 'Sync Freshdesk and Linear tickets',\n error: 'Failed to create Linear issue',\n freshdeskTicketId: items[0].json.id,\n freshdeskTicketSubject: items[0].json.subject,\n linearResponse: items[0].json\n};\n\nconsole.error('Linear Issue Creation Failed:', JSON.stringify(errorData, null, 2));\n\nreturn [{\n json: {\n error: true,\n message: 'Failed to create Linear issue',\n details: errorData\n }\n}];"
},
"typeVersion": 1
},
{
"id": "70b0dac2-16bb-4a06-8d6a-d70ad95d7ced",
"name": "🎉 Linear 생성 성공 로깅",
"type": "n8n-nodes-base.function",
"position": [
1664,
2080
],
"parameters": {
"functionCode": "// Log successful creation\nconst successData = {\n timestamp: new Date().toISOString(),\n workflow: 'Sync Freshdesk and Linear tickets',\n message: 'Successfully created Linear issue and linked to Freshdesk ticket',\n freshdeskTicketId: items[0].json.id,\n linearIssueId: items[0].json.data?.issueCreate?.issue?.id,\n linearIssueKey: items[0].json.data?.issueCreate?.issue?.identifier,\n action: 'create_linear_from_freshdesk'\n};\n\nconsole.log('Creation Success:', JSON.stringify(successData, null, 2));\n\nreturn [{\n json: {\n success: true,\n message: 'Successfully created Linear issue from Freshdesk ticket',\n details: successData\n }\n}];"
},
"typeVersion": 1
},
{
"id": "48c2ca3f-857d-4e4a-9e02-ff3c3741dcfa",
"name": "🆕 새 티켓 Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
544,
2080
],
"parameters": {
"path": "create-ticket",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "f1a4c78a-9a5d-40cd-bb99-136b1b776b54",
"name": "📄 티켓 업데이트 Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
544,
2272
],
"parameters": {
"path": "update-ticket",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "6a1887df-1e4c-4eed-8349-d0671501e1e1",
"name": "Webhook 트리거 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
2480
],
"parameters": {
"width": 324,
"height": 760,
"content": "## 🎣 Webhook Trigger & Data Entry\n\n*Entry point for Linear-to-Freshdesk synchronization:*\n\n• **Linear Webhook - Issue Updated** - Receives webhook notifications when Linear issues are modified\n\n*This webhook serves as the reverse sync trigger, capturing Linear issue updates and initiating the process to sync changes back to corresponding Freshdesk tickets.*"
},
"typeVersion": 1
},
{
"id": "e7943820-74be-4bf5-b823-5b87829444fb",
"name": "로깅 오류 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
1392,
2480
],
"parameters": {
"color": 5,
"width": 452,
"height": 768,
"content": "## 📊 Logging & Error Management\n\n*Comprehensive monitoring for reverse sync operations:*\n\n• **Log Freshdesk Update Success** - Records successful ticket updates with timestamps and IDs\n• **Log Missing Ticket ID Error** - Captures cases where Linear issues lack Freshdesk ticket references\n\n*This logging system provides visibility into reverse sync operations, enabling troubleshooting of failed updates and maintaining audit trails for Linear-to-Freshdesk synchronization.*"
},
"typeVersion": 1
},
{
"id": "848d05ae-fb8a-473f-be86-4b4c922ba031",
"name": "🎣 Linear 이슈 업데이트됨 Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
560,
2912
],
"parameters": {
"path": "linear-issue-updated",
"options": {}
},
"typeVersion": 1
},
{
"id": "8fc267ea-44fd-43e3-84e1-26a104e7d36e",
"name": "📄 Linear를 Freshdesk 필드에 매핑",
"type": "n8n-nodes-base.function",
"position": [
784,
2912
],
"parameters": {
"functionCode": "// Map Linear state to Freshdesk status\nconst linearState = items[0].json.data.state.name.toLowerCase();\nlet freshdeskStatus = 2; // Default to Open\n\nswitch(linearState) {\n case 'todo':\n case 'backlog':\n freshdeskStatus = 2; // Open\n break;\n case 'in progress':\n case 'in_progress':\n freshdeskStatus = 3; // Pending\n break;\n case 'done':\n case 'completed':\n freshdeskStatus = 4; // Resolved\n break;\n case 'canceled':\n case 'cancelled':\n freshdeskStatus = 5; // Closed\n break;\n}\n\n// Map Linear priority to Freshdesk priority\nconst linearPriority = items[0].json.data.priority || 3;\nlet freshdeskPriority = 2; // Default to Medium\n\nswitch(linearPriority) {\n case 1: // Urgent\n freshdeskPriority = 4;\n break;\n case 2: // High\n freshdeskPriority = 3;\n break;\n case 3: // Medium\n freshdeskPriority = 2;\n break;\n case 4: // Low\n freshdeskPriority = 1;\n break;\n}\n\n// Extract Freshdesk ticket ID from Linear issue description\nconst description = items[0].json.data.description || '';\nconst ticketIdMatch = description.match(/Freshdesk Ticket ID: (\\d+)/);\nconst freshdeskTicketId = ticketIdMatch ? ticketIdMatch[1] : null;\n\nreturn [{\n json: {\n ...items[0].json,\n freshdeskStatus: freshdeskStatus,\n freshdeskPriority: freshdeskPriority,\n freshdeskTicketId: freshdeskTicketId,\n linearTitle: items[0].json.data.title,\n linearDescription: items[0].json.data.description\n }\n}];"
},
"typeVersion": 1
},
{
"id": "ba73505f-c43e-4cf1-919a-53d71226fa4c",
"name": "🔍 Freshdesk 티켓 ID 존재 여부 확인",
"type": "n8n-nodes-base.if",
"position": [
1008,
2912
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ticket_id_exists",
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.freshdeskTicketId }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "2461420b-58df-4266-8ba6-143842afc09c",
"name": "🎫 Freshdesk 티켓 업데이트",
"type": "n8n-nodes-base.httpRequest",
"position": [
1232,
2816
],
"parameters": {
"url": "=https://{{ $vars.FRESHDESK_DOMAIN }}.freshdesk.com/api/v2/tickets/{{ $json.freshdeskTicketId }}",
"options": {},
"sendBody": true,
"sendHeaders": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{}
]
},
"genericAuthType": "httpBasicAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4
},
{
"id": "7b907b6a-1968-4d4e-9eb2-d2458179c95e",
"name": "⚠️ 티켓 ID 누락 오류 로깅",
"type": "n8n-nodes-base.function",
"position": [
1456,
3088
],
"parameters": {
"functionCode": "// Log error details\nconst errorData = {\n timestamp: new Date().toISOString(),\n workflow: 'Sync Freshdesk and Linear tickets',\n error: 'No Freshdesk Ticket ID found in Linear issue',\n linearIssueId: items[0].json.data.id,\n linearIssueTitle: items[0].json.data.title,\n linearDescription: items[0].json.data.description\n};\n\nconsole.error('Missing Freshdesk Ticket ID:', JSON.stringify(errorData, null, 2));\n\nreturn [{\n json: {\n error: true,\n message: 'No Freshdesk Ticket ID found in Linear issue description',\n details: errorData\n }\n}];"
},
"typeVersion": 1
},
{
"id": "e8bc7b41-59b5-4e5e-945a-33d5f13880dc",
"name": "✅ Freshdesk 업데이트 성공 로깅",
"type": "n8n-nodes-base.function",
"position": [
1456,
2816
],
"parameters": {
"functionCode": "// Log successful sync\nconst successData = {\n timestamp: new Date().toISOString(),\n workflow: 'Sync Freshdesk and Linear tickets',\n message: 'Successfully synced Linear issue to Freshdesk ticket',\n freshdeskTicketId: items[0].json.freshdeskTicketId,\n linearIssueId: items[0].json.data?.id,\n action: 'update_freshdesk_from_linear'\n};\n\nconsole.log('Sync Success:', JSON.stringify(successData, null, 2));\n\nreturn [{\n json: {\n success: true,\n message: 'Successfully updated Freshdesk ticket from Linear issue',\n details: successData\n }\n}];"
},
"typeVersion": 1
},
{
"id": "bdbfdef4-f069-452e-ab92-649ce6763a27",
"name": "API 운영 노트1",
"type": "n8n-nodes-base.stickyNote",
"position": [
960,
2480
],
"parameters": {
"color": 3,
"width": 420,
"height": 768,
"content": "## 🎯 API Operations & Validation\n\n*External communication and data integrity checks:*\n\n• **Check if Freshdesk Ticket ID Exists** - Validates that Linear issue contains valid Freshdesk ticket reference\n• **Update Freshdesk Ticket** - Makes REST API calls to Freshdesk to update ticket with synced data\n\n*These nodes ensure reliable reverse sync by validating ticket linkage before attempting updates and handling the actual API communication with Freshdesk.*"
},
"typeVersion": 1
},
{
"id": "46662f60-8cda-4f1a-ab36-b30b0d2caa44",
"name": "스티키 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
720,
2480
],
"parameters": {
"color": 3,
"width": 224,
"height": 768,
"content": "## 📄 Data Transformation & Field Mapping\n\n*Critical data processing back to Freshdesk:\n• Map Linear → Freshdesk Fields — Converts Linear issue data into Freshdesk format, handling state mapping (todo/backlog→Open, in_progress→Pending, done→Resolved, canceled→Closed), priority conversion (1—4 ↔ 4—1), and restoring the original Freshdesk ticket ID from the description.*"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"connections": {
"48c2ca3f-857d-4e4a-9e02-ff3c3741dcfa": {
"main": [
[
{
"node": "90550747-96c5-4c2f-9db1-6f9b69e357ba",
"type": "main",
"index": 0
}
]
]
},
"3b240bad-52b3-4d2f-87de-62ed8594ce53": {
"main": [
[
{
"node": "b1beacfa-51d9-45e1-8e30-14c63cd6d4a2",
"type": "main",
"index": 0
}
]
]
},
"f1a4c78a-9a5d-40cd-bb99-136b1b776b54": {
"main": [
[
{
"node": "90550747-96c5-4c2f-9db1-6f9b69e357ba",
"type": "main",
"index": 0
}
]
]
},
"2461420b-58df-4266-8ba6-143842afc09c": {
"main": [
[
{
"node": "e8bc7b41-59b5-4e5e-945a-33d5f13880dc",
"type": "main",
"index": 0
}
]
]
},
"b1beacfa-51d9-45e1-8e30-14c63cd6d4a2": {
"main": [
[
{
"node": "ee9c5ce0-8ed7-4042-8920-f2b1eeee78c3",
"type": "main",
"index": 0
}
],
[
{
"node": "58b14ee7-9633-41c9-abf4-b1019a026681",
"type": "main",
"index": 0
}
]
]
},
"848d05ae-fb8a-473f-be86-4b4c922ba031": {
"main": [
[
{
"node": "8fc267ea-44fd-43e3-84e1-26a104e7d36e",
"type": "main",
"index": 0
}
]
]
},
"ee9c5ce0-8ed7-4042-8920-f2b1eeee78c3": {
"main": [
[
{
"node": "70b0dac2-16bb-4a06-8d6a-d70ad95d7ced",
"type": "main",
"index": 0
}
]
]
},
"8fc267ea-44fd-43e3-84e1-26a104e7d36e": {
"main": [
[
{
"node": "ba73505f-c43e-4cf1-919a-53d71226fa4c",
"type": "main",
"index": 0
}
]
]
},
"90550747-96c5-4c2f-9db1-6f9b69e357ba": {
"main": [
[
{
"node": "3b240bad-52b3-4d2f-87de-62ed8594ce53",
"type": "main",
"index": 0
}
]
]
},
"ba73505f-c43e-4cf1-919a-53d71226fa4c": {
"main": [
[
{
"node": "2461420b-58df-4266-8ba6-143842afc09c",
"type": "main",
"index": 0
}
],
[
{
"node": "7b907b6a-1968-4d4e-9eb2-d2458179c95e",
"type": "main",
"index": 0
}
]
]
}
}
}이 워크플로우를 어떻게 사용하나요?
위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
고급 - 콘텐츠 제작, 멀티모달 AI
유료인가요?
이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.
관련 워크플로우 추천
Avkash Kakdiya
@itechnotion🚀 Founder of iTechNotion — we build custom AI-powered automation workflows for startups, agencies, and founders. 💡 Specializing in agentic AI systems, content automation, sales funnels, and digital workers. 🔧 14+ years in tech | Building scalable no-code/low-code solutions using n8n, OpenAI, and other API-first tools. 📬 Let’s automate what slows you down.
이 워크플로우 공유