DEV Community

Cover image for How to Build a Self-Hosted Customer Support Pipeline with n8n, Supabase, and WhatsApp
אחיה כהן
אחיה כהן

Posted on • Edited on • Originally published at achiya-automation.com

How to Build a Self-Hosted Customer Support Pipeline with n8n, Supabase, and WhatsApp

Why Self-Hosted?

Most customer support automation guides point you to Zendesk, Intercom, or Freshdesk. They're great products — but they come with per-seat pricing that can crush a small business budget. At $49-99/agent/month, a 3-person support team costs $1,800-3,600/year before you even start customizing.

What if you could build the same thing with open-source tools, running on a $20/month VPS?

Here's the architecture I keep coming back to. It handles WhatsApp as the primary channel, stores everything in a real database (not spreadsheets), and automates the entire pipeline from first contact to resolution.

The Stack

Component Tool Role Cost
Automation Engine n8n (self-hosted) Workflow orchestration Free (open-source)
Database Supabase (self-hosted) Customer data, ticket tracking Free (open-source)
Messaging WhatsApp Business API Customer communication ~$0.05/conversation
AI OpenAI API Intent classification ~$0.01/request
Hosting Any VPS (Hetzner, DigitalOcean) Infrastructure ~$20/month

Total: ~$25/month vs $150+/month for SaaS equivalents.

Architecture Overview

Customer (WhatsApp) -> WAHA/Cloud API -> n8n Webhook
    -> Router Node (by intent)
        -> FAQ: AI Response -> Send Reply
        -> Appointment: Check Calendar -> Book -> Confirm
        -> Complaint: Create Ticket -> Notify Team
        -> Sales: Qualify Lead -> CRM Entry -> Assign Agent
    -> Supabase (PostgreSQL)
Enter fullscreen mode Exit fullscreen mode

Step 1: Set Up the WhatsApp Webhook

Configure your WhatsApp API (Meta Cloud API or WAHA for self-hosted) to send incoming messages to an n8n webhook:

// n8n Webhook Node Configuration
{
  "httpMethod": "POST",
  "path": "whatsapp-support",
  "responseMode": "onReceived",
  "responseCode": 200
}
Enter fullscreen mode Exit fullscreen mode

The webhook receives: from (phone number), body (message text), timestamp, and type (text, image, document).

Step 2: Intent Classification with AI

// n8n Function Node
const message = $input.first().json.body;
const prompt = 'Classify this customer message into ONE category: FAQ, APPOINTMENT, COMPLAINT, SALES, OTHER. Message: "' + message + '"';
return [{ json: { prompt, originalMessage: message } }];
Enter fullscreen mode Exit fullscreen mode

This costs ~$0.001/message and runs in under 500ms. Handles Hebrew, English, and mixed languages automatically.

Step 3: Database Schema (Supabase)

CREATE TABLE customers (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  phone TEXT UNIQUE NOT NULL,
  name TEXT,
  first_contact TIMESTAMPTZ DEFAULT NOW(),
  last_contact TIMESTAMPTZ DEFAULT NOW(),
  total_interactions INT DEFAULT 1
);

CREATE TABLE tickets (
  id SERIAL PRIMARY KEY,
  customer_id UUID REFERENCES customers(id),
  category TEXT NOT NULL,
  message TEXT NOT NULL,
  status TEXT DEFAULT 'open',
  priority TEXT DEFAULT 'normal',
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE messages (
  id SERIAL PRIMARY KEY,
  customer_id UUID REFERENCES customers(id),
  direction TEXT NOT NULL,
  content TEXT NOT NULL,
  channel TEXT DEFAULT 'whatsapp',
  created_at TIMESTAMPTZ DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

Step 4: The Router Workflow

Use a Switch node after AI classification:

  • FAQ: Match FAQ database -> AI response -> Send via WhatsApp
  • Appointment: Parse date -> Check calendar -> Book -> Confirm
  • Complaint: Create ticket -> Notify team -> Acknowledge
  • Sales: Qualify lead -> CRM entry -> Assign agent

Step 5: Upsert Customer Records

// n8n Supabase Node
{
  "operation": "upsert",
  "table": "customers",
  "conflictColumn": "phone",
  "data": {
    "phone": "{{ $json.from }}",
    "name": "{{ $json.profile_name }}",
    "last_contact": "{{ $now }}"
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Automated Follow-ups

Set up n8n Cron triggers for:

  • 24-hour open ticket alerts
  • Post-resolution satisfaction surveys
  • 48-hour lead re-engagement

Production Considerations

  • Rate limiting: Start with 250 business-initiated conversations/24h
  • Error handling: Fall back to templates if AI fails
  • Monitoring: Use n8n execution logs + alerts for failed webhooks
  • Backup: Standard pg_dump via n8n cron job

What to Expect

The main benefit of this setup isn't some magical metric — it's that every customer message gets an instant acknowledgment, even at 3am. That alone changes the dynamic. Customers feel heard, and the business owner isn't chained to their phone.

The AI intent classification handles routine questions (hours, pricing, directions) without human involvement. More complex issues get routed to the right person with full context. It's not "80% automation" — it's "the simple stuff happens automatically, and the hard stuff gets escalated properly."

What's Next?

Extend with voice note transcription (Whisper), image processing (vision AI), multi-language support, and analytics dashboards (Metabase).

The key insight: you don't need enterprise software for enterprise-grade support.


Building automation systems for small businesses at Achiya Automation. Try n8n — it's free and open source. We specialize in WhatsApp bots, workflow automation, and AI agents — all self-hosted, no vendor lock-in.


Over to You

If you could only self-host ONE tool in your support stack, which would it be — the automation engine, the database, or the customer inbox?

I chose the inbox first (Chatwoot). That was a mistake. The automation engine should come first because without it, you're just self-hosting a fancy email client.

Here's what I'm still figuring out: at what volume does Chatwoot start struggling? I've seen slowdowns around 10K conversations/month on a 4GB VPS. Anyone running it at higher scale?

Share your self-hosted support stack below — I'll tell you what I'd change. 👇

Top comments (0)