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 →
{
"name": "04 - Reporte Diario de Ventas",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * *"
}
]
}
},
"id": "cron-trigger",
"name": "Trigger: Todos los d\u00edas 8:00 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
250,
400
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT \n COUNT(*) as total_orders,\n SUM(total) as total_revenue,\n AVG(total) as average_order_value,\n COUNT(DISTINCT email_cliente) as unique_customers\nFROM orders\nWHERE created_at >= NOW() - INTERVAL '24 hours'\n AND estado = 'completado'"
},
"id": "get-sales-metrics",
"name": "Obtener M\u00e9tricas de Ventas",
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
450,
300
],
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT \n p.nombre,\n COUNT(DISTINCT o.id) as times_sold,\n SUM((o.metadata->'productos'->0->>'quantity')::int) as units_sold\nFROM orders o\nCROSS JOIN LATERAL jsonb_array_elements(o.metadata->'productos') as product\nJOIN \"Producto\" p ON p.id = (product->>'id')::int\nWHERE o.created_at >= NOW() - INTERVAL '24 hours'\n AND o.estado = 'completado'\nGROUP BY p.nombre\nORDER BY units_sold DESC\nLIMIT 5"
},
"id": "get-top-products",
"name": "Productos M\u00e1s Vendidos",
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
450,
500
],
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "getAll",
"tableId": "abandoned_carts",
"returnAll": false,
"limit": 100,
"filters": {
"conditions": [
{
"keyName": "abandoned_at",
"keyValue": ">=",
"keyValue2": "NOW() - INTERVAL '24 hours'"
},
{
"keyName": "status",
"keyValue": "abandoned"
}
]
}
},
"id": "get-abandoned-carts",
"name": "Carritos Abandonados",
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
450,
700
],
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const metrics = $node['Obtener M\u00e9tricas de Ventas'].json[0] || {};\nconst topProducts = $node['Productos M\u00e1s Vendidos'].json || [];\nconst abandonedCarts = $node['Carritos Abandonados'].json || [];\n\nconst totalOrders = metrics.total_orders || 0;\nconst totalRevenue = parseFloat(metrics.total_revenue || 0).toFixed(2);\nconst avgOrderValue = parseFloat(metrics.average_order_value || 0).toFixed(2);\nconst uniqueCustomers = metrics.unique_customers || 0;\nconst abandonedCount = abandonedCarts.length;\n\n// Generar HTML del reporte\nconst html = `\n <div style=\"font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;\">\n <h1 style=\"color: #333; border-bottom: 3px solid #000; padding-bottom: 10px;\">\n \ud83d\udcca Reporte Diario - ${new Date().toLocaleDateString('es-ES')}\n </h1>\n \n <h2 style=\"color: #555; margin-top: 30px;\">\ud83d\udcb0 Resumen de Ventas</h2>\n <div style=\"background: #f5f5f5; padding: 20px; border-radius: 10px;\">\n <table style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 10px; border-bottom: 1px solid #ddd;\"><strong>Total de Pedidos:</strong></td>\n <td style=\"padding: 10px; border-bottom: 1px solid #ddd; text-align: right;\">${totalOrders}</td>\n </tr>\n <tr>\n <td style=\"padding: 10px; border-bottom: 1px solid #ddd;\"><strong>Ingresos Totales:</strong></td>\n <td style=\"padding: 10px; border-bottom: 1px solid #ddd; text-align: right; color: green; font-size: 18px;\"><strong>$${totalRevenue}</strong></td>\n </tr>\n <tr>\n <td style=\"padding: 10px; border-bottom: 1px solid #ddd;\"><strong>Valor Promedio de Pedido:</strong></td>\n <td style=\"padding: 10px; border-bottom: 1px solid #ddd; text-align: right;\">$${avgOrderValue}</td>\n </tr>\n <tr>\n <td style=\"padding: 10px;\"><strong>Clientes \u00danicos:</strong></td>\n <td style=\"padding: 10px; text-align: right;\">${uniqueCustomers}</td>\n </tr>\n </table>\n </div>\n\n <h2 style=\"color: #555; margin-top: 30px;\">\ud83c\udfc6 Top 5 Productos M\u00e1s Vendidos</h2>\n <div style=\"background: #f5f5f5; padding: 20px; border-radius: 10px;\">\n <ol style=\"margin: 0; padding-left: 20px;\">\n ${topProducts.map(p => `\n <li style=\"padding: 8px 0; border-bottom: 1px solid #ddd;\">\n <strong>${p.nombre}</strong> - ${p.units_sold} unidades vendidas\n </li>\n `).join('')}\n </ol>\n </div>\n\n <h2 style=\"color: #555; margin-top: 30px;\">\ud83d\uded2 Carritos Abandonados</h2>\n <div style=\"background: #fff3cd; padding: 20px; border-radius: 10px; border-left: 4px solid #ffc107;\">\n <p style=\"margin: 0; font-size: 16px;\">\n <strong>${abandonedCount}</strong> carritos abandonados en las \u00faltimas 24 horas.\n </p>\n ${abandonedCount > 0 ? `\n <p style=\"margin: 10px 0 0 0; color: #666;\">\n \ud83d\udca1 Considera enviar emails de recuperaci\u00f3n con descuentos.\n </p>\n ` : ''}\n </div>\n\n <div style=\"margin-top: 30px; padding: 20px; background: #e8f5e9; border-radius: 10px; text-align: center;\">\n <p style=\"margin: 0; color: #2e7d32; font-size: 14px;\">\n Reporte generado autom\u00e1ticamente por n8n\n </p>\n </div>\n </div>\n`;\n\nreturn {\n html,\n metrics: {\n totalOrders,\n totalRevenue,\n avgOrderValue,\n uniqueCustomers,\n abandonedCount\n }\n};"
},
"id": "generate-report",
"name": "Generar Reporte HTML",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
650,
400
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.resend.com/emails",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env.RESEND_API_KEY }}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "from",
"value": "Neurai.dev Reports <noreply@neurai.dev>"
},
{
"name": "to",
"value": "{{ $env.ADMIN_EMAILS }}"
},
{
"name": "subject",
"value": "\ud83d\udcca Reporte Diario - {{ new Date().toLocaleDateString('es-ES') }}"
},
{
"name": "html",
"value": "={{ $json.html }}"
}
]
}
},
"id": "send-email-report",
"name": "Enviar Reporte por Email",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
850,
300
]
},
{
"parameters": {
"authentication": "genericCredentialType",
"method": "POST",
"url": "https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "chat_id",
"value": "={{ $env.TELEGRAM_CHAT_ID }}"
},
{
"name": "text",
"value": "\ud83d\udcca *Reporte Diario*\\n\\n\ud83d\udcb0 Ingresos: ${{ $json.metrics.totalRevenue }}\\n\ud83d\udce6 Pedidos: {{ $json.metrics.totalOrders }}\\n\ud83d\udc65 Clientes: {{ $json.metrics.uniqueCustomers }}\\n\ud83d\uded2 Carritos abandonados: {{ $json.metrics.abandonedCount }}\\n\\n\u2705 Reporte completo enviado por email"
},
{
"name": "parse_mode",
"value": "Markdown"
}
]
}
},
"id": "send-telegram-summary",
"name": "Enviar Resumen a Telegram",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
850,
500
]
}
],
"connections": {
"Trigger: Todos los d\u00edas 8:00 AM": {
"main": [
[
{
"node": "Obtener M\u00e9tricas de Ventas",
"type": "main",
"index": 0
},
{
"node": "Productos M\u00e1s Vendidos",
"type": "main",
"index": 0
},
{
"node": "Carritos Abandonados",
"type": "main",
"index": 0
}
]
]
},
"Obtener M\u00e9tricas de Ventas": {
"main": [
[
{
"node": "Generar Reporte HTML",
"type": "main",
"index": 0
}
]
]
},
"Productos M\u00e1s Vendidos": {
"main": [
[
{
"node": "Generar Reporte HTML",
"type": "main",
"index": 0
}
]
]
},
"Carritos Abandonados": {
"main": [
[
{
"node": "Generar Reporte HTML",
"type": "main",
"index": 0
}
]
]
},
"Generar Reporte HTML": {
"main": [
[
{
"node": "Enviar Reporte por Email",
"type": "main",
"index": 0
},
{
"node": "Enviar Resumen a Telegram",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {},
"tags": [
"reporting",
"analytics",
"cron"
]
}
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.
supabaseApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
04 - Reporte Diario de Ventas. Uses supabase, httpRequest. Scheduled trigger; 7 nodes.
Source: https://github.com/julianesp/neuraidev/blob/25adc0bc25c1bd1cb74dc64feec5c79b3b0f737a/n8n-workflows/04-reporte-diario.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.
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.
• 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