{
  "meta": {
    "versionId": "1.0.0",
    "createdAt": "2025-09-29T07:07:58.593805",
    "updatedAt": "2025-09-29T07:07:58.593837",
    "owner": "n8n-user",
    "license": "MIT",
    "category": "automation",
    "status": "active",
    "priority": "high",
    "environment": "production"
  },
  "nodes": [
    {
      "id": "4fe13927-84cb-4227-9daa-d6cef72d10b9",
      "name": "CarrierNameLookup",
      "type": "n8n-nodes-base.code",
      "position": [
        740,
        320
      ],
      "parameters": {
        "jsCode": "var carrierCodes={}\nJSON.parse($('Get Carrier Codes').first().json.data).data.forEach(datum=>{\n  carrierCodes[datum.iataCode] = {icao:datum.icaoCode, name:datum.commonName}\n})\nreturn carrierCodes"
      },
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "cb0ab93c-5fc5-402d-8ac9-672960b14112",
      "name": "Gmail",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2080,
        400
      ],
      "parameters": {
        "message": "=Hi! We just found a bargain flight:\nDeparture Time: {{ $json.time }}\n[{{ $json.legs[0].carrier }}] {{ $json.duration }} flight from {{ $('FromTo').first().json.from }} to {{ $('FromTo').first().json.to }}\n",
        "options": {},
        "subject": "=Bargain Flight Found! {{ $('FromTo').first().json.from }} -> {{ $('FromTo').first().json.to }} @ {{ $json.price }} on {{ $json.time }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1,
      "notes": "This gmail node performs automated tasks as part of the workflow."
    },
    {
      "id": "2f98b3e2-8a25-496e-89f3-b1ebe7e33192",
      "name": "Get Dates",
      "type": "n8n-nodes-base.code",
      "position": [
        940,
        300
      ],
      "parameters": {
        "jsCode": "const getNextSevenDays = () => {\n    const dates = [];\n    const today = new Date();\n\n    for (const i of [7, 14]) {\n        const nextDate = new Date(today);\n        nextDate.setDate(today.getDate() + i);\n        \n        // Format the date as YYYY-MM-DD\n        const formattedDate = nextDate.toISOString().split('T')[0];\n        dates.push({date:formattedDate});\n    }\n\n    return dates;\n};\n\nreturn getNextSevenDays()"
      },
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "3d8cf3fa-6ce7-422a-978f-afe2884c1e1a",
      "name": "Merge & Extract",
      "type": "n8n-nodes-base.code",
      "position": [
        1660,
        400
      ],
      "parameters": {
        "jsCode": "//Merge\nresult = []\nfor (const item of $input.all()) {\n result = result.concat(JSON.parse(item.json.data).data)\n}\n\n//Extract data fields\nfinal_result = []\nfor (x of result){\n  let legs = x.itineraries[0].segments.map(y=>{\n          let a = $('CarrierNameLookup').item.json[y.carrierCode];\n           let carrier = a.name? a.name: a.icao;\n           return {carrier:carrier, duration:y.duration}})\n\n\n  console.log(x.itineraries[0].segments[0].departure.at)\n  let duration = x.itineraries[0].duration\n  let price = x.price.total+' '+x.price.currency\n\n  final_result.push({legs:legs, time:x.itineraries[0].segments[0].departure.at, duration:duration, price:price})\n}\n\nreturn final_result"
      },
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "89df1c9b-c863-4cf5-88a2-18793d542f02",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1200,
        240
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3,
      "notes": "This splitInBatches node performs automated tasks as part of the workflow."
    },
    {
      "id": "5595e34d-3736-42f6-ad64-e7f3c72c7f0a",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        1060,
        440
      ],
      "parameters": {
        "amount": 3
      },
      "typeVersion": 1.1,
      "notes": "This wait node performs automated tasks as part of the workflow."
    },
    {
      "id": "550005ad-ea97-4d83-90ac-67c7c583f2dc",
      "name": "Under Price",
      "type": "n8n-nodes-base.filter",
      "position": [
        1880,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "bc2a9b61-41eb-45b1-9ee3-00fe211dadc3",
              "operator": {
                "type": "number",
                "operation": "lt"
              },
              "leftValue": "={{ parseFloat($json.price) }}",
              "rightValue": 600
            }
          ]
        }
      },
      "typeVersion": 2.1,
      "notes": "This filter node performs automated tasks as part of the workflow."
    },
    {
      "id": "ce1beef1-4189-4cd7-b8c6-dd5bef2d9963",
      "name": "FromTo",
      "type": "n8n-nodes-base.set",
      "position": [
        560,
        320
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1944c696-6cfd-4d4d-8f3d-31cb89b37d3d",
              "name": "from",
              "type": "string",
              "value": "LHR"
            },
            {
              "id": "9c4d5ac9-fa75-4fa7-a369-2b0493150203",
              "name": "to",
              "type": "string",
              "value": "JFK"
            }
          ]
        }
      },
      "typeVersion": 3.4,
      "notes": "This set node performs automated tasks as part of the workflow."
    },
    {
      "id": "a4956257-28ce-4014-b549-ad413264c012",
      "name": "Amadeus Flight Search",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1340,
        440
      ],
      "parameters": {
        "url": "{{ $env.API_BASE_URL }}",
        "options": {},
        "sendQuery": true,
        "authentication": "{{ $credentials.genericCredentialType }}",
        "genericAuthType": "oAuth2Api",
        "queryParameters": {
          "parameters": [
            {
              "name": "originLocationCode",
              "value": "={{ $('FromTo').item.json.from }}"
            },
            {
              "name": "destinationLocationCode",
              "value": "={{ $('FromTo').item.json.to }}"
            },
            {
              "name": "adults",
              "value": "1"
            },
            {
              "name": "departureDate",
              "value": "={{ $json.date }}"
            }
          ]
        }
      },
      "credentials": {
        "oAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "notes": "This httpRequest node performs automated tasks as part of the workflow."
    },
    {
      "id": "b7a41d45-799d-4f65-a904-f8fa82e59620",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        260,
        -320
      ],
      "parameters": {
        "width": 490.02125360646824,
        "height": 538.1571460797832,
        "content": "# Amadeus Flight Bargains\nEvery day checks for bargain flights for an itinerary and price target of your choosing, and emails you if it finds a match.\n\n## Setup\n1. Create an api account on {{ $env.WEBHOOK_URL }}\n2. In **Amadeus Flight Search**, connect to Oauth2 API:\n  -- Grant Type - Client Credentials\n  -- Access Token URL - {{ $env.API_BASE_URL }}\n  -- Client ID/Secret - from your account\n3. Set your details in **Gmail**\n4. Set your desired Origin/Destination airports in FromTo\n5. Set the dates ahead you wish to search in **Get Dates** (default is 7 days and 14 days)\n6. Set the price target in **Under Price**\n\n## Test\nHit 'Test workflow'!"
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "88126395-c96a-4905-87db-57ad19cead23",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        360,
        320
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.2,
      "notes": "This scheduleTrigger node performs automated tasks as part of the workflow."
    },
    {
      "id": "0fa74451-6053-470c-b5c5-9b25fd2e5b55",
      "name": "Get Carrier Codes",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        360,
        600
      ],
      "parameters": {
        "url": "{{ $env.API_BASE_URL }}",
        "options": {},
        "authentication": "{{ $credentials.genericCredentialType }}",
        "genericAuthType": "oAuth2Api"
      },
      "credentials": {
        "oAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "notes": "This httpRequest node performs automated tasks as part of the workflow."
    }
  ],
  "connections": {
    "Amadeus Flight Search": {
      "main": [
        [],
        [],
        [],
        [],
        [],
        [],
        [],
        [],
        []
      ]
    },
    "Get Carrier Codes": {
      "main": [
        [],
        [],
        [],
        [],
        [],
        [],
        [],
        [],
        []
      ]
    }
  },
  "name": "Code Workflow",
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": null,
    "timezone": "UTC",
    "executionTimeout": 3600,
    "maxExecutions": 1000,
    "retryOnFail": true,
    "retryCount": 3,
    "retryDelay": 1000
  },
  "description": "Automated workflow: Code Workflow. This workflow integrates 10 different services: filter, httpRequest, stickyNote, wait, code. It contains 16 nodes and follows best practices for error handling and security.",
  "notes": "Excellent quality workflow: Code Workflow. This workflow has been optimized for production use with comprehensive error handling, security, and documentation.",
  "id": "wfad7908325de9"
}