{
  "id": "p4mLhWtfc6yPrTwC",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "(Retail) Auto-Sync New Orders to Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "4c43c050-482d-4594-a5a0-405c40063680",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        256,
        -112
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "gpt-4.1-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "900c409e-6239-4bf3-9e48-8458e6375332",
      "name": "Run Workflow Every Few Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -960,
        -224
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "b1aa6465-64c1-4139-bb24-26b03a08dc10",
      "name": "Get Last Successful Sync Time",
      "type": "n8n-nodes-base.code",
      "position": [
        -704,
        -224
      ],
      "parameters": {
        "jsCode": "// Access global static data\nconst data = $getWorkflowStaticData('global');\n\n// If no lastSync exists, default to the start of today\nif (!data.lastSync) {\n  // Use today's date dynamically\n  const today = new Date();\n  today.setHours(0, 0, 0, 0); // start of today\n  data.lastSync = today.toISOString();\n}\n\n// Pass lastSync to next node\nreturn [\n  {\n    lastSync: data.lastSync\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6480be0d-ec9c-42d0-946f-9db40078c7c4",
      "name": "Fetch Orders from Shopify",
      "type": "n8n-nodes-base.shopify",
      "position": [
        -480,
        -224
      ],
      "parameters": {
        "options": {
          "status": "any",
          "createdAtMin": "={{ $json.lastSync }}"
        },
        "operation": "getAll",
        "authentication": "accessToken"
      },
      "credentials": {
        "shopifyAccessTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d6427105-9c4e-4594-8484-c8052505f1d5",
      "name": "Mark Orders as New or Old",
      "type": "n8n-nodes-base.code",
      "position": [
        -256,
        -224
      ],
      "parameters": {
        "jsCode": "const data = $getWorkflowStaticData('global');\nconst lastSync = data.lastSync\n  ? new Date(data.lastSync)\n  : new Date('2025-01-01T00:00:00Z');\n\nconst createdAt = new Date($json.created_at);\n\n// Add a flag but KEEP the order\nreturn [\n  {\n    ...$json,\n    isNewOrder: createdAt > lastSync\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "02c2ad8f-d05a-4d90-9389-8bd3d8a924b2",
      "name": "Is This a New Order?",
      "type": "n8n-nodes-base.if",
      "position": [
        -64,
        -224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e682d16c-adc8-4056-8c7d-868adc964ea0",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isNewOrder }}",
              "rightValue": "true"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f167cc80-ca9b-457e-bfae-00e3cdff174d",
      "name": "AI Order Analysis",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        256,
        -368
      ],
      "parameters": {
        "text": "=Analyze this Shopify order.\n\nProduct name: {{ $json.fulfillments[0].line_items[0].name }}\nQuantity: {{ $json.fulfillments[0].line_items[0].quantity }}\nTotal price: {{ $json.total_price }}\nCurrency: {{ $json.currency }}\nCountry: {{ $json.shipping_country || 'Unknown' }}\n\nReturn JSON with:\n- category\n- priority\n- internal_note\n",
        "options": {
          "systemMessage": "You are an API.\nReturn ONLY raw JSON.\nDo not use markdown.\nDo not use ``` fences."
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "e28db2e1-e15a-4e27-9a0b-03f62eb62997",
      "name": "Prepare Final Order Data",
      "type": "n8n-nodes-base.set",
      "position": [
        800,
        -368
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "566b6add-9f2e-42dc-a9c0-3151eabf0077",
              "name": "id",
              "type": "number",
              "value": "={{ $('Is This a New Order?').item.json.id }}"
            },
            {
              "id": "debd4cc8-2465-46a1-82fa-37a39015fbaa",
              "name": "order_number",
              "type": "string",
              "value": "={{ $('Is This a New Order?').item.json.order_number }}"
            },
            {
              "id": "8e8657bb-7087-4aad-bb1a-72421313d096",
              "name": "order_created_at",
              "type": "string",
              "value": "={{ $('Is This a New Order?').item.json.created_at }}"
            },
            {
              "id": "726f107e-112c-45b1-95f0-b39021e474f7",
              "name": "subtotal_price",
              "type": "string",
              "value": "={{ $('Is This a New Order?').item.json.current_subtotal_price }}"
            },
            {
              "id": "594b12a4-d764-4645-a267-a34e9f63835d",
              "name": "total_price",
              "type": "string",
              "value": "={{ $('Is This a New Order?').item.json.current_total_price }}"
            },
            {
              "id": "50282f7c-ca72-46a1-b97b-24fb19616dc7",
              "name": "currency",
              "type": "string",
              "value": "={{ $('Is This a New Order?').item.json.customer.currency }}"
            },
            {
              "id": "671c6e81-1c53-4c6f-95aa-ed8f262e8f3e",
              "name": "product_name",
              "type": "string",
              "value": "={{ $('Is This a New Order?').item.json.fulfillments[0].line_items[0].name }}"
            },
            {
              "id": "5a6ba725-499a-41e0-a0c4-c8b0e3ec62ee",
              "name": "quantity",
              "type": "number",
              "value": "={{ $('Is This a New Order?').item.json.fulfillments[0].line_items[0].current_quantity }}"
            },
            {
              "id": "cc510cc2-b56a-40da-8233-e811b1de5242",
              "name": "=synced_at",
              "type": "string",
              "value": "={{$now}}"
            },
            {
              "id": "42993ffd-994d-4a01-be93-bb14a9f5e39e",
              "name": "shipping_country",
              "type": "string",
              "value": "={{ $json.shipping_address?.country || '' }}"
            },
            {
              "id": "74c97ea5-2228-4fa6-8544-aa124de71bee",
              "name": "category",
              "type": "string",
              "value": "={{ $json.category }}"
            },
            {
              "id": "f3561296-4feb-481d-91ac-beabb9703901",
              "name": "Priority",
              "type": "string",
              "value": "={{ $json.priority }}"
            },
            {
              "id": "59b0d67c-5b99-43f2-b550-d6ff6e16418f",
              "name": "note",
              "type": "string",
              "value": "={{ $json.internal_note }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "9bd7464b-df2e-4e13-a47e-c001ba1634ee",
      "name": "Convert AI Response to Data",
      "type": "n8n-nodes-base.code",
      "position": [
        576,
        -368
      ],
      "parameters": {
        "jsCode": "// AI returns JSON as string inside \"output\"\nconst parsed = JSON.parse($json.output);\n\n// Return parsed JSON as normal item\nreturn [\n  {\n    ...parsed\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "d1674778-2940-416e-99f7-566bf6d44a98",
      "name": "Save Order to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1024,
        -368
      ],
      "parameters": {
        "columns": {
          "value": {
            "Id": "={{ $json.id }}",
            "currency": "={{ $json.currency }}",
            "quantity": "={{ $json.quantity }}",
            "Synced_at": "={{ $json.synced_at }}",
            "total_price": "={{ $json.total_price }}",
            "Order Number": "={{ $json.order_number }}",
            "product_name": "={{ $json.product_name }}",
            "order_created": "={{ $json.order_created_at }}",
            "subtotal_price": "={{ $json.subtotal_price }}",
            "shipping_country": "={{ $json.shipping_country }}"
          },
          "schema": [
            {
              "id": "Id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Order Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Order Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "order_created",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "order_created",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "subtotal_price",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "subtotal_price",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "total_price",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "total_price",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "product_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "product_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "quantity",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "quantity",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "shipping_country",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "shipping_country",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Synced_at",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Synced_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 546571416,
          "cachedResultUrl": "#",
          "cachedResultName": "Shopify_order_data"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1TkODFnQS4sw8-ullt0U34aph2FMLteyUJvUYC6GarI0",
          "cachedResultUrl": "#",
          "cachedResultName": "New Order Track"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "857dd76a-f0c2-4ba8-9387-0cfe5d880b75",
      "name": "Update Sync Time",
      "type": "n8n-nodes-base.code",
      "position": [
        1232,
        -368
      ],
      "parameters": {
        "jsCode": "const data = $getWorkflowStaticData('global');\ndata.lastSync = new Date().toISOString();\nreturn items;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "939ebcf3-a00a-4a7c-9015-327db5e5336b",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1040,
        -352
      ],
      "parameters": {
        "color": 7,
        "height": 288,
        "content": "This node starts the workflow automatically every few minutes.\nIt checks Shopify regularly for new orders without manual effort."
      },
      "typeVersion": 1
    },
    {
      "id": "b6944e38-6b02-43c9-a69a-02525f6dd3e9",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -784,
        -352
      ],
      "parameters": {
        "color": 7,
        "height": 288,
        "content": "This node remembers the last time orders were successfully synced.\nIt helps avoid fetching the same order again and again."
      },
      "typeVersion": 1
    },
    {
      "id": "54fddf9b-d7a6-4066-af06-87dd593ce5e8",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -528,
        -464
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 432,
        "content": "## New Order Detection Process\n\nThis section detects only new Shopify orders.\nOrders are fetched based on the last successful sync time.\nEach order\u2019s creation time is compared with the stored sync value.\nOnly newly created orders are allowed to continue in the workflow.\nPreviously processed orders are ignored to avoid duplicates."
      },
      "typeVersion": 1
    },
    {
      "id": "d6e47373-e768-4736-8978-24b3f5e99b45",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        112,
        -576
      ],
      "parameters": {
        "color": 7,
        "width": 1312,
        "height": 592,
        "content": "## Order Processing & Storage\nOnce a new order is detected, this part of the workflow takes over.\nThe AI reviews the order to understand its importance and category.\nThe order data is then cleaned, organized, and prepared properly.\nFinally, the order is saved to Google Sheets and the sync time is updated.\nThis ensures every order is processed only once and stored safely."
      },
      "typeVersion": 1
    },
    {
      "id": "2755d6f0-8610-41d1-96e0-e6abf7b905d7",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1728,
        -976
      ],
      "parameters": {
        "width": 480,
        "height": 752,
        "content": "## How it works \n\nThis workflow automatically checks Shopify for new orders at regular intervals.\nIt remembers the last time it successfully ran and only looks for orders created after that time, so the same order is never processed twice.\n\nWhen a new order is found, the workflow extracts important order details such as product name, price, quantity, and shipping country.\nAn AI step then reviews the order to determine its category, priority level, and adds internal notes for quick understanding.\n\nAfter analysis, all order data is cleaned and organized into a final format.\nThe completed order is saved to Google Sheets as a new row.\nOnce everything is saved successfully, the workflow updates the last sync time, ensuring future runs only fetch newer orders.\n\nIf no new orders are found, the workflow safely stops without errors.\n\n\n## Setup steps\n\n**1.** Connect your Shopify credentials to the Shopify node.\n\n**2.** Set the Schedule Trigger to decide how often orders should be checked.\n\n**3.** Connect your Google Sheets account and select the target sheet.\n\n**4.** Review the AI prompt if you want to customize order analysis.\n\n**5.** Run the workflow once manually to initialize the first sync time.\n\nAfter setup, the workflow runs automatically with no manual effort."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "184de817-b3ed-4bc8-aa07-68f23f7f9c25",
  "connections": {
    "Update Sync Time": {
      "main": [
        []
      ]
    },
    "AI Order Analysis": {
      "main": [
        [
          {
            "node": "Convert AI Response to Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Order Analysis",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Is This a New Order?": {
      "main": [
        [
          {
            "node": "AI Order Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Final Order Data": {
      "main": [
        [
          {
            "node": "Save Order to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Orders from Shopify": {
      "main": [
        [
          {
            "node": "Mark Orders as New or Old",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Orders as New or Old": {
      "main": [
        [
          {
            "node": "Is This a New Order?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Order to Google Sheet": {
      "main": [
        [
          {
            "node": "Update Sync Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert AI Response to Data": {
      "main": [
        [
          {
            "node": "Prepare Final Order Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Last Successful Sync Time": {
      "main": [
        [
          {
            "node": "Fetch Orders from Shopify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Workflow Every Few Minutes": {
      "main": [
        [
          {
            "node": "Get Last Successful Sync Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}