AXERA FLOW
In production Technology · Micro business

Case · Axera Flow

Multi-tenant WhatsApp AI for two markets

One n8n workflow, one Evolution instance, one Postgres database serving multiple markets — each with its own language, persona, and escalation rules. Adding a market is a database row, not a code fork.

Timeline
Since May 2026
Duration
3 weeks
Sector
Technology

9 min

to launch a whole new market

Axera Flow · Technology

Before

The problem

Axera Flow operates across two markets that speak different languages, expect different conversational tones, and fall under different privacy regimes (LGPD in Brazil; PIPEDA, Law 25, PIPA in Canada). Hand-rolling two separate bots would mean two codebases, two pipelines, and two credential sets — a non-starter for a one-person operation.

After

The solution

A multi-tenant architecture: one n8n workflow, one Evolution API instance, one Postgres database, with every market-specific setting (system prompt, language, owner phone, business name) stored as a row in a per-market config table. The webhook reads the instance from the inbound message and injects everything dynamically. Adding a market is a new row — no code fork.

Tech stack

n8n Claude API OpenAI API Postgres Evolution API Hetzner

Results

Measured impact

To add a market

9 min

Workflow changes

0

Markets (BR + CA)

2

When Axera Flow started taking on its first leads across two markets at once — Brazil and Canada — we needed a WhatsApp assistant that wouldn’t just answer messages, but would qualify, route, and adapt to each market’s language, regulations, and tone, all from a single codebase.

The challenge

Axera Flow is a solo consultancy operating in two distinct markets: an established Brazilian audience and a freshly launched Canadian one. Each market speaks a different language, expects a different conversational tone, and operates under different regulatory frameworks (LGPD in Brazil; PIPEDA, Law 25, PIPA in Canada). Hand-rolling two separate bots would have meant maintaining two codebases, two deployment pipelines, and two sets of credentials — a non-starter for a one-person operation.

The practical question was: can a single workflow serve N markets, each with its own persona, language, owner phone, and escalation rules, without forking the codebase every time a new market is added?

The approach

We chose a multi-tenant architecture: one n8n workflow, one Evolution API instance, one Postgres database — with all market-specific configuration (system prompt, language, market code, owner phone, business name) stored as rows in a per-market config table. The webhook pulls the instance name from the inbound message, looks up the row, and injects everything dynamically.

This kept the build cost flat regardless of how many markets we add. Adding Canada to the existing Brazilian setup required no code changes — only a new row in the database, a new Evolution instance, and a configured webhook.

We deliberately avoided more elaborate approaches like deploying separate instances per market (would have multiplied infrastructure cost), or building a heavy admin UI (over-engineering for a solo operator).

What we built

A single n8n workflow that processes every inbound WhatsApp message through a dynamic pipeline:

  • Webhook → Code node extracts message, instance, and sender from Evolution’s payload
  • Postgres lookup pulls the active instance config and the conversation history (last 20 messages)
  • Claude API call with persona-specific system prompt, full history, and an escalate_to_owner tool
  • Branch on tool use — if Claude chooses to escalate, the workflow records the event, notifies the owner via WhatsApp with a structured summary, and triggers a separate Triage Agent that prepares an editorial briefing on the lead
  • Daily push — every morning at 9am Edmonton time, a scheduled workflow pulls pending unacknowledged escalations and pushes a numbered list to the owner, who can acknowledge via WhatsApp commands

Language handling is fully driven by the conversation context: the bot infers the conversation language from message history and responds accordingly. Escalation summaries and triage briefings are produced in the same language as the conversation, so the owner reads everything in the lead’s language.

Security follows defense-in-depth: webhook secret validation between Evolution and n8n, encrypted credentials in n8n (never exposed in workflow JSON), a separate read-only database user for analytics, and .env-based secret management for all containers.

The outcome

The Brazilian instance ran in production from early May 2026; the Canadian instance went live on May 16, 2026. Adding the Canadian market required:

  • One new row in the config table (≈4 minutes)
  • One Evolution instance creation via API (≈2 minutes)
  • One webhook configuration via API (≈2 minutes)
  • One WhatsApp QR Code scan (≈1 minute)
  • Zero workflow changes

End-to-end test on day one: a lead message in English received a Canadian-toned reply; an escalation request triggered both an owner notification and an editorial triage briefing — all in English, while the Brazilian instance continued operating in Portuguese without interruption. (The Brazilian instance was later paused on May 24 when the company narrowed scope to Canada-first; the multi-tenant design means turning it back on is a row, not a rebuild.)

Lessons learned

The biggest lesson was that multi-tenancy is easy in data and hard in prompts. The database side was straightforward: rows in a config table, dynamic SQL lookups, no problem. But the LLM-facing parts — the tool descriptions, the agent system prompts, the briefing templates — had been written in Portuguese during the Brazilian-only phase, and that hardcoded language quietly broke escalations on the Canadian instance for the first end-to-end test. The fix was to neutralize every LLM-facing instruction (“in the same language as the conversation” instead of “in Portuguese”), so that the prompts themselves became truly market-agnostic.

The second lesson was about workflow versioning hygiene. n8n’s UI separates Save (draft) from Publish (active version), and silent draft-only saves cost us a confused round of debugging when published behavior didn’t match what the editor showed. Now every workflow change in this stack ends with an explicit Publish step.