DEV Community

Airdesk Solutions
Airdesk Solutions

Posted on

What I Learned Building a Multi-Tenant CRM with WhatsApp + VOIP for the Travel Industry

Travel agencies run on chaos. Forty WhatsApp inquiries a day across three agents, phone calls about schedule changes, emails about refunds and most agencies manage all of it with browser tabs, spreadsheets, and prayer.

I've spent the last couple of years building Airdesk Solutions Private Limited, a multi-tenant CRM that pulls WhatsApp Business, voice calls, and email into one shared workspace for travel agencies. Here's what that actually involved including the parts that hurt.

The core architectural decision: multi-tenancy from day one

Travel agencies often have multiple branches, and B2B consolidators serve networks of sub-agents. That meant tenant isolation couldn't be an afterthought. Every conversation, booking, wallet transaction, and permission check is tenant-scoped at the data layer. Retrofitting this later would have been a rewrite; building it first slowed down v1 but made everything after cheaper.

The stack: Next.js/React on the frontend, Node.js services on the backend, MongoDB for data, Cloudflare R2 for file storage, all running on Hetzner.

WhatsApp Business API: the BSP question

You can't just "connect WhatsApp" you go through a Business Solution Provider. We started with one BSP and are moving toward WATI/360dialog, and the lesson is: abstract your messaging layer behind your own webhook middleware from the start. BSPs differ in webhook payload shapes, template handling, and session rules. If your CRM logic talks to a BSP directly instead of to your own normalized message model, switching providers becomes surgery instead of a config change.

The hard product problem isn't receiving messages it's shared-inbox semantics: who owns this conversation, what happens when two agents open the same chat, how automation hands off to a human without the customer noticing the seam.

VOIP: the part nobody warns you about

We run Asterisk on a Hetzner server, bridged to our admin backend through a Node.js AMI (Asterisk Manager Interface) service. Browser-based calling means WebRTC, and WebRTC means:

SIP over WebSocket with SIP.js on the client
A coturn TURN server for NAT traversal without it, "the call connects but there's no audio" becomes your most common bug report
Firewall rules (iptables/UFW) that fight with each other in creative ways
fail2ban, because the moment a SIP port is public, brute-force registration attempts start within hours

One-way audio issues alone taught me more about NAT than any networking course. If you're adding calling to a SaaS product: budget 3x the time you think telephony will take.

What I'd tell anyone building vertical SaaS

Pick a vertical with genuinely different workflows. Travel isn't "sales pipeline + custom fields." Bookings, agent wallets, supplier ledgers quirks mean a generic CRM genuinely doesn't fit that's the moat.

Own your integration boundaries. Normalize external APIs (BSPs, telephony) into your own models immediately.

Multi-tenant isolation is a feature you sell, not just architecture choice agencies ask about data separation in every demo.
Infrastructure is product. When a travel agent's softphone drops a call, they don't care whose TURN server it was.

Happy to go deeper on any of this in the comments — especially the Asterisk/WebRTC side, which I have opinions about.

Airdesk is live at www.theairdesk.com if you're curious what it became.

Top comments (0)