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 →
{
"name": "Live Tournament Engine (Score \u2192 Telegram Broadcast)",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "match-score-update",
"responseMode": "lastNode",
"options": {}
},
"id": "node-webhook",
"name": "Webhook \u2014 Score Update",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
0,
0
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "cfg-bot-token",
"name": "telegram_bot_token",
"value": "YOUR_TELEGRAM_BOT_TOKEN",
"type": "string"
},
{
"id": "cfg-group-id",
"name": "group_chat_id",
"value": "YOUR_TELEGRAM_GROUP_CHAT_ID",
"type": "string"
},
{
"id": "cfg-tournament-topic",
"name": "tournament_topic_id",
"value": "YOUR_TOURNAMENT_TOPIC_ID",
"type": "string"
},
{
"id": "cfg-secret",
"name": "webhook_secret",
"value": "YOUR_WEBHOOK_SECRET",
"type": "string"
},
{
"id": "cfg-supabase-url",
"name": "supabase_url",
"value": "YOUR_SUPABASE_URL",
"type": "string"
},
{
"id": "cfg-supabase-key",
"name": "supabase_service_key",
"value": "YOUR_SUPABASE_SERVICE_KEY",
"type": "string"
}
]
},
"options": {}
},
"id": "node-config",
"name": "Config",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
224,
0
]
},
{
"parameters": {
"jsCode": "const secret = $('Webhook \u2014 Score Update').item.json.headers['x-n8n-webhook-secret'];\nconst expected = $('Config').item.json.webhook_secret;\n\nif (secret !== expected) {\n throw new Error('Invalid webhook secret');\n}\n\nconst body = $('Webhook \u2014 Score Update').item.json.body;\nconst {\n matchId,\n event, // 'goal', 'card_yellow', 'card_red', 'kickoff', 'halftime', 'fulltime', 'status_change'\n team, // 'home' or 'away'\n homeTeam,\n awayTeam,\n homeScore,\n awayScore,\n playerName,\n minute,\n status\n} = body;\n\nif (!matchId || !event) {\n throw new Error('Missing required fields: matchId, event');\n}\n\nreturn {\n json: {\n matchId,\n event,\n team: team || 'home',\n homeTeam: homeTeam || 'Home',\n awayTeam: awayTeam || 'Away',\n homeScore: homeScore ?? 0,\n awayScore: awayScore ?? 0,\n playerName: playerName || null,\n minute: minute || null,\n status: status || null\n }\n};"
},
"id": "node-parse",
"name": "Parse Event",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
448,
0
]
},
{
"parameters": {
"jsCode": "const e = $('Parse Event').item.json;\n\nconst emoji = {\n goal: '\u26bd',\n card_yellow: '\ud83d\udfe8',\n card_red: '\ud83d\udfe5',\n kickoff: '\ud83c\udfdf\ufe0f',\n halftime: '\u23f8\ufe0f',\n fulltime: '\ud83c\udfc1',\n status_change: '\ud83d\udce2'\n};\n\nconst icon = emoji[e.event] || '\ud83d\udce2';\nlet message = '';\n\nswitch (e.event) {\n case 'goal': {\n const scorer = e.playerName ? ` (${e.playerName})` : '';\n const min = e.minute ? ` ${e.minute}'` : '';\n message = `${icon} <b>GOAL!</b>${min}${scorer}\\n\\n`\n + `<b>${e.homeTeam}</b> [${e.homeScore}] - [${e.awayScore}] <b>${e.awayTeam}</b>`;\n break;\n }\n case 'card_yellow': {\n const player = e.playerName || 'Unknown';\n const min = e.minute ? ` ${e.minute}'` : '';\n message = `${icon} <b>Yellow Card</b>${min} \u2014 ${player} (${e.team === 'home' ? e.homeTeam : e.awayTeam})\\n\\n`\n + `<b>${e.homeTeam}</b> [${e.homeScore}] - [${e.awayScore}] <b>${e.awayTeam}</b>`;\n break;\n }\n case 'card_red': {\n const player = e.playerName || 'Unknown';\n const min = e.minute ? ` ${e.minute}'` : '';\n message = `${icon} <b>Red Card</b>${min} \u2014 ${player} (${e.team === 'home' ? e.homeTeam : e.awayTeam})\\n\\n`\n + `<b>${e.homeTeam}</b> [${e.homeScore}] - [${e.awayScore}] <b>${e.awayTeam}</b>`;\n break;\n }\n case 'kickoff':\n message = `${icon} <b>KICK OFF!</b>\\n\\n<b>${e.homeTeam}</b> vs <b>${e.awayTeam}</b>\\n\\nThe match is underway! \ud83c\udf89`;\n break;\n case 'halftime':\n message = `${icon} <b>HALF TIME</b>\\n\\n<b>${e.homeTeam}</b> [${e.homeScore}] - [${e.awayScore}] <b>${e.awayTeam}</b>`;\n break;\n case 'fulltime':\n message = `${icon} <b>FULL TIME!</b>\\n\\n<b>${e.homeTeam}</b> [${e.homeScore}] - [${e.awayScore}] <b>${e.awayTeam}</b>\\n\\nFinal result confirmed.`;\n break;\n default:\n message = `${icon} <b>Match Update</b>\\n\\n<b>${e.homeTeam}</b> [${e.homeScore}] - [${e.awayScore}] <b>${e.awayTeam}</b>`;\n if (e.status) message += `\\nStatus: ${e.status}`;\n}\n\nreturn { json: { message, matchId: e.matchId } };"
},
"id": "node-format",
"name": "Format Broadcast",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
672,
0
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $('Config').item.json.telegram_bot_token }}/sendMessage",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify({ chat_id: $('Config').item.json.group_chat_id, text: $json.message, parse_mode: 'HTML', message_thread_id: Number($('Config').item.json.tournament_topic_id) || undefined }) }}",
"options": {
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "node-broadcast",
"name": "Broadcast to Tournament Topic",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
880,
0
]
},
{
"parameters": {
"jsCode": "const result = $input.item.json;\nreturn {\n json: {\n success: result.ok === true,\n telegramMessageId: result.ok ? result.result?.message_id : null\n }\n};"
},
"id": "node-response",
"name": "Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1104,
0
]
}
],
"connections": {
"Webhook \u2014 Score Update": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"Config": {
"main": [
[
{
"node": "Parse Event",
"type": "main",
"index": 0
}
]
]
},
"Parse Event": {
"main": [
[
{
"node": "Format Broadcast",
"type": "main",
"index": 0
}
]
]
},
"Format Broadcast": {
"main": [
[
{
"node": "Broadcast to Tournament Topic",
"type": "main",
"index": 0
}
]
]
},
"Broadcast to Tournament Topic": {
"main": [
[
{
"node": "Response",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "Sports"
},
{
"name": "Telegram"
},
{
"name": "Live"
}
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Live Tournament Engine (Score → Telegram Broadcast). Uses httpRequest. Webhook trigger; 6 nodes.
Source: https://github.com/hasancoded/n8n-workflow-templates/blob/main/live-tournament-engine.json — 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.
GiveWP Donations to Beacon. Uses httpRequest, stopAndError. Webhook trigger; 43 nodes.
Remove Video Background & Compose on Custom Image Background with Google Drive. Uses httpRequest, googleDrive. Webhook trigger; 25 nodes.
AI Website Chatbot — Main Handler. Uses httpRequest. Webhook trigger; 22 nodes.
GYRA+ | 2. Receber Decisão → Rotear para CRM. Uses httpRequest. Webhook trigger; 15 nodes.
Voice-Agent Orchestrator (Spec Example - import into n8n and adapt secrets). Uses httpRequest, respondToWebhook. Webhook trigger; 8 nodes.