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 →
{
"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.
openAiApi
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 →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
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
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.
03 - Recordatorio 4h (CON VERIFICACIÓN) ✅. Uses supabase, httpRequest, twilio. Scheduled trigger; 17 nodes.
02 - Recordatorio 24h antes (CON VERIFICACIÓN) ✅. Uses supabase, httpRequest, twilio. Scheduled trigger; 17 nodes.
How it works: