{
  "id": "zKRrIwXzcv7QvepA",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "OnBoarding Call Grading System",
  "tags": [
    {
      "id": "OYNCvrDxVQHw2gvR",
      "name": "Upwork",
      "createdAt": "2025-10-02T10:34:02.340Z",
      "updatedAt": "2025-10-02T10:34:02.340Z"
    }
  ],
  "nodes": [
    {
      "id": "a9579f80-9bec-473c-83c4-66b1134194ee",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -16,
        -176
      ],
      "parameters": {
        "path": "66273cf2-950f-42e5-a386-60d643868985",
        "options": {},
        "httpMethod": "POST",
        "responseData": "allEntries",
        "responseMode": "lastNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "d7377f6f-c1cc-47a9-8d1d-99dadd47fb2f",
      "name": "Append row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1280,
        -176
      ],
      "parameters": {
        "columns": {
          "value": {
            "Pain Points": "={{ $json.pain_points }}",
            "Overall Score %": "={{ $json.overall_score_percent }}",
            "What I Did Well": "={{ $json.what_i_did_well }}",
            "What to Improve": "={{ $json.what_to_improve }}",
            "Discovery (1\u20135)": "={{ $json.scores_discovery }}",
            "Feature requested": "={{ $json.feature_requested }}",
            "Overall Score [25]": "={{ $json.overall_score_25 }}",
            "Recording Share Url": "={{ $('Get a transcript').item.json.data.transcript_url }}",
            "Meeting Invitees Name": "={{ $('Get a transcript').item.json.data.sentences[15].speaker_name }}",
            "Meeting Invitees Email": "user@example.com",
            "Close/Next Steps (1\u20135)": "={{ $json.scores_close_next_steps }}",
            "Engagement/Rapport (1\u20135)": "={{ $json.scores_engagement_rapport }}",
            "Objection Handling (1\u20135)": "={{ $json.scores_objection_handling }}",
            "Onboarding Clarity (1\u20135)": "={{ $json.scores_onboarding_clarity }}",
            "Recording Duration In Minutes": "={{ $('Get a transcript').item.json.data.duration }}",
            "What CRM have you used in the past?": "={{ $json.crm_used_past }}"
          },
          "schema": [
            {
              "id": "Meeting Invitees Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Meeting Invitees Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Meeting Invitees Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Meeting Invitees Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Recording Share Url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Recording Share Url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Recording Duration In Minutes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Recording Duration In Minutes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "What CRM have you used in the past?",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "What CRM have you used in the past?",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Pain Points",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Pain Points",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Feature requested",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Feature requested",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "What I Did Well",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "What I Did Well",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "What to Improve",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "What to Improve",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Discovery (1\u20135)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Discovery (1\u20135)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Onboarding Clarity (1\u20135)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Onboarding Clarity (1\u20135)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Objection Handling (1\u20135)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Objection Handling (1\u20135)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Engagement/Rapport (1\u20135)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Engagement/Rapport (1\u20135)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Close/Next Steps (1\u20135)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Close/Next Steps (1\u20135)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Overall Score [25]",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Overall Score [25]",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Overall Score %",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Overall Score %",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "@dropdown",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "@dropdown",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "meeting_invitees_name",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "meeting_invitees_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "meeting_invitees_email",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "meeting_invitees_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "crm_used_past",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "crm_used_past",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "pain_points",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "pain_points",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "feature_requested",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "feature_requested",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "what_i_did_well",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "what_i_did_well",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "what_to_improve",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "what_to_improve",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "scores_discovery",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "scores_discovery",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "scores_onboarding_clarity",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "scores_onboarding_clarity",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "scores_objection_handling",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "scores_objection_handling",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "scores_engagement_rapport",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "scores_engagement_rapport",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "scores_close_next_steps",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "scores_close_next_steps",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "overall_score_25",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "overall_score_25",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "overall_score_percent",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "overall_score_percent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "notes",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TcWkY4KVQfl7n5n9UyjiV590GdzgbCOrLvfb8d6FreA/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1TcWkY4KVQfl7n5n9UyjiV590GdzgbCOrLvfb8d6FreA",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TcWkY4KVQfl7n5n9UyjiV590GdzgbCOrLvfb8d6FreA/edit?usp=drivesdk",
          "cachedResultName": "Kopie von REsimpli Onboarding Call - Fathom Call Score"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "072de8f9-05a4-4c32-a3a8-42726eefe3e3",
      "name": "Get a transcript",
      "type": "@firefliesai/n8n-nodes-fireflies.fireflies",
      "position": [
        208,
        -176
      ],
      "parameters": {
        "transcriptId": "={{ $json.body.meetingId }}"
      },
      "credentials": {
        "firefliesApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "57c6c8ee-a89d-4fd1-b7ae-e5fcb54ebb34",
      "name": "Message a model",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        688,
        -176
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o",
          "cachedResultName": "GPT-4O"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=Transcript (raw):\n{{ $json.Transcript }}\n\nTask:\n- Extract facts and evaluate according to System Prompt.\n- Reply exclusively in JSON format according to Assistant Prompt."
            },
            {
              "role": "assistant",
              "content": "={\n  \"meeting_invitees_name\": \"\",\n  \"meeting_invitees_email\": \"\",\n  \"crm_used_past\": \"\",\n  \"pain_points\": \"\",\n  \"feature_requested\": \"\",\n  \"what_i_did_well\": \"\",\n  \"what_to_improve\": \"\",\n  \"scores\": {\n    \"discovery\": 1,\n    \"onboarding_clarity\": 1,\n    \"objection_handling\": 1,\n    \"engagement_rapport\": 1,\n    \"close_next_steps\": 1\n  },\n  \"overall_score_25\": 0,\n  \"overall_score_percent\": 0,\n  \"notes\": \"\"\n}\n\n\nSpecific format requirements:\n- pain_points, feature_requested, what_i_did_well, what_to_improve are SEMICOLON-separated strings (not arrays).\n- Sort points alphabetically; deduplicate identical phrases.\n- Maximum 6 points per field; each phrase \u2264 12 words.\n- \"notes\" is optional, short (\u2264 50 words)."
            },
            {
              "role": "system",
              "content": "=You are a sober analyzer for sales transcripts of a CRM provider.\n\nRules:\n- Extract ONLY information from the transcript (no hallucinations).\n- If info is missing/unclear: use empty string \"\".\n- meeting_invitees_name = main contact (prospect), NOT additional participants.\n- Emails/names only if explicitly mentioned.\n- Scores are whole numbers 1\u20135 (estimate conservatively, never 0).\n- Calculate overall_score_25 = sum of the 5 scores.\n- Calculate overall_score_percent = round((overall_score_25/25)*100).\n- Output must be STRICT JSON according to the Assistant schema. No explanations/Markdown.\n\nFormat rules for text fields:\n- Always use ONE string (no arrays).\n- Multiple points must be SEMICOLON-separated, with a space after each semicolon.\n- No duplicate points, no leading/trailing semicolons, everything trimmed.\n- Order: alphabetically sorted (German sorting) for consistency.\n\n\u201cWhat to Improve\u201d \u2013 generation rules (must NOT be empty):\n- Derive improvements from (a) explicit criticism from the prospect, (b) visible gaps in discovery (goals, stakeholders, timeline, budget),\n  (c) unclear next steps, (d) weak objection handling, (e) missing proof of value.\n- Provide AT LEAST one, preferably 2\u20133 short, concrete points (semicolon-separated)."
            }
          ]
        }
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "2a5072fd-8895-41d6-b2bd-9c005b7d1b5d",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        1056,
        -176
      ],
      "parameters": {
        "jsCode": "// Hilfsfunktionen\nfunction getRawContent(item) {\n  const j = item.json || {};\n  return (\n    j?.message?.content ??\n    j?.data?.[0]?.message?.content ??\n    j?.choices?.[0]?.message?.content ??\n    j?.content ??\n    ''\n  );\n}\n\nfunction extractJson(raw) {\n  if (typeof raw !== 'string') return null;\n  // Entferne Markdown-Fences ```json ... ```\n  let cleaned = raw.replace(/```json/gi, '').replace(/```/g, '').trim();\n  const m = cleaned.match(/\\{[\\s\\S]*\\}/);\n  return m ? m[0] : null;\n}\n\nfunction clamp1to5(v) {\n  const n = Math.round(Number(v));\n  if (Number.isNaN(n)) return 1;\n  return Math.max(1, Math.min(5, n));\n}\n\nfunction ensureString(val) {\n  if (val === undefined || val === null) return \"\";\n  return String(val).trim();\n}\n\n// Starte mit dem ersten Item (typisch: 1 LLM-Response)\nconst raw = getRawContent(items[0]);\nconst jsonStr = extractJson(raw);\nif (!jsonStr) {\n  throw new Error('Kein JSON im LLM-Output gefunden.');\n}\n\nlet obj;\ntry {\n  obj = JSON.parse(jsonStr);\n} catch (e) {\n  throw new Error('JSON nicht parsebar: ' + e.message);\n}\n\n// Default-Werte einsetzen\nobj.meeting_invitees_name = ensureString(obj.meeting_invitees_name);\nobj.meeting_invitees_email = ensureString(obj.meeting_invitees_email);\nobj.crm_used_past = ensureString(obj.crm_used_past);\nobj.pain_points = ensureString(obj.pain_points);\nobj.feature_requested = ensureString(obj.feature_requested);\nobj.what_i_did_well = ensureString(obj.what_i_did_well);\nobj.what_to_improve = ensureString(obj.what_to_improve);\nobj.notes = ensureString(obj.notes);\n\n// Scores validieren\nconst s = obj.scores || {};\ns.discovery = clamp1to5(s.discovery);\ns.onboarding_clarity = clamp1to5(s.onboarding_clarity);\ns.objection_handling = clamp1to5(s.objection_handling);\ns.engagement_rapport = clamp1to5(s.engagement_rapport);\ns.close_next_steps = clamp1to5(s.close_next_steps);\nobj.scores = s;\n\n// Gesamtwerte neu berechnen\nconst overall = s.discovery + s.onboarding_clarity + s.objection_handling + s.engagement_rapport + s.close_next_steps;\nobj.overall_score_25 = overall;\nobj.overall_score_percent = Math.round((overall / 25) * 100);\n\n// Output flatten f\u00fcr Sheets/Airtable etc.\nconst out = {\n  meeting_invitees_name: obj.meeting_invitees_name,\n  meeting_invitees_email: obj.meeting_invitees_email,\n  crm_used_past: obj.crm_used_past,\n  pain_points: obj.pain_points,\n  feature_requested: obj.feature_requested,\n  what_i_did_well: obj.what_i_did_well,\n  what_to_improve: obj.what_to_improve,\n  scores_discovery: s.discovery,\n  scores_onboarding_clarity: s.onboarding_clarity,\n  scores_objection_handling: s.objection_handling,\n  scores_engagement_rapport: s.engagement_rapport,\n  scores_close_next_steps: s.close_next_steps,\n  overall_score_25: obj.overall_score_25,\n  overall_score_percent: obj.overall_score_percent,\n  notes: obj.notes\n};\n\nreturn [{ json: out }];"
      },
      "typeVersion": 2
    },
    {
      "id": "d15b7a46-5899-4cdb-b434-41da0b969f20",
      "name": "Code in JavaScript1",
      "type": "n8n-nodes-base.code",
      "position": [
        448,
        -176
      ],
      "parameters": {
        "jsCode": "// === Konfiguration ===\nconst GAP_BREAK_SECONDS = 15;     // Neuer Block, wenn zwischen S\u00e4tzen > 15s liegen\nconst INCLUDE_TIMESTAMPS = true;  // Zeitstempel am Block-Anfang zeigen (mm:ss)\nconst TIME_FORMAT = \"mm:ss\";      // mm:ss oder hh:mm:ss\n\n// === Hilfsfunktionen ===\nfunction toTimecode(sec) {\n  if (sec == null || isNaN(sec)) return \"\";\n  const s = Math.max(0, Math.floor(sec));\n  const h = Math.floor(s / 3600);\n  const m = Math.floor((s % 3600) / 60);\n  const ss = s % 60;\n  const pad = (n)=>String(n).padStart(2,\"0\");\n  if (TIME_FORMAT === \"hh:mm:ss\" || h > 0) return `${pad(h)}:${pad(m)}:${pad(ss)}`;\n  return `${pad(m)}:${pad(ss)}`;\n}\n\nfunction cleanText(t) {\n  // Bewahre Original-Satz, aber trimme Leerzeichen\n  return String(t ?? \"\").replace(/\\s+/g, \" \").trim();\n}\n\nfunction ensureEndPunctuation(t) {\n  // Wenn der Block nicht auf . ! ? endet, f\u00fcge einen Punkt hinzu\n  if (!t) return t;\n  return /[.!?\u2026]$/.test(t) ? t : t + \".\";\n}\n\n// === Input robust finden ===\nconst root = items[0]?.json || {};\nconst data = root.data || root;\nconst sentences = Array.isArray(data.sentences) ? data.sentences.slice() : [];\nconst speakersArr = Array.isArray(data.speakers) ? data.speakers : [];\n\n// Map Speaker-ID -> Name\nconst speakerMap = new Map();\nfor (const s of speakersArr) {\n  if (s && typeof s.id !== \"undefined\") {\n    speakerMap.set(s.id, s.name || `Speaker ${s.id}`);\n  }\n}\n\n// Fallback: wenn speakerMap leer ist, holen wir Namen aus den S\u00e4tzen\nif (speakerMap.size === 0) {\n  for (const s of sentences) {\n    if (typeof s.speaker_id !== \"undefined\") {\n      speakerMap.set(s.speaker_id, s.speaker_name || `Speaker ${s.speaker_id}`);\n    }\n  }\n}\n\n// Sortieren nach index (falls vorhanden) sonst start_time\nsentences.sort((a, b) => {\n  if (typeof a.index === \"number\" && typeof b.index === \"number\") return a.index - b.index;\n  return (a.start_time ?? 0) - (b.start_time ?? 0);\n});\n\n// === Gruppierung zu Sprecher-Bl\u00f6cken ===\nconst blocks = []; // [{ speakerName, startTime, endTime, text }]\nlet current = null;\n\nfor (const s of sentences) {\n  const name = speakerMap.get(s.speaker_id) || s.speaker_name || \"Unbekannt\";\n  const t = cleanText(s.text ?? s.raw_text ?? \"\");\n\n  if (!t) continue;\n\n  const st = Number(s.start_time ?? 0);\n  const et = Number(s.end_time ?? st);\n\n  const shouldBreak =\n    !current ||\n    current.speakerName !== name ||\n    (typeof current.lastEnd === \"number\" && typeof st === \"number\" && st - current.lastEnd > GAP_BREAK_SECONDS);\n\n  if (shouldBreak) {\n    // neuen Block starten\n    current = {\n      speakerName: name,\n      startTime: st,\n      lastEnd: et,\n      texts: [t]\n    };\n    blocks.push(current);\n  } else {\n    // an bestehenden Block anh\u00e4ngen\n    current.texts.push(t);\n    current.lastEnd = et;\n  }\n}\n\n// === Formatierung ===\n\n// a) Formatiert mit Sprecher + Zeit (wie Beispiel)\nconst formattedLines = blocks.map(b => {\n  let linePrefix = b.speakerName + \": \";\n  if (INCLUDE_TIMESTAMPS) {\n    linePrefix = `${b.speakerName}: ${toTimecode(b.startTime)}  `;\n  }\n  const paragraph = ensureEndPunctuation(cleanText(b.texts.join(\" \")));\n  return linePrefix + paragraph;\n});\nconst transcript_formatted = formattedLines.join(\"\\n\\n\");\n\n// b) Plain-Flie\u00dftext ohne Zeitstempel, Sprecher dennoch markiert\nconst plainLines = blocks.map(b => {\n  const paragraph = ensureEndPunctuation(cleanText(b.texts.join(\" \")));\n  return `${b.speakerName}: ${paragraph}`;\n});\nconst transcript_plain = plainLines.join(\"\\n\\n\");\n\n// Optional: Metadaten (Titel/Meeting-Link), falls vorhanden\nconst meta = {\n  title: data.title || \"\",\n  meeting_link: data.meeting_link || \"\",\n  organizer_email: data.organizer_email || \"\",\n  date_iso: data.dateString || \"\"\n};\n\nreturn [{\n  json: {\n    transcript_formatted,\n    transcript_plain,\n    meta\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "bd1bf746-bc2f-468e-95ca-8179aab21cec",
      "name": "Send a message",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2016,
        -48
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "Hey, your google sheet is ready! Go check it out!",
        "options": {},
        "subject": "Grading Call System ",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "bb529931-6899-4905-9a14-a2322f5c8488",
      "name": "Send a message1",
      "type": "n8n-nodes-base.slack",
      "position": [
        1536,
        -48
      ],
      "parameters": {
        "text": "Hey, your google sheet is ready! Go check it out!",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09HKQVAKB7",
          "cachedResultName": "demo"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "d877f4be-78c0-4ea1-af64-6b296c35cd00",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -112,
        -480
      ],
      "parameters": {
        "width": 464,
        "height": 608,
        "content": "## Setup fireflies.ai\n\n- Create an Account \n- Setup a Webhook in fireflies.ai \n- API Section: https://app.fireflies.ai/integrations/custom/n8n"
      },
      "typeVersion": 1
    },
    {
      "id": "3253a5b7-fcb5-4652-8bda-2c18639969e9",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -480
      ],
      "parameters": {
        "color": 5,
        "width": 816,
        "height": 608,
        "content": "## Connect Open AI Credential \nGo to https://platform.openai.com and log in.\n\t2.\tClick on your profile icon in the top-right corner.\n\t3.\tSelect View API keys.\n\t4.\tClick Create new secret key.\n\t5.\tCopy the generated key (it starts with sk-...) and save it securely \u2014 you won\u2019t be able to see it again later."
      },
      "typeVersion": 1
    },
    {
      "id": "42cc890a-7510-4dfa-b556-5125357cc34c",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1232,
        -480
      ],
      "parameters": {
        "color": 4,
        "width": 512,
        "height": 608,
        "content": "## Setup Slack\n\n\ud83d\udd39 Slack API Credentials\n\n\t1.\tGo to https://api.slack.com/apps and log in with your Slack account.\n\t2.\tClick Create New App.\n\t\u2022\tChoose From scratch and select your workspace.\n\t3.\tIn the app dashboard, go to OAuth & Permissions.\n\t4.\tUnder Scopes, add the permissions your app needs.\n\t5.\tScroll up and click Install to Workspace.\n\t6.\tOnce installed, you\u2019ll see your Bot User OAuth Token (xoxb-...). Copy and save it securely."
      },
      "typeVersion": 1
    },
    {
      "id": "8d4db160-d9f7-4b8c-9744-f11f99375455",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1776,
        -480
      ],
      "parameters": {
        "width": 464,
        "height": 608,
        "content": "## Setup Gmail  \n\n1.\tGo to https://console.cloud.google.com/ and log in.\n2.\tCreate a New Project (or select an existing one).\n3.\tIn the left menu, go to APIs & Services \u2192 Library.\n4.\tSearch for Gmail API and click Enable.\n5.\tGo to APIs & Services \u2192 Credentials.\n6.\tClick Create Credentials \u2192 OAuth client ID.\n7. You\u2019ll need to configure an OAuth consent screen first (name + scope).\n8.\tChoose the app type (e.g., Desktop, Web).\n9.\tOnce created, copy your Client ID and Client Secret.\n10.\tDownload the credentials.json file (you\u2019ll need it for client apps)."
      },
      "typeVersion": 1
    },
    {
      "id": "13ec4b49-ebed-4fa3-bc00-993951948242",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        -848
      ],
      "parameters": {
        "color": 6,
        "width": 368,
        "height": 336,
        "content": "## How it Works \n\n\t1.\tTrigger via Webhook \u2013 The workflow starts whenever a Fireflies.ai transcript is available.\n\t2.\tTranscript Analysis \u2013 The call transcript is passed to OpenAI, which evaluates and grades the quality of the call.\n\t3.\tLead Data Logging \u2013 The graded results and lead information are automatically appended into a Google Sheet for record-keeping and performance tracking.\n\t4.\tNotifications \u2013 You instantly receive a Slack or Gmail notification summarizing the evaluation, ensuring you never miss important insights."
      },
      "typeVersion": 1
    },
    {
      "id": "9c4a4d5d-e559-4302-9c34-b762b95dbe22",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        608,
        -848
      ],
      "parameters": {
        "color": 6,
        "width": 368,
        "height": 336,
        "content": "## Why its Valuable \n\n\t\u2022\t\u2705 Automated Call Reviews \u2013 No need to manually re-listen or grade calls.\n\t\u2022\t\u2705 Consistent Scoring \u2013 Objective AI-powered evaluation improves training and feedback.\n\t\u2022\t\u2705 Centralized Data \u2013 All call insights and lead details are stored neatly in Google Sheets.\n\t\u2022\t\u2705 Instant Alerts \u2013 Sales teams get notified right away via Slack or Gmail, boosting response times.\n\t\u2022\t\u2705 Scalable \u2013 Works out-of-the-box for onboarding, sales, or support teams, and reduces manual overhead.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e3db7392-05a2-4fca-abfd-7f442e5563b9",
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Get a transcript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Message a model": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get a transcript": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Append row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append row in sheet": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send a message1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "Message a model",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}