AutomationFlowsData & Sheets › Monitor Boamp It Tenders and Score Them with Gpt-4o Mini to Supabase

Monitor Boamp It Tenders and Score Them with Gpt-4o Mini to Supabase

Byben daamer @ahmedbendaamer on n8n.io

• Fetches IT-related tenders from the French BOAMP API (filter: informatique) • Scores each tender with OpenAI (pertinence, budget, stack, GO/NO-GO) • Routes to Supabase as hot (≥75) or archived • Run the SQL from the "Supabase Schema" sticky note in the workflow before use

Cron / scheduled trigger★★★★☆ complexity16 nodesHTTP RequestSupabase
Data & Sheets Trigger: Cron / scheduled Nodes: 16 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #13765 — we link there as the canonical source.

This workflow follows the HTTP Request → Supabase recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "w69l72uRokyiUp7g",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Monitor BOAMP IT tenders with AI scoring to Supabase",
  "tags": [],
  "nodes": [
    {
      "id": "61d56904-218d-4d62-87fb-7f21a2b1ba5c",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        976
      ],
      "parameters": {
        "color": 5,
        "width": 520,
        "height": 380,
        "content": "## Monitor BOAMP IT Tenders with AI Scoring\n\n**Who it's for:** ESN, IT consultancies, and agencies monitoring French public tenders (BOAMP) for IT and DevOps opportunities.\n\n**What it does:** Fetches IT-related tenders from the BOAMP API, scores each with OpenAI (pertinence, budget, stack), and routes to Supabase as hot (\u226575) or archived.\n\n**Setup:** Run the SQL in the \"Supabase Schema\" sticky (right) in Supabase SQL Editor. Add OpenAI and Supabase credentials."
      },
      "typeVersion": 1
    },
    {
      "id": "f8747f21-c023-4cbe-aa68-f89613c8952e",
      "name": "Sticky Note 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1216,
        880
      ],
      "parameters": {
        "color": 7,
        "width": 220,
        "height": 140,
        "content": "**Step 1 - Triggers**\n\n\u2022 Schedule: every 4 hours\n\u2022 Manual: for testing\n\u2022 Webhook: external trigger"
      },
      "typeVersion": 1
    },
    {
      "id": "5e40fc30-1cfe-4be0-bc8d-7f705885e759",
      "name": "Sticky Note 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1552,
        1104
      ],
      "parameters": {
        "color": 7,
        "height": 120,
        "content": "**Step 2 - Fetch & Normalize**\n\nBOAMP API (filter: informatique)"
      },
      "typeVersion": 1
    },
    {
      "id": "87efc239-7d64-47c8-91e0-95a2767faa6f",
      "name": "Sticky Note 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2032,
        1056
      ],
      "parameters": {
        "color": 7,
        "width": 360,
        "height": 120,
        "content": "**Step 3\u20135 - AI & Route**\n\nScore \u2192 Parse \u2192 Hot (\u226575) or Archive \u2192 Supabase"
      },
      "typeVersion": 1
    },
    {
      "id": "9fd12931-3b53-4fb0-b294-7fdfdc72eacd",
      "name": "Supabase Schema",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        1376
      ],
      "parameters": {
        "color": 6,
        "width": 360,
        "height": 400,
        "content": "**Supabase Schema** \u2014 Run in Supabase SQL Editor before use:\n\n```sql\nCREATE TABLE IF NOT EXISTS opportunities (\n  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,\n  source TEXT NOT NULL,\n  external_id TEXT NOT NULL,\n  title TEXT,\n  raw_data JSONB,\n  stack_keywords TEXT[],\n  budget_estimated TEXT,\n  score INT DEFAULT 0,\n  summary TEXT,\n  status TEXT DEFAULT 'new' CHECK (status IN ('new','notified','archived')),\n  created_at TIMESTAMPTZ DEFAULT NOW(),\n  UNIQUE(source, external_id)\n);\nCREATE INDEX IF NOT EXISTS idx_opportunities_status ON opportunities(status);\nCREATE INDEX IF NOT EXISTS idx_opportunities_score ON opportunities(score DESC);\nCREATE INDEX IF NOT EXISTS idx_opportunities_created ON opportunities(created_at DESC);\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "62dc5076-fe50-4d04-9292-b2da274dbd69",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "position": [
        1264,
        1408
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1",
              "name": "SCORE_THRESHOLD",
              "type": "number",
              "value": 75
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "aa8a2ee0-b377-492d-b516-0a02f93faa4e",
      "name": "Schedule Every 4 Hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1264,
        1200
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 4
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c9bb673d-b573-422a-8b0c-2944cff3ce90",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        1248,
        1568
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "bd4f9a7a-8bba-4ef7-acd8-7b5ac25a7625",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        1264,
        1056
      ],
      "parameters": {
        "path": "devops-radar-fetch",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "bad3b741-ad9e-48ee-86cd-3c6ffb4c106f",
      "name": "Fetch BOAMP IT Tenders",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1552,
        1296
      ],
      "parameters": {
        "url": "https://boamp-datadila.opendatasoft.com/api/explore/v2.1/catalog/datasets/boamp/records?limit=10&refine=objet:informatique",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "80fb7470-fd15-4248-9d95-1d63f0001a83",
      "name": "Normalize Tender Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1776,
        1296
      ],
      "parameters": {
        "jsCode": "const config = $('Config').first()?.json ?? {};\nconst results = $input.first().json?.results ?? [];\nreturn results.map(r => ({\n  json: {\n    ...config,\n    source: 'BOAMP',\n    external_id: r.idweb ?? r.id ?? '',\n    title: r.objet ?? 'Sans titre',\n    raw_data: r,\n    body: (r.objet ?? '') + ' ' + (r.descripteur_libelle?.join(' ') ?? '') + ' ' + (r.type_marche_facette?.join(' ') ?? '')\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "c98315e9-0fd9-4b55-9ed5-2dfff75c020e",
      "name": "AI Score Tender",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1984,
        1296
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"gpt-4o-mini\",\n  \"messages\": [{\n    \"role\": \"user\",\n    \"content\": \"Analyse cette opportunit\u00e9 B2B IT. R\u00e9ponds en JSON uniquement: {\\\"pertinence\\\":0-100,\\\"budget_estimated\\\":\\\"string\\\",\\\"stack_keywords\\\":[\\\"k1\\\",\\\"k2\\\"],\\\"summary\\\":\\\"5 lignes\\\",\\\"recommendation\\\":\\\"GO|NO_GO\\\"}\\n\\nTitre: {{ $json.title }}\\nCorps: {{ $json.body }}\"\n  }],\n  \"temperature\": 0.2,\n  \"max_tokens\": 500\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "openAiApi"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "86c3a6fa-f09a-4d5f-b297-ea773a11415c",
      "name": "Parse AI Response",
      "type": "n8n-nodes-base.code",
      "position": [
        2208,
        1296
      ],
      "parameters": {
        "jsCode": "const resp = $input.first().json;\nconst content = resp.choices?.[0]?.message?.content ?? resp.message?.content ?? '{}';\nlet parsed = {};\ntry { parsed = JSON.parse(content.replace(/```json?/g,'').replace(/```/g,'').trim()); } catch(e) { parsed = { pertinence: 50 }; }\nconst allNorm = $('Normalize Tender Data').all();\nconst idx = $itemIndex ?? 0;\nconst opp = allNorm[idx]?.json ?? allNorm[0]?.json ?? {};\nconst score = Math.min(100, Math.max(0, parsed.pertinence ?? 50));\nconst threshold = opp.SCORE_THRESHOLD ?? 75;\nreturn { json: { ...opp, ...parsed, score, status: score >= threshold ? 'notified' : 'archived' } };"
      },
      "typeVersion": 2
    },
    {
      "id": "f9d7080e-3e14-4c7d-a896-6fdcc5b4a0e5",
      "name": "Is Hot Opportunity?",
      "type": "n8n-nodes-base.if",
      "position": [
        2432,
        1296
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $json.score }}",
              "rightValue": "={{ $json.SCORE_THRESHOLD ?? 75 }}"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3eefceaa-1b87-4f13-be55-a47bf144a977",
      "name": "Supabase Insert Hot",
      "type": "n8n-nodes-base.supabase",
      "position": [
        2656,
        1200
      ],
      "parameters": {
        "tableId": "opportunities",
        "dataToSend": "autoMapInputData",
        "inputsToIgnore": "SCORE_THRESHOLD"
      },
      "typeVersion": 1
    },
    {
      "id": "f5c96ac0-e63c-49b9-b4ba-926a4cd13f88",
      "name": "Supabase Insert Archived",
      "type": "n8n-nodes-base.supabase",
      "position": [
        2656,
        1392
      ],
      "parameters": {
        "tableId": "opportunities",
        "dataToSend": "autoMapInputData",
        "inputsToIgnore": "SCORE_THRESHOLD"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "b29813be-1c90-4f0a-ba87-a99ab488edbd",
  "connections": {
    "Config": {
      "main": [
        [
          {
            "node": "Fetch BOAMP IT Tenders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Score Tender": {
      "main": [
        [
          {
            "node": "Parse AI Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Response": {
      "main": [
        [
          {
            "node": "Is Hot Opportunity?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Hot Opportunity?": {
      "main": [
        [
          {
            "node": "Supabase Insert Hot",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Supabase Insert Archived",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Tender Data": {
      "main": [
        [
          {
            "node": "AI Score Tender",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch BOAMP IT Tenders": {
      "main": [
        [
          {
            "node": "Normalize Tender Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Every 4 Hours": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

• Fetches IT-related tenders from the French BOAMP API (filter: informatique) • Scores each tender with OpenAI (pertinence, budget, stack, GO/NO-GO) • Routes to Supabase as hot (≥75) or archived • Run the SQL from the "Supabase Schema" sticky note in the workflow before use

Source: https://n8n.io/workflows/13765/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

This workflow solves a common problem with RSS feeds: they often only provide a short summary or snippet of the full article. This template automatically monitors a list of your favorite blog RSS feed

HTTP Request, RSS Feed Read, Supabase
Data & Sheets

This workflow is a multi-system document synchronization pipeline built in n8n, designed to automatically sync and back up files between Microsoft SharePoint, Supabase/Postgres, and Google Drive.

HTTP Request, Supabase, Postgres +1
Data & Sheets

03 - Recordatorio 4h (CON VERIFICACIÓN) ✅. Uses supabase, httpRequest, twilio. Scheduled trigger; 17 nodes.

Supabase, HTTP Request, Twilio
Data & Sheets

02 - Recordatorio 24h antes (CON VERIFICACIÓN) ✅. Uses supabase, httpRequest, twilio. Scheduled trigger; 17 nodes.

Supabase, HTTP Request, Twilio
Data & Sheets

How it works:

HTTP Request, Supabase, N8N Nodes Influencersclub