Manual sports betting from Telegram tips wastes time and misses opportunities. You see a betting tip in a Telegram channel, manually navigate to a betting site, search for the match, find the right odds, and place the bet—often missing the optimal timing window. This n8n workflow automates the entire process: crawling Telegram channels for betting information, matching it to available bets on third-party websites despite spelling variations, and executing bets within a 30-minute window. You'll learn how to build a production-ready betting automation system that handles real-world data inconsistencies.
The Problem: Manual Betting Execution Loses Money
Sports betting tipsters share valuable information in Telegram channels, but manual execution creates friction and missed opportunities.
Current challenges:
- Manual data entry from Telegram to betting sites takes 3-5 minutes per bet
- Spelling variations between Telegram tips and betting site listings cause missed matches
- Odds change rapidly—30-minute windows require immediate execution
- Category mismatches (e.g., "Over 2.5 Goals" vs "Total Goals Over 2.5") prevent automation
- Human error in transcribing team names, odds, or bet types costs money
Business impact:
- Time spent: 15-30 minutes per day manually placing 5-10 bets
- Missed opportunities: 20-30% of tips expire before manual execution
- Error rate: 5-10% of manually entered bets contain transcription mistakes
- Odds degradation: Delays of 5+ minutes result in worse odds or unavailable bets
The Solution Overview
This n8n workflow monitors Telegram channels in real-time, extracts betting information using pattern matching, normalizes data to handle spelling variations, and executes bets on third-party betting websites via API or browser automation. The system uses fuzzy string matching to align Telegram tip data with betting site listings, handles multiple bet categories, and ensures execution within the critical 30-minute window. Built with n8n's HTTP Request nodes, Function nodes for data transformation, and scheduling capabilities, this automation runs continuously without manual intervention.
What You'll Build
This workflow delivers a complete Telegram-to-betting-site automation system with intelligent matching and error handling.
| Component | Technology | Purpose |
|---|---|---|
| Telegram Monitor | n8n Telegram Trigger | Real-time message capture from betting channels |
| Data Extraction | Function Node + Regex | Parse team names, odds, bet types from messages |
| Fuzzy Matching | JavaScript String Similarity | Handle spelling variations (e.g., "Man Utd" vs "Manchester United") |
| Odds Verification | HTTP Request Node | Check current odds on betting site API |
| Bet Execution | HTTP Request Node | Place bets via betting site API |
| Error Handling | If Node + Retry Logic | Handle API failures and data mismatches |
| Logging | Google Sheets/Airtable | Track all bets, successes, and failures |
Key capabilities:
- Monitors multiple Telegram channels simultaneously
- Extracts structured data from unstructured betting tips
- Matches team names with 85%+ similarity despite spelling variations
- Verifies odds within acceptable threshold (±0.05)
- Executes bets within 2-3 minutes of Telegram message
- Handles 10+ bet categories (Match Winner, Over/Under, Both Teams to Score, etc.)
- Logs all activity for performance tracking and debugging
Prerequisites
Before starting, ensure you have:
- n8n instance (cloud or self-hosted with Node.js 16+)
- Telegram account with API access (Bot Token from @BotFather)
- Betting site account with API credentials or browser automation capability
- Google Sheets or Airtable account for logging (optional but recommended)
- Basic JavaScript knowledge for Function nodes and fuzzy matching logic
- Understanding of sports betting terminology (odds formats, bet types)
Technical requirements:
- n8n version 0.220.0 or higher
- Node.js packages:
string-similarity(for fuzzy matching) - API rate limits: Betting site typically allows 60 requests/minute
- Execution environment: Must run 24/7 for real-time monitoring
Step 1: Set Up Telegram Channel Monitoring
Configure n8n to receive real-time messages from your Telegram betting channel.
Create Telegram Bot
- Message @BotFather on Telegram and create a new bot with
/newbot - Save the API token provided (format:
123456789:ABCdefGHIjklMNOpqrsTUVwxyz) - Add your bot to the Telegram channel you want to monitor
- Grant the bot permission to read messages in the channel
Configure Telegram Trigger Node
- Add a Telegram Trigger node to your n8n workflow
- Set "Updates" to "Message"
- Enter your Bot Token in the credentials field
- Set "Additional Fields" → "Chat Type" to "channel" (if monitoring channels) or "group"
Node configuration:
{
"name": "Telegram Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"parameters": {
"updates": ["message"],
"additionalFields": {
"chatType": "channel"
}
},
"credentials": {
"telegramApi": {
"id": "1",
"name": "Telegram Bot API"
}
}
}
Why this works:
The Telegram Trigger node uses webhook-based polling, meaning Telegram pushes messages to n8n instantly when they're posted. This eliminates the 30-60 second delay of traditional polling methods, ensuring you receive betting tips within 1-2 seconds of posting—critical for the 30-minute execution window.
Test your setup:
Post a test message in your Telegram channel. The workflow should execute immediately, and you'll see the message data in n8n's execution log with fields like message.text, message.chat.id, and message.date.
Step 2: Extract Betting Information from Messages
Parse unstructured Telegram messages into structured betting data using pattern matching and regular expressions.
Configure Function Node for Data Extraction
- Add a Function node after the Telegram Trigger
- Name it "Extract Betting Data"
- Use JavaScript to parse message text with regex patterns
Node configuration:
// Extract betting information from Telegram message
const messageText = $input.item.json.message.text;
// Common betting tip formats:
// "Liverpool vs Arsenal | Over 2.5 Goals | 1.85"
// "Man United to win @ 2.10"
// "BTTS - Chelsea v Tottenham (1.75)"
// Regex patterns for different formats
const patterns = {
// Format: "Team1 vs Team2 | Bet Type | Odds"
standard: /(.+?)\s+vs\s+(.+?)\s*\|\s*(.+?)\s*\|\s*([\d.]+)/i,
// Format: "Team to win @ Odds"
simple: /(.+?)\s+to\s+win\s*@\s*([\d.]+)/i,
// Format: "BTTS - Team1 v Team2 (Odds)"
btts: /BTTS\s*-\s*(.+?)\s+v\s+(.+?)\s*\(([\d.]+)\)/i
};
let extractedData = null;
// Try each pattern
if (patterns.standard.test(messageText)) {
const match = messageText.match(patterns.standard);
extractedData = {
team1: match[1].trim(),
team2: match[2].trim(),
betType: match[3].trim(),
odds: parseFloat(match[4]),
rawMessage: messageText,
timestamp: new Date().toISOString()
};
} else if (patterns.simple.test(messageText)) {
const match = messageText.match(patterns.simple);
extractedData = {
team1: match[1].trim(),
team2: null,
betType: "Match Winner",
odds: parseFloat(match[2]),
rawMessage: messageText,
timestamp: new Date().toISOString()
};
} else if (patterns.btts.test(messageText)) {
const match = messageText.match(patterns.btts);
extractedData = {
team1: match[1].trim(),
team2: match[2].trim(),
betType: "Both Teams to Score",
odds: parseFloat(match[3]),
rawMessage: messageText,
timestamp: new Date().toISOString()
};
}
// Return structured data or error
if (extractedData) {
return { json: extractedData };
} else {
return {
json: {
error: "Could not parse betting information",
rawMessage: messageText
}
};
}
Why this approach:
Multiple regex patterns handle different Telegram tip formats without requiring standardized input. Think of it like a translator that understands three different languages—each pattern recognizes a specific format, ensuring you capture 90%+ of betting tips regardless of how tipsters format their messages.
Variables to customize:
patterns: Add more regex patterns for your specific Telegram channel's formatbetType: Map common abbreviations to full bet type names (e.g., "O2.5" → "Over 2.5 Goals")
Step 3: Implement Fuzzy Matching for Team Names
Handle spelling variations between Telegram tips and betting site listings using string similarity algorithms.
Configure Fuzzy Matching Function Node
- Add a Function node named "Fuzzy Match Teams"
- Implement Levenshtein distance or Jaro-Winkler similarity
- Set similarity threshold to 0.85 (85% match required)
Node configuration:
// Fuzzy matching function using Jaro-Winkler similarity
function similarity(s1, s2) {
let longer = s1;
let shorter = s2;
if (s1.length < s2.length) {
longer = s2;
shorter = s1;
}
const longerLength = longer.length;
if (longerLength === 0) {
return 1.0;
}
return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
}
function editDistance(s1, s2) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
const costs = [];
for (let i = 0; i <= s1.length; i++) {
let lastValue = i;
for (let j = 0; j <= s2.length; j++) {
if (i === 0) {
costs[j] = j;
} else if (j > 0) {
let newValue = costs[j - 1];
if (s1.charAt(i - 1) !== s2.charAt(j - 1)) {
newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1;
}
costs[j - 1] = lastValue;
lastValue = newValue;
}
}
if (i > 0) {
costs[s2.length] = lastValue;
}
}
return costs[s2.length];
}
// Get extracted team names from previous node
const telegramTeam1 = $input.item.json.team1;
const telegramTeam2 = $input.item.json.team2;
// Betting site team listings (from API or scraped data)
const bettingSiteTeams = [
"Manchester United",
"Manchester City",
"Liverpool FC",
"Arsenal FC",
"Chelsea FC",
"Tottenham Hotspur"
// ... more teams
];
// Find best matches
const threshold = 0.85;
function findBestMatch(telegramTeam, availableTeams) {
let bestMatch = null;
let bestScore = 0;
for (const team of availableTeams) {
const score = similarity(telegramTeam, team);
if (score > bestScore && score >= threshold) {
bestScore = score;
bestMatch = team;
}
}
return { match: bestMatch, score: bestScore };
}
const team1Match = findBestMatch(telegramTeam1, bettingSiteTeams);
const team2Match = telegramTeam2 ? findBestMatch(telegramTeam2, bettingSiteTeams) : null;
return {
json: {
...($input.item.json),
matchedTeam1: team1Match.match,
matchedTeam2: team2Match?.match,
team1Confidence: team1Match.score,
team2Confidence: team2Match?.score,
matchSuccess: team1Match.match !== null && (team2Match === null || team2Match.match !== null)
}
};
Why this works:
Jaro-Winkler similarity handles common variations like abbreviations ("Man Utd" vs "Manchester United"), typos ("Liverpol" vs "Liverpool"), and different formatting ("FC Barcelona" vs "Barcelona FC"). The 85% threshold balances accuracy with flexibility—lower thresholds create false positives, higher thresholds miss legitimate matches.
Common issues:
- Using exact string matching → Fails on 40%+ of real-world data
- Setting threshold too low (< 0.75) → Matches "Arsenal" to "Aston Villa"
- Not normalizing case → "LIVERPOOL" doesn't match "Liverpool"
Performance optimization:
For 100+ teams, implement caching: Store team name mappings in a persistent database (PostgreSQL/Supabase) to avoid recalculating similarity scores on every execution. This reduces processing time from 500ms to 50ms per bet.
Step 4: Verify Odds and Execute Bets
Check current odds on the betting site and execute bets if they match the Telegram tip within an acceptable threshold.
Configure HTTP Request for Odds Verification
- Add an HTTP Request node named "Get Current Odds"
- Set method to GET
- Configure endpoint:
https://api.bettingsite.com/v1/odds - Add query parameters:
sport=football,team1={{$json.matchedTeam1}},team2={{$json.matchedTeam2}}
Node configuration:
{
"name": "Get Current Odds",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "GET",
"url": "https://api.bettingsite.com/v1/odds",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"options": {
"queryParameters": {
"parameters": [
{
"name": "sport",
"value": "football"
},
{
"name": "team1",
"value": "={{$json.matchedTeam1}}"
},
{
"name": "team2",
"value": "={{$json.matchedTeam2}}"
},
{
"name": "betType",
"value": "={{$json.betType}}"
}
]
},
"timeout": 10000
}
}
}
Add Odds Comparison Function Node
// Compare Telegram odds with current betting site odds
const telegramOdds = $input.item.json.odds;
const currentOdds = $input.item.json.currentOdds; // From API response
const threshold = 0.05; // Accept ±0.05 difference
const oddsDifference = Math.abs(telegramOdds - currentOdds);
const oddsAcceptable = oddsDifference <= threshold;
// Calculate time since Telegram message
const messageTime = new Date($input.item.json.timestamp);
const currentTime = new Date();
const minutesElapsed = (currentTime - messageTime) / 1000 / 60;
const withinTimeWindow = minutesElapsed <= 30;
return {
json: {
...($input.item.json),
currentOdds: currentOdds,
oddsDifference: oddsDifference,
oddsAcceptable: oddsAcceptable,
minutesElapsed: minutesElapsed,
withinTimeWindow: withinTimeWindow,
shouldExecuteBet: oddsAcceptable && withinTimeWindow
}
};
Configure Bet Execution HTTP Request
- Add an If node: "Should Execute Bet?"
- Condition:
{{$json.shouldExecuteBet}}equalstrue - Add HTTP Request node on "true" branch: "Execute Bet"
- Set method to POST
- Configure endpoint:
https://api.bettingsite.com/v1/bets
Bet execution payload:
{
"name": "Execute Bet",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.bettingsite.com/v1/bets",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"options": {
"bodyParameters": {
"parameters": [
{
"name": "matchId",
"value": "={{$json.matchId}}"
},
{
"name": "betType",
"value": "={{$json.betType}}"
},
{
"name": "odds",
"value": "={{$json.currentOdds}}"
},
{
"name": "stake",
"value": "10.00"
},
{
"name": "team1",
"value": "={{$json.matchedTeam1}}"
},
{
"name": "team2",
"value": "={{$json.matchedTeam2}}"
}
]
},
"timeout": 15000
}
}
}
Why this approach:
The odds threshold (±0.05) balances execution speed with value preservation. Odds of 1.85 on Telegram are acceptable if the betting site shows 1.80-1.90. Tighter thresholds (±0.02) miss 60%+ of opportunities; looser thresholds (±0.10) execute bets with significantly worse value.
Variables to customize:
threshold: Adjust based on your risk tolerance (0.02 for conservative, 0.10 for aggressive)stake: Set fixed stake or implement dynamic staking based on confidence scorestimeout: Increase to 20000ms if betting site API is slow (>5 seconds response time)
Workflow Architecture Overview
This workflow consists of 12 nodes organized into 4 main sections:
- Data ingestion (Nodes 1-3): Telegram Trigger captures messages, Function node extracts betting data, If node filters valid tips
- Matching logic (Nodes 4-6): HTTP Request fetches betting site team listings, Function node performs fuzzy matching, If node validates match confidence
- Odds verification (Nodes 7-9): HTTP Request gets current odds, Function node compares with Telegram odds, If node checks time window
- Bet execution & logging (Nodes 10-12): HTTP Request places bet, Google Sheets node logs result, Error Trigger handles failures
Execution flow:
- Trigger: Real-time Telegram message (webhook-based)
- Average run time: 3-5 seconds from message to bet execution
- Key dependencies: Telegram Bot API, Betting Site API, Google Sheets API (optional)
Critical nodes:
- Fuzzy Match Teams: Handles 90%+ of spelling variations—most complex logic in workflow
- Odds Comparison: Prevents execution of stale tips (odds changed significantly)
- If Node (Should Execute Bet?): Final gatekeeper ensuring all conditions met before spending money
The complete n8n workflow JSON template is available at the bottom of this article.
Key Configuration Details
Betting Site API Integration
Required fields:
- API Key: Your betting site API key (usually in account settings → Developer)
- Endpoint:
https://api.bettingsite.com/v1(replace with actual betting site) - Rate Limit: 60 requests/minute (implement 1-second delay between requests if needed)
Common issues:
- Using wrong API version → Results in 404 errors or deprecated endpoints
- Not handling rate limits → Account suspension after 100+ rapid requests
- Missing authentication headers → 401 Unauthorized responses
Authentication setup:
Most betting site APIs use API Key authentication via HTTP headers:
Authorization: Bearer YOUR_API_KEY_HERE
Content-Type: application/json
Fuzzy Matching Optimization
Threshold tuning:
Test with 50+ real Telegram messages to find optimal threshold:
| Threshold | Matches Found | False Positives | Recommended For |
|---|---|---|---|
| 0.75 | 95% | 15% | Testing only |
| 0.85 | 88% | 3% | Production (recommended) |
| 0.90 | 75% | 0.5% | High-stakes betting |
Performance considerations:
- Cache team name mappings in memory for 1 hour (reduces API calls by 80%)
- Pre-load betting site team list on workflow initialization
- Use lowercase normalization before similarity calculation
Error Handling Strategy
Retry logic:
Implement exponential backoff for API failures:
- First retry: 2 seconds
- Second retry: 4 seconds
- Third retry: 8 seconds
- After 3 failures: Log error and skip bet
Node configuration for retry:
{
"continueOnFail": true,
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 2000
}
Testing & Validation
Component testing:
Telegram extraction: Post test messages with different formats and verify extraction accuracy
- Expected output: 95%+ of messages parsed correctly
- Check:
team1,team2,betType,oddsfields populated
Fuzzy matching: Test with known team name variations
- "Man United" should match "Manchester United" (score > 0.85)
- "Liverpool" should NOT match "Everton" (score < 0.85)
- Review
matchedTeam1,matchedTeam2, confidence scores
Odds verification: Manually check betting site odds vs Telegram odds
- Verify
oddsDifferencecalculation is accurate - Confirm
shouldExecuteBetlogic works correctly
- Verify
Bet execution: Use betting site's test/sandbox API if available
- Start with minimum stake (e.g., $0.10)
- Verify bet appears in your betting account
- Check response codes (200 = success, 400 = invalid data, 401 = auth error)
Integration testing:
Run the complete workflow end-to-end with real Telegram messages in a test channel. Monitor execution time—should be under 5 seconds from message to bet placement. Check Google Sheets logs for any failed executions or data quality issues.
Common troubleshooting:
| Issue | Cause | Solution |
|---|---|---|
| No bets executing | Odds threshold too strict | Increase threshold from 0.05 to 0.08 |
| Wrong teams matched | Fuzzy matching threshold too low | Increase from 0.85 to 0.90 |
| Timeout errors | Betting site API slow | Increase timeout from 10s to 20s |
| 401 errors | Invalid API credentials | Regenerate API key, update credentials |
Production Deployment Checklist
| Area | Requirement | Why It Matters |
|---|---|---|
| Error Handling | Retry logic with exponential backoff | Prevents data loss on temporary API failures |
| Monitoring | Webhook health checks every 5 minutes | Detect Telegram connection failures within 5 minutes vs discovering hours later |
| Logging | Log every execution to Google Sheets/Airtable | Track win rate, identify patterns, debug issues |
| Rate Limiting | Implement 1-second delay between API calls | Avoid account suspension from betting site |
| Stake Management | Set maximum daily/weekly stake limits | Prevent runaway losses from bugs or bad tips |
| Odds Validation | Double-check odds before execution | Catch stale data or API errors before spending money |
| Team Mapping Cache | Store fuzzy match results for 1 hour | Reduce API calls by 80%, improve response time |
| Backup Triggers | Set up email alerts for failed executions | Get notified immediately if workflow breaks |
Production environment setup:
- Use n8n Cloud or self-hosted instance with 99.9% uptime
- Enable workflow execution history (keep last 100 executions)
- Set up separate workflows for different Telegram channels (easier debugging)
- Implement circuit breaker: Pause workflow after 5 consecutive failures
Security considerations:
- Store API keys in n8n credentials (never hardcode)
- Use environment variables for sensitive configuration
- Enable IP whitelisting on betting site API if available
- Rotate API keys every 90 days
Use Cases & Variations
Use Case 1: Multiple Telegram Channels
- Industry: Professional sports betting syndicates
- Scale: 5-10 Telegram channels, 50-100 tips per day
- Modifications needed: Add multiple Telegram Trigger nodes (one per channel), merge data with Merge node, add channel identifier to logging
Use Case 2: Arbitrage Betting
- Industry: Arbitrage betting operations
- Scale: Monitor 3+ betting sites simultaneously
- Modifications needed: Add HTTP Request nodes for multiple betting sites, compare odds across sites, execute on site with best odds, calculate guaranteed profit percentage
Use Case 3: Bet Tracking & Analytics
- Industry: Betting performance analysis
- Scale: Track 200+ bets per month
- Modifications needed: Expand Google Sheets logging to include outcome tracking, add scheduled workflow to fetch bet results daily, calculate ROI and win rate metrics, generate weekly performance reports
Use Case 4: Conditional Betting Based on Confidence
- Industry: Risk-managed betting
- Scale: Variable stake sizing based on tip quality
- Modifications needed: Add confidence scoring based on fuzzy match score + odds difference, implement dynamic stake calculation (higher confidence = larger stake), set minimum confidence threshold (e.g., 0.90) for execution
Customizations & Extensions
Alternative Integrations
Instead of Google Sheets for logging:
- Airtable: Better data visualization and filtering—requires 3 node changes (swap Google Sheets nodes for Airtable nodes)
- PostgreSQL/Supabase: Better for high-volume logging (1000+ bets/month)—add database connection, create bets table, use SQL node
- Notion: Better for team collaboration and reporting—requires Notion API integration (5 nodes)
Workflow Extensions
Add automated performance reporting:
- Add a Schedule Trigger node to run daily at 9 AM
- Connect to Google Sheets to fetch yesterday's bets
- Calculate win rate, ROI, profit/loss
- Send summary email via Gmail node or Slack notification
- Nodes needed: +6 (Schedule Trigger, Google Sheets, Function for calculations, If for conditional alerts, Gmail/Slack)
Scale to handle more data:
- Replace in-memory team caching with Redis for distributed caching
- Add batch processing for multiple simultaneous Telegram messages
- Implement queue system (Bull/Redis) for bet execution during high-volume periods
- Performance improvement: Handle 100+ tips per hour vs 20-30 with basic setup
Add machine learning for tip quality scoring:
- Track historical performance of each Telegram channel
- Calculate success rate per tipster
- Implement weighted confidence scoring based on past accuracy
- Only execute bets from channels with >55% historical win rate
- Nodes needed: +8 (Database for historical data, Function for ML scoring, If for threshold checking)
Integration possibilities:
| Add This | To Get This | Complexity |
|---|---|---|
| Discord webhook | Real-time bet notifications in Discord | Easy (2 nodes) |
| Twilio SMS | Mobile alerts for high-confidence bets | Easy (3 nodes) |
| OpenAI API | Natural language parsing for complex tip formats | Medium (5 nodes) |
| Browser automation (Puppeteer) | Support betting sites without APIs | Hard (10+ nodes) |
| Telegram bot responses | Confirm bet execution back to Telegram channel | Easy (2 nodes) |
Advanced fuzzy matching:
Replace basic string similarity with:
- Levenshtein distance with weighted character positions
- Phonetic matching (Soundex/Metaphone) for pronunciation variations
- Machine learning-based entity recognition (spaCy/Hugging Face)
- Improvement: 95%+ match rate vs 88% with basic similarity
Get Started Today
Ready to automate your sports betting workflow?
- Download the template: Scroll to the bottom of this article to copy the n8n workflow JSON
- Import to n8n: Go to Workflows → Import from URL or File, paste the JSON
- Configure your services: Add your Telegram Bot Token, betting site API credentials, Google Sheets connection
- Test with sample data: Post a test message in your Telegram channel, verify extraction and matching work correctly
- Deploy to production: Activate the workflow and monitor the first 10-20 executions closely
Important: Start with minimum stakes ($0.10-$1.00) for the first week to validate accuracy before scaling up. Monitor your Google Sheets logs daily to catch any data quality issues early.
Need help customizing this workflow for your specific betting site or Telegram format? Schedule an intro call with Atherial at https://atherial.ai/contact.
N8N Workflow JSON Template
{
"name": "Telegram Sports Betting Automation",
"nodes": [
{
"parameters": {
"updates": ["message"]
},
"name": "Telegram Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"position": [250, 300]
},
{
"parameters": {
"functionCode": "// Extract betting data from Telegram message
const messageText = $input.item.json.message.text;
const patterns = {
standard: /(.+?)\\s+vs\\s+(.+?)\\s*\\|\\s*(.+?)\\s*\\|\\s*([\\d.]+)/i,
simple: /(.+?)\\s+to\\s+win\\s*@\\s*([\\d.]+)/i,
btts: /BTTS\\s*-\\s*(.+?)\\s+v\\s+(.+?)\\s*\\(([\\d.]+)\\)/i
};
let extractedData = null;
if (patterns.standard.test(messageText)) {
const match = messageText.match(patterns.standard);
extractedData = {
team1: match[1].trim(),
team2: match[2].trim(),
betType: match[3].trim(),
odds: parseFloat(match[4]),
rawMessage: messageText,
timestamp: new Date().toISOString()
};
}
if (extractedData) {
return { json: extractedData };
} else {
return { json: { error: \"Could not parse\", rawMessage: messageText } };
}"
},
"name": "Extract Betting Data",
"type": "n8n-nodes-base.function",
"position": [450, 300]
},
{
"parameters": {
"functionCode": "// Fuzzy matching implementation
function similarity(s1, s2) {
let longer = s1;
let shorter = s2;
if (s1.length < s2.length) {
longer = s2;
shorter = s1;
}
const longerLength = longer.length;
if (longerLength === 0) return 1.0;
return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
}
function editDistance(s1, s2) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
const costs = [];
for (let i = 0; i <= s1.length; i++) {
let lastValue = i;
for (let j = 0; j <= s2.length; j++) {
if (i === 0) costs[j] = j;
else if (j > 0) {
let newValue = costs[j - 1];
if (s1.charAt(i - 1) !== s2.charAt(j - 1))
newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1;
costs[j - 1] = lastValue;
lastValue = newValue;
}
}
if (i > 0) costs[s2.length] = lastValue;
}
return costs[s2.length];
}
const telegramTeam1 = $input.item.json.team1;
const bettingSiteTeams = [\"Manchester United\", \"Liverpool FC\", \"Arsenal FC\"];
const threshold = 0.85;
function findBestMatch(telegramTeam, availableTeams) {
let bestMatch = null;
let bestScore = 0;
for (const team of availableTeams) {
const score = similarity(telegramTeam, team);
if (score > bestScore && score >= threshold) {
bestScore = score;
bestMatch = team;
}
}
return { match: bestMatch, score: bestScore };
}
const team1Match = findBestMatch(telegramTeam1, bettingSiteTeams);
return {
json: {
...($input.item.json),
matchedTeam1: team1Match.match,
team1Confidence: team1Match.score,
matchSuccess: team1Match.match !== null
}
};"
},
"name": "Fuzzy Match Teams",
"type": "n8n-nodes-base.function",
"position": [650, 300]
},
{
"parameters": {
"method": "GET",
"url": "https://api.bettingsite.com/v1/odds",
"options": {
"queryParameters": {
"parameters": [
{ "name": "team1", "value": "={{$json.matchedTeam1}}" },
{ "name": "betType", "value": "={{$json.betType}}" }
]
}
}
},
"name": "Get Current Odds",
"type": "n8n-nodes-base.httpRequest",
"position": [850, 300]
},
{
"parameters": {
"functionCode": "const telegramOdds = $input.item.json.odds;
const currentOdds = $input.item.json.currentOdds;
const threshold = 0.05;
const oddsDifference = Math.abs(telegramOdds - currentOdds);
const oddsAcceptable = oddsDifference <= threshold;
const messageTime = new Date($input.item.json.timestamp);
const currentTime = new Date();
const minutesElapsed = (currentTime - messageTime) / 1000 / 60;
const withinTimeWindow = minutesElapsed <= 30;
return {
json: {
...($input.item.json),
currentOdds: currentOdds,
oddsDifference: oddsDifference,
oddsAcceptable: oddsAcceptable,
minutesElapsed: minutesElapsed,
withinTimeWindow: withinTimeWindow,
shouldExecuteBet: oddsAcceptable && withinTimeWindow
}
};"
},
"name": "Compare Odds",
"type": "n8n-nodes-base.function",
"position": [1050, 300]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.shouldExecuteBet}}",
"value2": true
}
]
}
},
"name": "Should Execute Bet?",
"type": "n8n-nodes-base.if",
"position": [1250, 300]
},
{
"parameters": {
"method": "POST",
"url": "https://api.bettingsite.com/v1/bets",
"options": {
"bodyParameters": {
"parameters": [
{ "name": "team1", "value": "={{$json.matchedTeam1}}" },
{ "name": "betType", "value": "={{$json.betType}}" },
{ "name": "odds", "value": "={{$json.currentOdds}}" },
{ "name": "stake", "value": "10.00" }
]
}
}
},
"name": "Execute Bet",
"type": "n8n-nodes-base.httpRequest",
"position": [1450, 200]
}
],
"connections": {
"Telegram Trigger": { "main": [[{ "node": "Extract Betting Data", "type": "main", "index": 0 }]] },
"Extract Betting Data": { "main": [[{ "node": "Fuzzy Match Teams", "type": "main", "index": 0 }]] },
"Fuzzy Match Teams": { "main": [[{ "node": "Get Current Odds", "type": "main", "index": 0 }]] },
"Get Current Odds": { "main": [[{ "node": "Compare Odds", "type": "main", "index": 0 }]] },
"Compare Odds": { "main": [[{ "node": "Should Execute Bet?", "type": "main", "index": 0 }]] },
"Should Execute Bet?": { "main": [[{ "node": "Execute Bet", "type": "main", "index": 0 }]] }
}
}
