{
  "id": "3FtOev3VfU3pKYia",
  "name": "Perplexity Google Searcher",
  "tags": [
    {
      "id": "5EWJHSucuo3Ru5rj",
      "name": "n8n Creator Template",
      "createdAt": "2025-10-12T17:23:49.597Z",
      "updatedAt": "2025-10-12T17:23:49.597Z"
    }
  ],
  "nodes": [
    {
      "id": "d9fe9c9c-0336-4146-82ff-38323a024f33",
      "name": "Get All Rows",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -2432,
        48
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_TAB_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_TAB_ID",
          "cachedResultName": "YOUR_SHEET_TAB_NAME"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit?usp=drivesdk",
          "cachedResultName": "YOUR_SHEET_NAME"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "alwaysOutputData": true
    },
    {
      "id": "da22e108-3c0a-415e-8853-73b810023e68",
      "name": "Filter \u2014 Pending Only",
      "type": "n8n-nodes-base.filter",
      "position": [
        -2224,
        48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition-status-pending",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json['Status'] }}",
              "rightValue": "Pending"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "69b19172-da6d-403a-a0e8-509190cff583",
      "name": "Loop Over Rows",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -2000,
        48
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "5af35002-68e8-47e9-85ed-78654f38c570",
      "name": "Set Status \u2014 Processing",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1792,
        64
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "Processing",
            "row_number": "={{ $json['row_number'] }}"
          },
          "schema": [
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ]
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_TAB_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_TAB_ID",
          "cachedResultName": "YOUR_SHEET_TAB_NAME"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit?usp=drivesdk",
          "cachedResultName": "YOUR_SHEET_NAME"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "44e92705-608d-4fb9-b345-0a29d59a6646",
      "name": "Get Config Tab",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1568,
        64
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_CONFIG_TAB_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_CONFIG_TAB_ID",
          "cachedResultName": "YOUR_CONFIG_TAB_NAME"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit?usp=drivesdk",
          "cachedResultName": "YOUR_SHEET_NAME"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "0287a14f-474e-4a3a-952e-62dfa5f03414",
      "name": "Build Dynamic Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        -1360,
        64
      ],
      "parameters": {
        "jsCode": "// Grab the name from the loop\nconst name = $('Loop Over Rows').item.json['Name'];\n\n// Grab all config rows \u2014 each row is one question/field\nconst configRows = $input.all();\n\n// Build a map of field_key -> question with [NAME] replaced\nconst fieldMap = {};\nconst questionLines = [];\n\nfor (const row of configRows) {\n  const fieldKey = row.json['Field Key'];         // e.g. current_company\n  const columnLetter = row.json['Column'];        // e.g. C\n  const rawQuestion = row.json['Question Template']; // e.g. What company does [NAME] work for?\n\n  if (!fieldKey || !rawQuestion) continue;\n\n  // Replace [NAME] placeholder with actual name\n  const hydrated = rawQuestion.replace(/\\[NAME\\]/gi, name);\n\n  fieldMap[fieldKey] = {\n    column: columnLetter,\n    question: hydrated\n  };\n\n  questionLines.push(`- ${fieldKey}: ${hydrated}`);\n}\n\n// Build the JSON keys block for the prompt\nconst jsonKeys = Object.keys(fieldMap)\n  .map(k => `  \"${k}\": \"\"`)\n  .join(',\\n');\n\n// Build the final prompt\nconst prompt = `Research the following person: ${name}\n\nReturn ONLY a valid JSON object with exactly these keys, no explanation, no markdown, no citations:\n{\n${jsonKeys}\n}\n\nAnswer each key using these questions:\n${questionLines.join('\\n')}\n\nIf you cannot find an answer for a field, use the string \"Not found\" as the value.`;\n\nreturn [{\n  json: {\n    name: name,\n    row_number: $('Loop Over Rows').item.json['row_number'],\n    prompt: prompt,\n    field_map: fieldMap,\n    field_keys: Object.keys(fieldMap)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "53cf4ac3-46a0-4d19-a65d-2936f9319567",
      "name": "Perplexity \u2014 Research Call",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        -1152,
        64
      ],
      "parameters": {
        "url": "https://api.perplexity.ai/chat/completions",
        "method": "POST",
        "options": {
          "timeout": 30000
        },
        "jsonBody": "={\n  \"model\": \"sonar\",\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"You are a research assistant. Always respond with only a valid JSON object. No markdown, no backticks, no explanations, no citations.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": {{ JSON.stringify($json.prompt) }}\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.2
    },
    {
      "id": "bf7da2fb-7917-4e7f-90d7-7ba3910ad67c",
      "name": "Parse Perplexity Response",
      "type": "n8n-nodes-base.code",
      "position": [
        -912,
        48
      ],
      "parameters": {
        "jsCode": "// Get Perplexity raw response\nlet raw = '';\ntry {\n  raw = $input.first().json.choices[0].message.content;\n} catch (e) {\n  throw new Error('Could not read Perplexity response: ' + e.message);\n}\n\n// Strip markdown fences if present\nraw = raw.replace(/```json/gi, '').replace(/```/g, '').trim();\n\n// Parse JSON\nlet parsed;\ntry {\n  parsed = JSON.parse(raw);\n} catch (e) {\n  throw new Error('JSON parse failed. Raw response: ' + raw);\n}\n\n// Pull field map and metadata from Build Dynamic Prompt node\nconst fieldMap = $('Build Dynamic Prompt').item.json.field_map;\nconst fieldKeys = $('Build Dynamic Prompt').item.json.field_keys;\nconst name = $('Build Dynamic Prompt').item.json.name;\nconst rowNumber = $('Build Dynamic Prompt').item.json.row_number;\n\n// Build the sheet update payload dynamically from field map\nconst sheetPayload = { row_number: rowNumber };\nconst notFoundFields = [];\n\nfor (const key of fieldKeys) {\n  const value = parsed[key] || 'Not found';\n  sheetPayload[key] = value;\n\n  if (!parsed[key] || parsed[key].toLowerCase() === 'not found') {\n    notFoundFields.push(key);\n  }\n}\n\nreturn [{\n  json: {\n    ...sheetPayload,\n    name: name,\n    field_map: fieldMap,\n    field_keys: fieldKeys,\n    not_found_fields: notFoundFields,\n    has_missing: notFoundFields.length > 0\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "1c26a085-d3e2-4c15-98ee-513daac1bd63",
      "name": "Map Fields to Sheet Columns",
      "type": "n8n-nodes-base.code",
      "position": [
        -704,
        48
      ],
      "parameters": {
        "jsCode": "// This node dynamically maps parsed field values back to their sheet columns\nconst input = $input.first().json;\nconst fieldMap = input.field_map;\nconst fieldKeys = input.field_keys;\nconst rowNumber = input.row_number;\n\nconst columnPayload = {\n  row_number: rowNumber,\n  Status: 'Done',\n  'Error Log': ''\n};\n\nfor (const key of fieldKeys) {\n  const colHeader = fieldMap[key]?.column;\n  const value = input[key] || 'Not found';\n  if (colHeader) {\n    columnPayload[colHeader] = value;\n  }\n}\n\nreturn [{\n  json: columnPayload\n}];"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "7b38f127-0f4e-41fe-aed9-bcecb58aedc9",
      "name": "Write Results to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -512,
        48
      ],
      "parameters": {
        "columns": {
          "value": {
            "row_number": 0
          },
          "schema": [
            {
              "id": "Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Company",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Current Company",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Location",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Current Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Industry",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Industry",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Socials / Others",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Socials / Others",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Error Log",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Error Log",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_TAB_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_TAB_ID",
          "cachedResultName": "YOUR_SHEET_TAB_NAME"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit?usp=drivesdk",
          "cachedResultName": "YOUR_SHEET_NAME"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "044f9ae9-289f-4f64-a33e-6c8198eccc19",
      "name": "Any Fields Missing?",
      "type": "n8n-nodes-base.if",
      "position": [
        -320,
        48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition-has-missing",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.has_missing }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "95c3e58e-ce5e-47be-b97e-decbde3ec7e5",
      "name": "Slack \u2014 Missing Fields Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        -64,
        32
      ],
      "parameters": {
        "text": "=\u26a0\ufe0f *Perplexity Research \u2014 Missing Fields*\n\n*Name:* {{ $json.name }}\n*Row:* {{ $json.row_number }}\n*Missing Fields:* {{ $json.not_found_fields.join(', ') }}\n*Time:* {{ $now.toISO() }}\n\nAll other fields were written to the sheet. Please review row {{ $json.row_number }} manually.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SLACK_CHANNEL_ID",
          "cachedResultName": "YOUR_SLACK_CHANNEL_NAME"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "5e8aa6f9-161e-49b6-b3a2-b5d7c9187bd5",
      "name": "Write Error to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -848,
        320
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "Error",
            "Error Log": "={{ $json.error?.message ?? 'Perplexity API call failed \u2014 check credentials or rate limits' }}",
            "row_number": "={{ $('Loop Over Rows').item.json['row_number'] }}"
          },
          "schema": [
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Error Log",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Error Log",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ]
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "dcaf2dc4-6ab2-4372-9d24-274564f24b70",
      "name": "Slack \u2014 API Error Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        -688,
        320
      ],
      "parameters": {
        "text": "=\ud83d\udea8 *Perplexity Research \u2014 API Error*\n\n*Name:* {{ $('Loop Over Rows').item.json['Name'] }}\n*Row:* {{ $('Loop Over Rows').item.json['row_number'] }}\n*Error:* {{ $json.error?.message ?? 'Unknown error \u2014 Perplexity API call failed' }}\n*Time:* {{ $now.toISO() }}\n\nRow status has been set to *Error*. Please check Column H for details.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SLACK_CHANNEL_ID",
          "cachedResultName": "YOUR_SLACK_CHANNEL_NAME"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "dc63b796-3e14-44ec-a50b-8739cae1cbff",
      "name": "When clicking 'Execute workflow'",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -2608,
        48
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "c09cf0a2-a99d-44f4-9d9e-8ff302437764",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3120,
        -256
      ],
      "parameters": {
        "width": 432,
        "height": 640,
        "content": "## Perplexity People Researcher\nAutomatically researches people from a Google Sheet using the Perplexity AI API and writes the results back to the same sheet.\n\n## What It Does\nAdd a name to your Google Sheet and set the status to Pending. The workflow picks it up, sends your research questions to Perplexity, and writes the answers back to the correct columns \u2014 all without any manual steps.\n\n\n##Setup\nCredentials needed:\n\n-Google Sheets OAuth2\n-Perplexity API \u2014 HTTP Header Auth, value: Bearer\nYOUR_API_KEY\n-Slack API\n\n##Google Sheet structure:\nSheet 1 \u2014 Main data tab with these columns:\nName | Status | Current Company | Location | Current Title | Industry | Socials / Others | Error Log\nConfig tab \u2014 Controls what questions get asked:\nField Key | Question Template | Column\n\nIn the Question Template column use [NAME] as a placeholder \u2014 the workflow replaces it with the actual name automatically.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "541146bc-880f-438c-a20d-aae84e4aa7ce",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2512,
        -400
      ],
      "parameters": {
        "color": 6,
        "width": 656,
        "height": 432,
        "content": "## How To Use\nOpen your Google Sheet\nType a name in Column A\nSet Column B status to Pending\nRun the workflow \u2014 results appear in columns C through G automatically\n\nTo change what gets researched, edit the questions in the Config tab. No changes to the workflow needed.\n\n## Placeholders To Replace\n\nYOUR_GOOGLE_SHEET_ID\nYOUR_GOOGLE_CREDENTIAL_ID\nYOUR_PERPLEXITY_CREDENTIAL_ID\nYOUR_SLACK_CREDENTIAL_ID\nYOUR_SLACK_CHANNEL_ID\nYOUR_SHEET_TAB_NAME\nYOUR_CONFIG_TAB_NAME"
      },
      "typeVersion": 1
    },
    {
      "id": "7b306700-1fce-4496-936e-28fedf05d844",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1168,
        304
      ],
      "parameters": {
        "color": 3,
        "width": 288,
        "height": 224,
        "content": "## Error Handling\nIf Perplexity cannot find an answer for a field, the cell is written as \"Not found\" and a Slack alert is sent with the name and which fields were missing. If the API call fails entirely, the row status is set to Error, the error message is written to Column H, and a separate Slack alert fires."
      },
      "typeVersion": 1
    },
    {
      "id": "e87c8fdc-8989-487b-bf7e-c46756fd982f",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1664,
        -256
      ],
      "parameters": {
        "color": 6,
        "width": 480,
        "height": 288,
        "content": "## Creating and formating questions \n\nThe next few nodes are grabbing the status of the spreadsheet from pending to processing.\n\nThen taking the sheet called \"config tab\" which is where you will input your questions and you will use the place holder [NAME] as mentioned to plug in questions you want to ask perplexity.\n\nThen in the Perplexity node it will use an API to ask and return the answeres it has to those questions about the person you are looking for."
      },
      "typeVersion": 1
    },
    {
      "id": "4790c847-22b6-4628-a289-568aca3d2ea7",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -784,
        -192
      ],
      "parameters": {
        "color": 6,
        "width": 432,
        "height": 192,
        "content": "## Parse and write answers\n\nThose individual values are then mapped to their correct column headers, matching exactly what your sheet expects. The row number is carried through this entire process so the write always lands in the right place \u2014 never on the wrong person.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "9be4c5ae-f203-4f10-9564-703ac98374a8",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -160,
        -208
      ],
      "parameters": {
        "color": 3,
        "width": 288,
        "height": 224,
        "content": "## Error Handling\nSimilar to the other error log node this one will send a detailed slack message on what rows are experiencing the missing fields error. "
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "762707b8-d89e-4eab-8f2c-fdedad82f64f",
  "connections": {
    "Get All Rows": {
      "main": [
        [
          {
            "node": "Filter \u2014 Pending Only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Config Tab": {
      "main": [
        [
          {
            "node": "Build Dynamic Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Rows": {
      "main": [
        [],
        [
          {
            "node": "Set Status \u2014 Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any Fields Missing?": {
      "main": [
        [
          {
            "node": "Slack \u2014 Missing Fields Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Over Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Dynamic Prompt": {
      "main": [
        [
          {
            "node": "Perplexity \u2014 Research Call",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Error to Sheet": {
      "main": [
        [
          {
            "node": "Slack \u2014 API Error Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Results to Sheet": {
      "main": [
        [
          {
            "node": "Any Fields Missing?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter \u2014 Pending Only": {
      "main": [
        [
          {
            "node": "Loop Over Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Perplexity Response": {
      "main": [
        [
          {
            "node": "Map Fields to Sheet Columns",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Status \u2014 Processing": {
      "main": [
        [
          {
            "node": "Get Config Tab",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map Fields to Sheet Columns": {
      "main": [
        [
          {
            "node": "Write Results to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Perplexity \u2014 Research Call": {
      "main": [
        [
          {
            "node": "Parse Perplexity Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Write Error to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking 'Execute workflow'": {
      "main": [
        [
          {
            "node": "Get All Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}