{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "0dc258f0-4d50-4bbf-9063-b252f597c245",
      "name": "Convert To Markdown",
      "type": "n8n-nodes-base.markdown",
      "position": [
        440,
        -20
      ],
      "parameters": {
        "html": "={{ $('Get Filtered Messages').item.json.textAsHtml }}",
        "options": {},
        "destinationKey": "markdown"
      },
      "typeVersion": 1
    },
    {
      "id": "fced2dd2-720f-4534-a459-94f6cd13314b",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        748,
        200
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4b04a2bf-29a6-42f6-8e72-c264f092780e",
      "name": "Mark as Read",
      "type": "n8n-nodes-base.gmail",
      "position": [
        220,
        -20
      ],
      "parameters": {
        "messageId": "={{ $json.id }}",
        "operation": "markAsRead"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "5c208e16-c987-4bf0-b3f6-27d560b3ce5e",
      "name": "Get Filtered Messages",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        0,
        -20
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "from:(user@example.com) subject:(New job:)"
        },
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyX",
              "unit": "minutes",
              "value": 10
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "6674d03e-91ca-4c6b-8091-b956920e7d9a",
      "name": "Send Slack Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        1860,
        -20
      ],
      "parameters": {
        "text": "=\ud83d\udea8 *New Upwork Job Opportunity!*\n----\n\n*{{ $json.job.jobName.toUpperCase() }}*\n_{{ $json.job.descriptionSnippet }}..._\n\n\ud83d\uddfa\ufe0f {{ $json.job.country }}\n{{ $json.output.paymentVerified ? \"\u2705 Payment verified\" : \"\u274c Payment not verified\"  }}\n\ud83d\udd67 {{ $json.job.jobType }} | {{ $json.job.price }}\n\ud83c\udff7\ufe0f {{ $json.job.tags.map(tag => `\\`${tag}\\``).join(', ') }}\n\u2b50 {{ $json.job.clientRating }}\n\ud83d\udcb0 {{ $json.job.amountSpent }}\n\ud83c\udfc6 {{ $json.job.experienceLevel }}\n\ud83d\udcc6 Posted {{ $json.job.postedAt }}\n\n----\n*AI EVALUATION*\nScore: *{{ $json.evaluation.score }}*\n_{{ $json.evaluation.reasoning }}_\n---\n\n_View this job:_ {{ $json.job.jobDetailUrl }}\n\n",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C090EHUFGEN",
          "cachedResultName": "testing"
        },
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "0b9a8a79-3639-4a83-ac4d-9bbd22adef5e",
      "name": "OpenRouter Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1124,
        200
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e282e1a2-70c7-40ca-a394-33e33976f855",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        1440,
        -20
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "43e777e8-2442-4cc9-8b58-65f1e8f591e5",
              "name": "evaluation",
              "type": "object",
              "value": "={{ $json.output }}"
            },
            {
              "id": "a2c26763-047f-4360-984a-272b88fe3bcc",
              "name": "job",
              "type": "object",
              "value": "={{ $('Job Data Extractor').item.json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "37767da3-90bc-42c5-8fe4-a8d45be89cf3",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 660,
        "height": 460,
        "content": "## Fetch and format emails\n\nHere we use a Gmail search query to find all Upwork job alerts, and format the message body for LLM analysis. An Upwork Freelancer Plus subscription is required in order to receive job alerts.\n\nIMPORTANT: We're polling Gmail for new messages every 10 minutes. This will use a workflow execution each time. You may want to adjust this frequency based on the amount of workflow executions you want to use."
      },
      "typeVersion": 1
    },
    {
      "id": "96107c5a-8311-4836-a51e-09ce43994892",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 460,
        "content": "## Extract data from job\n\nPull out job information like country, price, etc."
      },
      "typeVersion": 1
    },
    {
      "id": "a8e422da-0984-4090-abde-eb2344dc2b28",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1000,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 340,
        "height": 460,
        "content": "## Score the skillset match\n\nREQUIRED: Replace the placeholder text in the prompt between the <my_profile> tags with your own freelancer profile. Be as detailed as possible to achieve the best results."
      },
      "typeVersion": 1
    },
    {
      "id": "51b4e572-fe95-41ca-8ef1-e6638d6cbe8c",
      "name": "Filter By Score",
      "type": "n8n-nodes-base.filter",
      "position": [
        1640,
        -20
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ab20e70f-c9e3-4873-ab6a-e975dffefa35",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $json.evaluation.score }}",
              "rightValue": 7
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "bf621b43-05bd-47c2-bd29-4484400dff62",
      "name": "Opportunity Scorer",
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "position": [
        1040,
        -20
      ],
      "parameters": {
        "text": "=**Situation**\nYou are an expert job matching analyst specializing in freelance opportunities. You'll evaluate the compatibility between my professional profile (skills, experience, and preferences) and Upwork job listings to determine how well we match.\n\n**Task**\nAnalyze the provided Upwork job details against my skills and preferences, then generate a comprehensive match score on a scale of 1-10, where 10 indicates an exceptional match and 1 indicates a poor fit.\n\n**Objective**\nHelp me identify the most suitable job opportunities that align with my capabilities and preferences, saving me time by focusing only on highly compatible positions.\n\n**Knowledge**\n- The job information includes: job name, job type (hourly/fixed), price range, description snippet, country, payment verification status, client rating, amount spent, relevant tags, posting date, and required experience level\n- The description snippet provides limited information about the job requirements\n- Primary matching factors: job name, description snippet, and tags\n- Secondary matching factors: experience level, job type, and payment amount\n- My skills and preferences will be provided in my request\n\nWhen analyzing the match:\n1. Evaluate technical skill alignment based on job name, description snippet, and tags first and foremost\n2. Consider experience level requirements\n3. Factor in my stated job type preferences (hourly vs. fixed), if provided\n4. Account for payment range alignment with my expectations, if provided\n5. Assess if the job description suggests requirements outside my capabilities\n6. Consider any specific preferences I've mentioned (location, industry, etc.)\n\nYou must provide a nuanced, honest assessment of the match quality rather than inflating scores. For each match score, provide brief but specific reasoning explaining why the score was assigned, highlighting both strengths and potential misalignments.\n\n<my_profile>\nREPLACE THIS WITH YOUR PROFILE. BELOW IS AN EXAMPLE PROFILE.\nI\u2019m a seasoned web designer with over 8 years of experience crafting modern, user-friendly websites for startups, agencies, and global brands. My work spans across responsive design, UI/UX optimization, and full website redesigns that prioritize both aesthetic appeal and functional performance. I\u2019m highly proficient with tools like Figma, Adobe XD, Webflow, WordPress, and Shopify, and I frequently collaborate with developers to ensure seamless handoff using platforms like Zeplin or Storybook. Whether you\u2019re looking to improve conversions, refresh your brand\u2019s digital presence, or build something entirely new, I bring a strong design eye, clear communication, and a results-driven approach to every project.\n\nI have a slight preference for hourly projects with a rate about $30/hour. \n</my_profile>\n\n<job>\n{{ JSON.stringify($json.output, null, 2) }}\n</job>",
        "options": {},
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n    \"additionalProperties\": false,\n    \"required\": [\n      \"score\",\n      \"reasoning\"\n    ],\n\t\"properties\": {\n        \"score\": {\n          \"type\": \"integer\",\n          \"minimum\": 1,\n          \"maximum\": 10\n        },\n        \"reasoning\": {\n          \"type\": \"string\"\n        }\n\t}\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "f768b4e4-3eba-41b1-a6aa-c34c14dead7c",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1380,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 620,
        "height": 460,
        "content": "## Send filtered notifications to Slack\n\nHere we only send notifications for jobs that have a match score of 7 or greater, but you can filter the notifications however you'd like. Be sure to select a channel from your workspace in the Slack node."
      },
      "typeVersion": 1
    },
    {
      "id": "ffbe5e44-4e6d-4b88-92cd-042a47fdc77c",
      "name": "Job Data Extractor",
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "position": [
        660,
        -20
      ],
      "parameters": {
        "text": "=Below is a job alert email received from Upwork. Please extract the requested information in valid JSON format.\n\nSubject: {{ $('Get Filtered Messages').item.json.subject }}\nBody: {{ $json.markdown }}",
        "options": {},
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n    \"additionalProperties\": false,\n    \"required\": [\n      \"jobName\",\n      \"jobType\", \n      \"jobDetailUrl\", \n      \"price\", \n      \"descriptionSnippet\", \n      \"country\", \n      \"paymentVerified\",\n      \"clientRating\",\n      \"amountSpent\",\n      \"tags\",\n      \"postedAt\",\n      \"experienceLevel\"\n    ],\n\t\"properties\": {\n        \"jobName\": {\n          \"type\": \"string\"\n        },\n\t\t\"jobType\": {\n\t\t\t\"enum\": [\"Hourly\", \"Fixed\"]\n\t\t},\n        \"price\": {\n          \"type\": \"string\"\n        },\n        \"jobDetailUrl\": {\n          \"type\": \"string\"\n        },\n        \"descriptionSnippet\": {\n          \"type\": \"string\",\n          \"description\": \"The description of the job before the 'more' link\"\n        },\n      \"country\": {\n        \"type\": \"string\"\n      },\n      \"paymentVerified\": {\n        \"type\": \"boolean\"\n      },\n      \"clientRating\": {\n        \"type\": \"number\"\n      },\n      \"amountSpent\": {\n        \"type\": \"string\"\n      },\n      \"tags\": {\n        \"type\": \"array\",\n        \"description\": \"List of categories with a link typically found below the country. Just include the tag name, not the url.\",\n        \"items\": {\n          \"type\": \"string\"\n        }\n      },\n      \"postedAt\": {\n        \"type\": \"string\"\n      },\n      \"experienceLevel\": {\n        \"enum\": [\"Entry\", \"Intermediate\", \"Expert\"]\n      }\n\t}\n}"
      },
      "typeVersion": 1.2
    }
  ],
  "connections": {
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Filter By Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark as Read": {
      "main": [
        [
          {
            "node": "Convert To Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter By Score": {
      "main": [
        [
          {
            "node": "Send Slack Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Job Data Extractor": {
      "main": [
        [
          {
            "node": "Opportunity Scorer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Opportunity Scorer": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert To Markdown": {
      "main": [
        [
          {
            "node": "Job Data Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Filtered Messages": {
      "main": [
        [
          {
            "node": "Mark as Read",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Job Data Extractor",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Opportunity Scorer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}