n8n + Chatwoot + Dify — business-logic-driven support hub
When AI support needs to call orders / refunds / CRM / email across many systems, n8n becomes the orchestration hub that pulls all business logic into one place.
- Scenario
- AI support needs deep integration with business systems (orders / refunds / CRM / ERP)
- Monthly cost
- $80 - $300
- Difficulty
- Medium
What this combo solves#
“Chatwoot + Dify” is enough for pure Q&A, but problems emerge once business actions are involved:
- “Look up my order” should query the ERP — logic gets scattered
- Refund amounts need to be sourced from the order API
- High-priority tickets must notify Slack and Lark
- Monthly CSAT data has to aggregate into Notion
- KB must auto-sync from
docs/in GitHub
Having Dify Workflow call every external API directly is an anti-pattern — URLs, auth, error handling are duplicated everywhere. Change the ERP interface and every workflow has to change.
Correct pattern: Dify only calls n8n. n8n owns all business-side logic.
Architecture#
Key: every “AI ↔ business” / “support ↔ business” / “external trigger ↔ internal data” wire goes through n8n.
When to pick this#
| Situation | Fits? |
|---|---|
| AI support reads / writes orders, refunds, CRM | ✓ Strong fit |
| Many business systems, volatile interfaces | ✓ |
| GitHub Push → auto-sync KB | ✓ |
| Cross-team data flows (sales, support, ops) | ✓ |
| Single system, support is Q&A only | ✗ Chatwoot + Dify is enough |
Roles#
| Component | Owns | Does NOT |
|---|---|---|
| Chatwoot | Channels, agents | Direct business-API calls |
| Dify | Prompts, KB, LLM | Direct business APIs (only calls n8n) |
| n8n | Business logic, orchestration, cron | Customer-facing UI |
| PostgreSQL | Shared metadata | Business data |
| Redis | Queues, cache |
10 production workflows#
| # | Trigger | Workflow |
|---|---|---|
| W1 | Dify tool call | Lookup order → ERP → structured response |
| W2 | Dify tool call | Refund decision (rules + amount check) |
| W3 | Chatwoot webhook | New ticket → write Notion + notify sales |
| W4 | Chatwoot webhook | Sensitive keyword → escalate + Lark alert |
| W5 | Daily cron | Pull Chatwoot → compute KPIs → push report |
| W6 | GitHub push | docs change → fetch → call Dify API to rebuild KB |
| W7 | Weekly cron | Sample 50 tickets → LLM scoring → write Notion |
| W8 | Chatwoot webhook | Ticket resolved → tag customer LTV → CRM sync |
| W9 | Dify tool call | Unified multi-channel notify (email + Slack + SMS) |
| W10 | Monthly cron | Archive data → S3 + audit trigger |
Deployment#
1. Bring up n8n#
# Use PostgreSQL persistence, not default SQLite
docker run -d --name n8n \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
-e DB_TYPE=postgresdb \
-e DB_POSTGRESDB_HOST=postgres \
-e DB_POSTGRESDB_DATABASE=n8n \
-e DB_POSTGRESDB_USER=n8n \
-e DB_POSTGRESDB_PASSWORD=changeme \
-e N8N_HOST=n8n.example.com \
-e WEBHOOK_URL=https://n8n.example.com/ \
-e N8N_BASIC_AUTH_ACTIVE=true \
-e N8N_BASIC_AUTH_USER=admin \
-e N8N_BASIC_AUTH_PASSWORD=changeme \
n8nio/n8n
2. First workflow — order lookup#
Webhook (POST /lookup-order)
→ HTTP Request (ERP API)
→ Transform data
→ Respond to Webhook (JSON)
Publish → webhook URL: https://n8n.example.com/webhook/lookup-order
3. Custom tool in Dify#
Dify → Tools → Create Custom Tool:
openapi: 3.0.0
info: { title: Business Tools, version: 1.0 }
servers:
- url: https://n8n.example.com/webhook
paths:
/lookup-order:
post:
operationId: lookup_order
parameters:
- { name: order_id, in: body, required: true, schema: { type: string } }
responses:
'200': { description: Order info }
/initiate-refund:
post:
operationId: initiate_refund
parameters: [...]
4. Dify Agent / Workflow#
Enable lookup_order in your Dify Agent. The model calls it when appropriate.
User: “Where is order ORD-12345?” AI (calls lookup_order → “Shipped — SF1234567890”): “Your order shipped — tracking SF1234567890, arriving tomorrow.”
5. Chatwoot ↔ n8n both ways#
Chatwoot → n8n: Settings → Integrations → Webhooks → https://n8n.example.com/webhook/chatwoot-event
n8n → Chatwoot: n8n nodes call Chatwoot’s API with its token.
Cost#
| Resource | Monthly |
|---|---|
| 8C/16G VPS (n8n + Dify) | $60 |
| 4C/8G VPS (Chatwoot) | $30 |
| Managed Postgres | $25 |
| LLM tokens (5k conv/mo) | $30-100 |
| Total | $145-215 / mo |
Outcomes#
SaaS team after 8 weeks:
| Metric | Dify-only | + n8n |
|---|---|---|
| % business questions AI handles | 35% | 78% |
| Business-API error rate | 12% | 2.5% |
| KB freshness (docs change → AI sees) | 1-7 days | < 5 min |
| Eng maintenance | High (Dify edits on every ERP change) | Low (n8n only) |
| New workflows / month | 1-2 | 5-8 |
Design principles#
1. Dify never calls business APIs directly#
Every business call goes through n8n. When the ERP changes, only n8n updates.
2. Webhooks must be idempotent#
The same event can fire multiple times (retries) — deduplicate by request_id.
3. Critical workflows get failure alerts#
Each workflow ends with a “catch error → Lark / PagerDuty → log to Notion” branch.
4. Rate-limit business APIs#
Promo-day floods can overwhelm the ERP. Add rate-limit nodes upstream.
5. Version-control workflows#
Export n8n workflows as JSON to Git. Review like code.
Pitfalls#
- SQLite collapses under heavy webhook load — production demands PostgreSQL
- Sync vs async confusion — slow business APIs time out Dify tool calls; switch to fire-and-poll
- Credential management — keep all tokens in n8n’s credential store, encrypted, rotated
- Multi-environment — test and prod n8n must be separate instances, not shared
- License caveat — n8n’s Sustainable Use License allows self-hosting but restricts resale
Evolution#
| Stage | Add |
|---|---|
| 1. Foundation | Chatwoot + Dify + n8n |
| 2. Monitoring | Grafana + Prometheus on n8n metrics |
| 3. HA | n8n worker mode (main + worker split) |
| 4. Multi-team | n8n users + Workspaces |
| 5. CI/CD | Export workflows to Git + auto-deploy |