{
  "id": "r8Qe7WuBooLIDbHv",
  "meta": {
    "templateTitle": "fluidX \u2014 Create Session & Notify (API Integration Example)",
    "templateDescription": "Creates a production-ready fluidX THE EYE session, delivers SMS/email invites, deduplicates media polling, adds AI-based labels, and syncs photos plus rolling summaries to Google Drive.",
    "templateInstructions": "# \ud83d\udcdd Setup \u2014 fluidX THE EYE Session Automation\n\n## 1. Accounts & Docs\n- Create a developer login at https://live.fluidx.digital (TEST plan is free)\n- Review the API reference: https://live.fluidx.digital/api/swagger.html\n\n## 2. Required Credentials in n8n\n1. `fluidx API key` (HTTP Header Auth \u2192 header `x-api-key`)\n2. SMTP account for outbound email notifications\n3. Google Drive OAuth2 credential (for uploads)\n4. Optional: OpenAI credential if you want AI photo captions\n\n## 3. Configure the \"Set Config\" node\n- `BASE_URL`: keep `https://live.fluidx.digital`\n- `company` / `project` / `billingcode` / `sku`: set to your production identifiers\n- `language`: controls the OpenAI caption language (default `DE`)\n- `message`: SMS intro text; the customer link is appended automatically\n- Phone/email fields come from the built-in form each run, so no personal data is stored in the workflow\n\n## 4. Run Flow\nForm Trigger \u2192 Create Session \u2192 Set Session Vars \u2192 Google Drive folder \u2192 Send SMS \u2192 Send Email \u2192 Wait for live feed \u2192 Poll `/api/revxr/ext/session` for `photoRefs` \u2192 Skip already processed photos via workflow static data \u2192 Download \u2192 Analyze (optional OpenAI) \u2192 Upload media + captions to Drive \u2192 Fetch `/api/fx/ext/media/summary`, convert to text, and keep the latest summary file per session.\n\n## 5. Operational Notes\n- All HTTP request nodes reference the `fluidx API key` credential so you can rotate keys centrally.\n- Workflow static data is cleared after each run to avoid leaking media IDs between sessions.\n- Replace the Google Drive folder ID with your own shared workspace before publishing.\n- Use environment variables or n8n Credentials for any other secrets you add.\n\nHappy streaming! \ud83d\ude80\n",
    "templateCredsSetupCompleted": true
  },
  "name": "n8n_fluidx_create_session",
  "tags": [],
  "nodes": [
    {
      "id": "0d2978ac-0459-47fd-9b99-9851852cad04",
      "name": "\ud83d\udcdd Setup & Instructions",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 688,
        "height": 540,
        "content": "### Setup \u2014 Create a fluidX revXR THE EYE session\n\n**Goal:** Invite the customer via SMS and the service agent via email so both join the fluidX THE EYE session and share their cameras live.\n\n1. Sign in at https://live.fluidx.digital (activate the TEST ABO plan, \u20ac0) and create your API key.\n2. Review the API docs: https://live.fluidx.digital/api/swagger.html.\n3. In n8n add credentials:\n   - fluidX API key (HTTP Header Auth \u2192 header x-api-key)\n   - SMTP account for outbound email.\n   - OpenAI key\n   - Google Drive API\n4. Open the \"Set Config\" node \u2014 the defaults are ready to test; adjust other values if needed (the form collects the phone and email each run).\n5. Run the flow: Submit the form (\"On form submission\") \u2192 Create Session \u2192 Set Session Vars \u2192 Create Drive folder \u2192 Send SMS \u2192 Send Email.\n6. Create a THEEYE folder in your Google Drive root.\n\nTips:\n- Keep secrets inside n8n credentials or environment variables.\n- Use demo data while testing; swap to production values when ready.\n- Log out of live.fluidx.digital in the agent's browser before testing to ensure the invite flow opens a clean session.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f3421d4b-5e6a-4dd8-890e-c9023d262599",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        288,
        960
      ],
      "parameters": {
        "options": {},
        "formTitle": "fluidX digital The Eye Session Invitation",
        "formFields": {
          "values": [
            {
              "fieldLabel": "User Phone Number",
              "placeholder": "+1234567890",
              "requiredField": true
            },
            {
              "fieldLabel": "Agent Email Address",
              "placeholder": "user@example.com",
              "requiredField": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "cdd96102-c2b5-471a-aeaf-a6da0bee2f40",
      "name": "Set Config",
      "type": "n8n-nodes-base.set",
      "position": [
        512,
        960
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "BASE_URL",
              "value": "https://live.fluidx.digital"
            },
            {
              "name": "phoneNumberUser",
              "value": "={{ $json['User Phone Number'] }}"
            },
            {
              "name": "message",
              "value": "fluidX.digital TheEye. Your Link: "
            },
            {
              "name": "emailAgent",
              "value": "={{ $json['Agent Email Address'] }}"
            },
            {
              "name": "language",
              "value": "DE"
            },
            {
              "name": "company",
              "value": "service berlin"
            },
            {
              "name": "project",
              "value": "fluidX demo"
            },
            {
              "name": "billingcode",
              "value": "demo-budget"
            },
            {
              "name": "correlationId",
              "value": "{{$now}}"
            },
            {
              "name": "sku",
              "value": "THEEYE"
            }
          ]
        },
        "options": {},
        "keepOnlySet": true
      },
      "typeVersion": 2
    },
    {
      "id": "bece2d3b-3465-4cab-8483-f49136e1778c",
      "name": "Set Session Vars",
      "type": "n8n-nodes-base.set",
      "position": [
        960,
        960
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "sessionId",
              "value": "={{ $json.revXRSession.id }}"
            },
            {
              "name": "viewTheEyeUrl",
              "value": "={{ $json.sessionInfo.viewTheEyeUrl }}"
            },
            {
              "name": "theEyeUserUrl",
              "value": "={{ $json.sessionInfo.theEyeUserUrl }}"
            },
            {
              "name": "folderName",
              "value": "={{ 'THEEYE_' + $now.toFormat('yyyyLLdd_HHmmss') + '_' + $json.revXRSession.id }}"
            }
          ]
        },
        "options": {},
        "keepOnlySet": true
      },
      "typeVersion": 2
    },
    {
      "id": "e77f231d-a7ba-4be8-87a7-b6f97e9aa3cc",
      "name": "Create Session Folder",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1184,
        960
      ],
      "parameters": {
        "name": "={{ $node[\"Set Session Vars\"].json.folderName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "10d6dEoF6GVYGMUW0M1eZiSlDc7JLtaxY",
          "cachedResultUrl": "https://drive.google.com/drive/folders/10d6dEoF6GVYGMUW0M1eZiSlDc7JLtaxY",
          "cachedResultName": "THEEYE"
        },
        "resource": "folder"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "f9d45461-ef0b-4724-a771-96abd835c6b7",
      "name": "Send email to Agent",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1632,
        960
      ],
      "parameters": {
        "text": "=fluidx.digital View TheEye: Your Link: \n{{ $node[\"Set Session Vars\"].json.viewTheEyeUrl }}",
        "options": {},
        "subject": "fluidX.digital View TheEye Link",
        "toEmail": "={{ $node[\"Set Config\"].json.emailAgent }}",
        "fromEmail": "user@example.com",
        "emailFormat": "text"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "78c8ce11-4a68-4f4a-af66-deb61212bffc",
      "name": "\u2139\ufe0f Viewer Tips",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2495,
        400
      ],
      "parameters": {
        "color": 7,
        "width": 835,
        "height": 364,
        "content": "### If the Session is closed: Get the media summary\nfluidX API GET /api/fx/ext/media/summary\nUpload the final Summary to the Google Drive\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "18bfe57d-a072-4886-b99e-2f9e3fbc9773",
      "name": "Split photoRefs (Item Lists)",
      "type": "n8n-nodes-base.itemLists",
      "position": [
        2976,
        912
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "=photoRefs"
      },
      "typeVersion": 3,
      "alwaysOutputData": false
    },
    {
      "id": "5f6ee9ef-966a-411e-beee-c2d5f0406c44",
      "name": "fluidX API - Media Info HTTP Request GET",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        3424,
        944
      ],
      "parameters": {
        "url": "={{ $item(0).$node[\"Set Config\"].json.BASE_URL }}/api/revxr/ext/media/info",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "type",
              "value": "image"
            },
            {
              "name": "id",
              "value": "={{ $json.id }}"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "18f9e934-a057-4327-b806-67f33c710dab",
      "name": "Upload file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        6112,
        528
      ],
      "parameters": {
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create Session Folder').item.json.id }}"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "68726804-080e-4eaa-868a-6f18012165d0",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        6560,
        1184
      ],
      "parameters": {
        "amount": 15
      },
      "typeVersion": 1.1
    },
    {
      "id": "3a119e17-c12c-4a95-978a-1dcfdef0acc1",
      "name": "Wait1",
      "type": "n8n-nodes-base.wait",
      "position": [
        1856,
        960
      ],
      "parameters": {
        "amount": 30
      },
      "typeVersion": 1.1
    },
    {
      "id": "4f4c0803-fd98-450a-adcc-185f904f4346",
      "name": "Analyze image",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "onError": "continueRegularOutput",
      "position": [
        4768,
        704
      ],
      "parameters": {
        "text": "=What's in this image? Output language is {{ $('Set Config').item.json.language }}",
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "chatgpt-4o-latest",
          "cachedResultName": "CHATGPT-4O-LATEST"
        },
        "options": {},
        "resource": "image",
        "inputType": "base64",
        "operation": "analyze"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "354b4dca-18e9-42ce-b489-95d2b8cab6c6",
      "name": "Merge Analyze + URL",
      "type": "n8n-nodes-base.merge",
      "position": [
        4992,
        768
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "6656b843-0c83-4301-a834-c1a0da326b92",
      "name": "Build MediaInfo",
      "type": "n8n-nodes-base.set",
      "position": [
        5216,
        768
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "type",
              "value": "image"
            },
            {
              "name": "id",
              "value": "={{ $json._srcId }}"
            },
            {
              "name": "title",
              "value": "={{\n  (() => {\n    // Kandidaten vom Analyze-Node \u2013 nimm was bef\u00fcllt ist\n    const raw =($json['0'].content[0].text).trim();\n\n    // Fallback: sinnvoller Titel, falls nichts da\n    const fallback = `Image ${$json.id || ''}`.trim();\n\n    if (!raw) return fallback;\n\n    // erste Satzh\u00e4lfte nehmen\n    let first = (raw.split(/[.!?\\n]/).find(s => s && s.trim().length) || raw).trim();\n\n    // leading Phrasen weg\n    first = first\n      .replace(/^\\s*(the|this)\\s+image\\s+(shows|depicts|displays)\\s*/i, '')\n      .replace(/^\\s*(an?\\s+|the\\s+)?(photo|image)\\s+of\\s+/i, '')\n      .trim();\n\n first = first\n      .replace(/^\\s*(Auf dem|Das)\\s+Bild\\s+(sieht man|zeigt)\\s*/i, '')\n      .replace(/^\\s*(einen?\\s+|ein\\s+)?(Bild)\\s+of\\s+/i, '')\n      .trim();\n\n    // auf 10 W\u00f6rter k\u00fcrzen\n    const words = first.split(/\\s+/);\n    let title = words.slice(0, 10).join(' ');\n\n    // Erstes Zeichen gro\u00df\n    title = title.charAt(0).toUpperCase() + title.slice(1);\n\n    return title || fallback;\n  })()\n}}"
            },
            {
              "name": "description",
              "value": "={{ $json['0'].content[0].text }}"
            }
          ]
        },
        "options": {},
        "keepOnlySet": true
      },
      "typeVersion": 2
    },
    {
      "id": "aa94f2dd-756a-46f2-9210-91be6ee3b883",
      "name": "fluidX API - Create Session",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        736,
        960
      ],
      "parameters": {
        "url": "={{ $node[\"Set Config\"].json.BASE_URL }}/api/fx/ext/session/create",
        "method": "POST",
        "options": {
          "timeout": 30000
        },
        "jsonBody": "={\n  \"sessionDetails\": {\n    \"company\": {{ $json.company.toJsonString() }},\n    \"project\": {{ $json.project.toJsonString() }},\n    \"billingcode\": {{ $json.billingcode.toJsonString() }},\n    \"correlationId\": \"2025-1234\",\n    \"sku\": {{ $json.sku.toJsonString() }}\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "58f80aca-625f-44bb-9f3b-0c726d9e3a20",
      "name": "fluidX API - Send SMS User",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1408,
        960
      ],
      "parameters": {
        "url": "={{ $node[\"Set Config\"].json.BASE_URL }}/api/fx/ext/sms/send",
        "method": "POST",
        "options": {
          "timeout": 30000
        },
        "jsonBody": "={\n  \"phoneNumber\": \"{{ $node[\"Set Config\"].json.phoneNumberUser }}\",\n  \"message\": {{ ($node[\"Set Config\"].json.message + $node[\"Set Session Vars\"].json.theEyeUserUrl).toJsonString() }},\n  \"sessionId\": {{ $node[\"Set Session Vars\"].json.sessionId.toJsonString() }}\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "d54991a8-c71f-49d2-b3d0-a8b4a42ebaa8",
      "name": "fluidX API - Get Session Info",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        2080,
        960
      ],
      "parameters": {
        "url": "={{ $item(0).$node[\"Set Config\"].json.BASE_URL }}/api/revxr/ext/session",
        "options": {
          "timeout": 30000
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "sessionId",
              "value": "={{  $item(0).$node[\"Set Session Vars\"].json.sessionId }}"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "09d29311-35df-4666-b3ed-69d350ee23ef",
      "name": "fluidX API - Download Photo THEEYE Session",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4320,
        768
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {
          "timeout": 60000
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "3dce58d2-3599-4cfe-8270-86eaed04f5bd",
      "name": "fluidX API - Media Info HTTP Request POST",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5440,
        768
      ],
      "parameters": {
        "url": "={{ $item(0).$node[\"Set Config\"].json.BASE_URL }}/api/revxr/ext/media/info",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ $json }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "9a9c03a1-4c76-4cc9-b99c-1402870c57d4",
      "name": "If new Image",
      "type": "n8n-nodes-base.if",
      "position": [
        3872,
        848
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "33e243e6-7c66-4e3d-bb2e-b91a1c0f1d2e",
              "operator": {
                "type": "string",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{ $json.mediaInfo.description }}",
              "rightValue": ""
            },
            {
              "id": "c495e43a-4333-479e-9dc9-c0e29f8259c4",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "d5961c10-19fe-4cf3-8c29-e7bd0394238f",
      "name": "If Media Id",
      "type": "n8n-nodes-base.if",
      "position": [
        3200,
        1040
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "4f59097c-8851-43c7-9b9a-78a4d6181d8a",
              "operator": {
                "type": "number",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.id }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "78d49f55-9671-4868-b617-f5f9b29be27c",
      "name": "If Session Active",
      "type": "n8n-nodes-base.if",
      "position": [
        2304,
        896
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-session-active",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.revXRSession.status }}",
              "rightValue": "ACTIVE"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2de45ed6-e553-4e9b-b0e7-c270f22b4df5",
      "name": "The End",
      "type": "n8n-nodes-base.noOp",
      "position": [
        3648,
        600
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "55247c08-471c-46b4-97be-ef17c50a3445",
      "name": "Generate Photo Summary",
      "type": "n8n-nodes-base.code",
      "position": [
        5664,
        768
      ],
      "parameters": {
        "jsCode": "// Iterate through all incoming items and create one summary per mediaInfo\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const info = item.json.mediaInfo || {};\n\n  const description = info.description?.trim() || 'No description';\n  const filename = `photo-${info.imageId || info.id || Date.now()}.txt`;\n\n  results.push({\n    json: {\n      filename,\n      text: `Title: ${info.title || 'Untitled'}\\nDescription: ${description}\\n---\\n`\n    }\n  });\n}\n\nreturn results;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "33faddeb-94fe-42e9-9293-2b576f810159",
      "name": "Upload Photo Summary",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        6112,
        768
      ],
      "parameters": {
        "name": "={{ $json.filename }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create Session Folder').first().json.id.trim() }}"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "ead00873-f003-4565-a0d5-2ce82697d2fa",
      "name": "Convert Text to Binary",
      "type": "n8n-nodes-base.code",
      "position": [
        5888,
        768
      ],
      "parameters": {
        "jsCode": "// Convert all text summaries to binary files for Google Drive upload\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const { text, filename } = item.json;\n  const buffer = Buffer.from(text, 'utf8');\n\n  results.push({\n    json: { filename },\n    binary: {\n      data: {\n        data: buffer.toString('base64'),\n        mimeType: 'text/plain',\n        fileName: filename\n      }\n    }\n  });\n}\n\nreturn results;\n\n"
      },
      "typeVersion": 2
    },
    {
      "id": "eb3e2f03-92e5-4bf4-8cbe-06d505ddc038",
      "name": "fluidX API - Media Summary",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2528,
        600
      ],
      "parameters": {
        "url": "={{ $item(0).$node[\"Set Config\"].json.BASE_URL }}/api/fx/ext/media/summary",
        "options": {
          "timeout": 30000
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "sessionId",
              "value": "={{ $item(0).$node[\"Set Session Vars\"].json.sessionId }}"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b10c3d6a-bb00-4d4a-b3f3-4b2814525b2d",
      "name": "Carry URL and Id",
      "type": "n8n-nodes-base.set",
      "position": [
        4544,
        768
      ],
      "parameters": {
        "values": {
          "number": [
            {
              "name": "_srcId",
              "value": "={{ $json.id }}"
            }
          ],
          "string": [
            {
              "name": "_srcUrl",
              "value": "={{ $json.url }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 2
    },
    {
      "id": "cf9f62ec-6c67-4e0d-b62f-cfe3ca5b566f",
      "name": "If photos",
      "type": "n8n-nodes-base.if",
      "position": [
        2752,
        992
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "7988fb13-6236-4794-b051-9d992e47ab05",
              "operator": {
                "type": "array",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json.photoRefs }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "703663ab-56b1-4837-bfbe-fa6bc4d86a5f",
      "name": "Extract Media Refs photos",
      "type": "n8n-nodes-base.set",
      "position": [
        2528,
        992
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "photoRefs",
              "value": "={{$json.mediaInfo?.photoRefs || $json.photoRefs || []}}"
            }
          ]
        },
        "options": {},
        "keepOnlySet": true
      },
      "typeVersion": 2
    },
    {
      "id": "2ea8fec6-05db-4c6f-9790-b4f72c3ed42a",
      "name": "Check Already Uploaded",
      "type": "n8n-nodes-base.code",
      "position": [
        4096,
        768
      ],
      "parameters": {
        "jsCode": "// \ud83d\udd01 1\ufe0f\u20e3 Global store initialisieren\nconst store = $getWorkflowStaticData('global');\nif (!store.uploadedPhotoIds) store.uploadedPhotoIds = [];\n\n// \ud83d\udd01 2\ufe0f\u20e3 Alle eingehenden Items holen\nconst items = $input.all();\nconst newItems = [];\n\n// \ud83d\udd01 3\ufe0f\u20e3 Schleife: nur neue Bilder behalten\nfor (const item of items) {\n  const id = item.json.id;\n  if (!id) continue;\n\n  if (!store.uploadedPhotoIds.includes(id)) {\n    store.uploadedPhotoIds.push(id);\n    console.log(`\u2705 Neues Foto erkannt: ${id}`);\n    newItems.push(item);\n  } else {\n    console.log(`\u26a0\ufe0f Foto ${id} wurde bereits verarbeitet, \u00fcberspringe`);\n  }\n}\n\n// \ud83d\udd01 4\ufe0f\u20e3 Alles Neue als Batch zur\u00fcckgeben\nreturn newItems;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "42b490c0-d66d-41bb-8ec4-16ba19ea10e5",
      "name": "Merge photoRefs",
      "type": "n8n-nodes-base.merge",
      "position": [
        3648,
        848
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "5aa40281-8a45-434f-beae-b131f8decb96",
      "name": "Clear Uploaded Photo Store",
      "type": "n8n-nodes-base.code",
      "position": [
        3424,
        600
      ],
      "parameters": {
        "jsCode": "// \ud83e\uddf9 Clear stored photo IDs after the session ends\nconst store = $getWorkflowStaticData('global');\n\nif (store.uploadedPhotoIds && store.uploadedPhotoIds.length > 0) {\n  console.log(`\ud83e\uddf9 Removing ${store.uploadedPhotoIds.length} stored photo IDs from the upload cache`);\n  store.uploadedPhotoIds = [];\n} else {\n  console.log('\u2705 No stored photo ID cache \u2013 nothing to clean up');\n}\n\nreturn $input.all();\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a71d0b5a-6076-41c2-8d71-0b738ed14485",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        6336,
        752
      ],
      "parameters": {
        "mode": "chooseBranch"
      },
      "typeVersion": 3.2
    },
    {
      "id": "adf7b7e5-2f9a-4c4d-8f00-1fec2c7315c3",
      "name": "Convert Summary Text to Binary",
      "type": "n8n-nodes-base.code",
      "position": [
        2752,
        600
      ],
      "parameters": {
        "jsCode": "// \ud83e\udde0 Safe conversion of session summary text to binary for Google Drive upload\nconst store = $getWorkflowStaticData('global');\nif (!store.sessionSummaryFiles || typeof store.sessionSummaryFiles !== 'object') {\n  store.sessionSummaryFiles = {};\n}\n\n// \ud83d\udd39 Get session info\nconst sessionItems = $items('Set Session Vars', 0, 0);\nconst sessionId = sessionItems[0]?.json?.sessionId || 'unknown-session';\n\n// \ud83d\udd39 Skip if we already uploaded a summary for this session\nif (store.sessionSummaryFiles[sessionId]) {\n  console.log(`\u2705 Session ${sessionId} summary already uploaded (file ${store.sessionSummaryFiles[sessionId]}). Skipping re-upload.`);\n  return [];\n}\n\n// \ud83d\udd39 Extract summary text from API response (robustly handle all cases)\nlet raw = $json.data ?? $json.body ?? $json.text ?? $json.mediaSummary ?? '';\nif (typeof raw !== 'string') {\n  try {\n    raw = JSON.stringify(raw, null, 2);\n  } catch (e) {\n    raw = String(raw);\n  }\n}\n\nconst summaryText = raw.trim() || '\u26a0\ufe0f Empty summary received from API';\nconst filename = `session-summary-${sessionId}.txt`;\n\nlet buffer;\ntry {\n  buffer = Buffer.from(summaryText, 'utf8');\n} catch (e) {\n  buffer = Buffer.from('\u26a0\ufe0f Error creating buffer from summary text', 'utf8');\n}\n\nreturn [{\n  json: { filename, sessionId },\n  binary: {\n    data: {\n      data: buffer.toString('base64'),\n      mimeType: 'text/plain',\n      fileName: filename,\n      fileExtension: 'txt'\n    }\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "c0c73a6c-ea0e-44b5-9cd4-133d45e3fa80",
      "name": "Upload Session Summary",
      "type": "n8n-nodes-base.googleDrive",
      "onError": "continueRegularOutput",
      "position": [
        2976,
        600
      ],
      "parameters": {
        "name": "={{ $json.filename }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create Session Folder').first().json.id.trim() }}"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": false,
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "727998b9-3c8e-4764-9cf1-3d683ab91670",
      "name": "\u2139\ufe0f Viewer Tips1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1924,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 740,
        "height": 400,
        "content": "### Get session information\nfluidX API GET /api/revxr/ext/session\n"
      },
      "typeVersion": 1
    },
    {
      "id": "3fe62bc4-ae18-4632-8d41-41f29442b8cc",
      "name": "## Create THE EYE Session",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 1840,
        "height": 400,
        "content": "### Create THE EYE session\nInvite the user via SMS and the agent via email.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "964e64a8-7b21-4cb4-837d-c1aab865590b",
      "name": "\u2139\ufe0f Viewer Tips2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3252,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 590,
        "height": 400,
        "content": "### Retrieve the media information\nfluidX API GET /api/revxr/ext/media/info\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a7c957dd-8d95-484b-b104-61f44550c669",
      "name": "\u2139\ufe0f Viewer Tips3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4000,
        600
      ],
      "parameters": {
        "color": 7,
        "width": 600,
        "height": 343,
        "content": "### Download the image via photoRefs\nUse the photoRefs download URL. If there is no MediaInfo, it is a new image captured on the customer's device.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "ffafc7ec-4972-41fe-9c20-51e5982be325",
      "name": "\u2139\ufe0f Viewer Tips4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4600,
        600
      ],
      "parameters": {
        "color": 7,
        "width": 580,
        "height": 343,
        "content": "### Analyze the image\nUse the `Analyze Image` node (or your preferred vision model) to extract insights.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "536dd4c3-2c3c-49ec-a509-ce9759fb22f6",
      "name": "\u2139\ufe0f Viewer Tips5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5200,
        300
      ],
      "parameters": {
        "color": 7,
        "width": 660,
        "height": 636,
        "content": "### Create Media Info\nfluidX API POST /api/revxr/ext/media/info\nDocument the AI findings back into the session payload.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "bb49376f-7d0f-4528-b255-54f49f577a25",
      "name": "\u2139\ufe0f Viewer Tips6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5875,
        300
      ],
      "parameters": {
        "color": 7,
        "width": 660,
        "height": 636,
        "content": "### Upload image and MediaInfo\nStore both assets in your Google Drive THEEYE folder.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "db283dae-d28f-4c4d-af92-557df597d384",
      "name": "\u2139\ufe0f Viewer Tips7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2680,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 564,
        "height": 400,
        "content": "### Prepare image information\nExtract the image references: download URL and ID.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "8cf50456-15d7-410f-9e63-f0f167e18171",
      "name": "\u2139\ufe0f Viewer Tips9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3334,
        400
      ],
      "parameters": {
        "color": 7,
        "width": 510,
        "height": 364,
        "content": "### The end\nClean up remaining assets and wrap up the session.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "remember-summary-file-12345678",
      "name": "Remember Session Summary File",
      "type": "n8n-nodes-base.code",
      "position": [
        3200,
        600
      ],
      "parameters": {
        "jsCode": "// Track uploaded summary file IDs per session so we only upload once.\nconst store = $getWorkflowStaticData('global');\nif (!store.sessionSummaryFiles || typeof store.sessionSummaryFiles !== 'object') {\n  store.sessionSummaryFiles = {};\n}\n\nconst sessionItems = $items('Set Session Vars', 0, 0);\nconst sessionId = sessionItems[0]?.json?.sessionId || 'unknown-session';\nconst uploadedId = $json?.id;\n\nif (uploadedId) {\n  store.sessionSummaryFiles[sessionId] = uploadedId;\n  console.log(`\ud83d\udcc4 Stored session summary file ${uploadedId} for ${sessionId}`);\n} else {\n  console.log('\u26a0\ufe0f No uploaded summary file ID found \u2013 nothing stored.');\n}\n\nreturn $input.all();\n"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c45e820e-c6f4-4d56-b7df-5b26abb1add6",
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "fluidX API - Get Session Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait1": {
      "main": [
        [
          {
            "node": "fluidX API - Get Session Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "The End": {
      "main": []
    },
    "If photos": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Split photoRefs (Item Lists)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Config": {
      "main": [
        [
          {
            "node": "fluidX API - Create Session",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Media Id": {
      "main": [
        [
          {
            "node": "fluidX API - Media Info HTTP Request GET",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload file": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If new Image": {
      "main": [
        [
          {
            "node": "Check Already Uploaded",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze image": {
      "main": [
        [
          {
            "node": "Merge Analyze + URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build MediaInfo": {
      "main": [
        [
          {
            "node": "fluidX API - Media Info HTTP Request POST",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge photoRefs": {
      "main": [
        [
          {
            "node": "If new Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Carry URL and Id": {
      "main": [
        [
          {
            "node": "Analyze image",
            "type": "main",
            "index": 0
          },
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Analyze + URL",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Set Session Vars": {
      "main": [
        [
          {
            "node": "Create Session Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Session Active": {
      "main": [
        [
          {
            "node": "Extract Media Refs photos",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "fluidX API - Media Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Set Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Analyze + URL": {
      "main": [
        [
          {
            "node": "Build MediaInfo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send email to Agent": {
      "main": [
        [
          {
            "node": "Wait1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Photo Summary": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Create Session Folder": {
      "main": [
        [
          {
            "node": "fluidX API - Send SMS User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Already Uploaded": {
      "main": [
        [
          {
            "node": "fluidX API - Download Photo THEEYE Session",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert Text to Binary": {
      "main": [
        [
          {
            "node": "Upload Photo Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Photo Summary": {
      "main": [
        [
          {
            "node": "Convert Text to Binary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Session Summary": {
      "main": [
        [
          {
            "node": "Remember Session Summary File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Media Refs photos": {
      "main": [
        [
          {
            "node": "If photos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clear Uploaded Photo Store": {
      "main": [
        [
          {
            "node": "The End",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "fluidX API - Media Summary": {
      "main": [
        [
          {
            "node": "Convert Summary Text to Binary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "fluidX API - Send SMS User": {
      "main": [
        [
          {
            "node": "Send email to Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "fluidX API - Create Session": {
      "main": [
        [
          {
            "node": "Set Session Vars",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split photoRefs (Item Lists)": {
      "main": [
        [
          {
            "node": "If Media Id",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge photoRefs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remember Session Summary File": {
      "main": [
        [
          {
            "node": "Clear Uploaded Photo Store",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "fluidX API - Get Session Info": {
      "main": [
        [
          {
            "node": "If Session Active",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert Summary Text to Binary": {
      "main": [
        [
          {
            "node": "Upload Session Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "fluidX API - Media Info HTTP Request GET": {
      "main": [
        [
          {
            "node": "Merge photoRefs",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "fluidX API - Media Info HTTP Request POST": {
      "main": [
        [
          {
            "node": "Generate Photo Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "fluidX API - Download Photo THEEYE Session": {
      "main": [
        [
          {
            "node": "Carry URL and Id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}