Skip to content
SKSuraj Kumar

Customer messaging

WhatsApp Team Inbox & CRM

A shared team inbox for WhatsApp with assignment, response deadlines, reply drafting and the platform messaging rules enforced in code.

  • AI system
  • AI
  • Messaging
  • CRM
  • Next.js
Role
Sole engineer. Conversation model, messaging-window rule engine, webhook handling and the agent inbox interface.
Work type
Private client project
Timeline
9 weeks build effort · 2025
Status
Case study published
Client
Private client work

Build effort, not elapsed calendar time. Engagements ran alongside study and employment, so this figure is the work itself rather than the span it sat in.

Interface built in code for this case study — not a client screen capture.

01Business problem

What was actually going wrong

A large share of Indian businesses sell and support on WhatsApp from personal phones, which means the customer history belongs to whoever is holding the handset.

Who feels it

  • Retail and service businesses selling through WhatsApp
  • Support staff sharing a number or using their own
  • Owners who lose customer history when staff change
  • Customers waiting on a reply nobody owns

The pattern is everywhere: enquiries arrive on WhatsApp, two or three staff members answer from their own numbers, and the record of what was promised to a customer exists only in one person’s chat history. When that person is on leave, the conversation restarts. When they leave the company, it disappears.

There is no view of what is unanswered. An enquiry that arrives at 9pm sits unseen next to a personal message from a friend, and nobody can say how long a customer has been waiting. Ownership is implicit, so two people reply to the same customer or nobody does.

On top of that, the WhatsApp Business Platform has real rules — a business can only send free-form messages inside a window after the customer’s last message, and outside it must use pre-approved templates. Teams working from personal phones discover these rules by having messages fail, and a CRM that ignores them produces confident interfaces that quietly do not deliver.

02Product overview

What got built

A team inbox built on the WhatsApp Business Platform where every conversation belongs to a contact record, has an assigned owner and a response deadline, and where the platform’s messaging window rules are enforced by the composer rather than discovered through failures.

Engineering notes

  • Monotonic message state machine over unordered webhooks
  • Service window derived once and enforced at send time
  • E.164 normalization as the contact identity key
  • Optimistic sends reconciled against provider message ids

Conversations are attached to contact records rather than phone handsets. A contact carries the full message history across staff, plus structured attributes — enquiry source, interest, order references, language preference — so context survives a change of owner. Assignment is explicit and every conversation has exactly one owner and a visible response deadline.

The composer knows the platform rules. Inside the customer service window it allows free-form replies; outside it, it switches to approved template selection with parameter fields and explains why. This single piece of logic removes the most common cause of a business message silently not arriving.

Language handling is the part generic inboxes get wrong. Customers write in English, Hindi, and Hinglish in Latin script, often within one message. Reply drafting works with the mixed-script reality rather than assuming a single language, and drafts are suggestions in the composer — an agent always sends.

03Key features

What the software does, feature by feature

10 capabilities, of which 3 are model-backed. The rest are ordinary deterministic software, and the distinction is marked so the AI claim stays honest.

  • 01

    Shared team inbox

    One queue of conversations with owner, status, last message and time waiting, so nothing depends on who is holding a phone.

  • 02

    Contact records

    Message history, structured attributes, order references and notes attached to a contact rather than a chat thread.

  • 03

    Assignment and response deadlines

    Explicit ownership with a deadline per conversation, and escalation when a first response has not gone out in time.

  • 04

    Messaging window enforcement

    The composer allows free-form replies only inside the platform’s service window and requires approved templates outside it.

  • 05

    Reply draftingmodel-backed

    Suggested replies generated from the conversation and contact record, presented in the composer for an agent to edit and send.

  • 06

    Mixed-script handlingmodel-backed

    Messages in English, Hindi and Hinglish are handled without assuming one language per conversation, including for drafting.

  • 07

    Intent taggingmodel-backed

    Incoming messages are tagged with an intent — price enquiry, order status, complaint, support — which drives routing and reporting.

  • 08

    Template library

    Approved templates with parameter fields, approval status and category, so an agent cannot select a template that will be rejected.

  • 09

    Quick replies and snippets

    Team-maintained canned responses with variables, because most questions in a messaging channel are the same twenty questions.

  • 10

    Conversation reporting

    First response time, resolution time and intent mix by period — the numbers a manager needs to staff the channel.

04User flow

How a person moves through it

The path from the trigger to the finished record, with each step attributed to whoever performs it — a person or the system.

  1. 01CustomerSends a WhatsApp message to the business number.
  2. 02SystemReceives the webhook, deduplicates it, resolves or creates the contact and appends to the conversation.
  3. 03SystemTags intent, sets the response deadline and assigns an owner by routing rule.
  4. 04AgentOpens the conversation with full contact history and a suggested reply already drafted.
  5. 05AgentEdits and sends — free-form inside the service window, or an approved template outside it.
  6. 06SystemTracks delivery and read receipts against the message and updates conversation state.
  7. 07ManagerReviews unanswered conversations, response times and intent mix.

05Architecture

How it is put together

The processing path first, then the layers it runs on, then the constraints that shaped both.

Path through the system

6 stages

  1. 01

    Receive

    Webhook intake with idempotency on provider message id.

  2. 02

    Resolve

    Phone normalized to E.164, contact matched or created.

  3. 03

    Classify

    Intent and language detected, conversation attributes updated.

  4. 04

    Route

    Owner assigned, response deadline set, escalation scheduled.

  5. 05

    Respond

    Draft offered; composer enforces window and template rules.

  6. 06

    Track

    Delivery and read receipts folded into message state.

Layers

Interface
Conversation list with waiting timeThread view with delivery statesWindow-aware composerContact panel with attributes and ordersTemplate picker with parameters
Application state
Conversation + message modelMessage state machine (queued → sent → delivered → read → failed)Window eligibility resolverOptimistic send with reconciliation
Services
WhatsApp Business Platform clientWebhook handler with idempotencyIntent and language classificationDraft generation
Records
Contacts and conversationsMessage log with provider idsTemplate registry with approval stateRouting rules and deadlines

Why it is shaped this way

  • Webhooks are not ordered and not exactly-once. Every inbound event is keyed by provider message id and status events are applied as a monotonic state machine, so a late "sent" callback cannot overwrite a "read" state.
  • The service window is computed from the customer’s last inbound message timestamp, which makes template requirement a derived property of the conversation rather than something an agent has to remember.
  • Drafts are never auto-sent. The one place the system sends without a human is the delivery of an explicitly scheduled template, which is a distinct, logged action.

06Technical decisions

The choices that mattered, and what each one cost

Every decision here was contested by a reasonable alternative. The trade-off column is the part usually left out.

01

Model message delivery as a monotonic state machine keyed by provider id.

Why

Status callbacks arrive out of order and can be redelivered. Ranking states and refusing backward transitions is the only reliable way to keep the thread honest about what the customer actually received.

Trade-off

A genuine regression — delivered then failed — needs an explicit exception in the ranking rather than being handled by the general rule.

02

Make the messaging window a first-class property of the conversation.

Why

Every send decision depends on it, so computing it once per conversation and exposing it to the composer, the template picker and the scheduler avoids three implementations that can disagree.

Trade-off

The value is time-dependent, so it is recomputed on render and re-checked at send time. The interface can be a minute stale; the send path cannot be.

03

Attach conversations to contacts, and contacts to normalized phone numbers.

Why

The same customer messages from a number written five different ways across systems. Normalizing to E.164 at every boundary is what allows one contact record instead of five.

Trade-off

Numbers without a resolvable country code need a default region, which is configuration rather than inference.

04

Treat Hinglish as normal input rather than a failure of language detection.

Why

A large share of real messages are Latin-script Hindi mixed with English. Systems that force a single detected language produce drafts that read as wrong to the customer.

Trade-off

Automated intent tagging is less certain on mixed script, so intent is shown as an editable tag rather than a locked classification.

07Challenges

What was genuinely difficult

Not the setup work. These are the problems where the first implementation was wrong and had to be reconsidered.

01

Duplicate and out-of-order webhooks produced duplicated messages and threads that lied about delivery.

Approach

Inbound events are deduplicated on provider message id before any write. Status transitions are applied through a rank comparison so only forward moves are accepted, and unknown statuses are logged rather than applied.

Outcome

Threads became a reliable record. A redelivered webhook is a no-op instead of a second bubble in the conversation.

02

Agents kept composing free-form replies that could not be delivered because the service window had closed.

Approach

The composer derives its mode from the window. Outside it, the free-form field is replaced by the template picker with an inline explanation and the parameter fields for the chosen template, and send is re-validated server-side.

Outcome

The failure mode disappeared from the agent’s experience, and template usage became a deliberate choice rather than a workaround.

03

Optimistic sends made the thread feel fast but risked showing a message that never left.

Approach

An optimistic message is inserted with a queued state and a client-generated key, then reconciled when the provider id returns. Failures move to a failed state with a retry action rather than vanishing.

Outcome

The interface stays responsive while never showing a message as sent that the provider rejected.

08Business value

What it changes for the business

Stated qualitatively on purpose. Invented percentages are the easiest thing to put on a portfolio and the easiest thing to see through.

Operational effect

  • Customer history stops living on personal phones and survives staff changes.
  • Every conversation has one owner and a visible waiting time, so unanswered enquiries are findable.
  • Platform messaging rules are enforced where the work happens, removing the most common cause of undelivered business messages.
  • Agents answer faster on repetitive enquiries without a customer receiving an unreviewed automated reply.
  • Gives an owner real numbers on their busiest channel: response time, resolution time and what customers are actually asking about.

What would change at scale

  • Move webhook processing behind a durable queue with a dead-letter path, since inbound volume is bursty and provider retries are unforgiving of a slow handler.
  • Add per-number send rate limiting and quality-rating awareness, because platform quality throttling is a real operational risk for a business that scales messaging.
  • Support multiple business numbers with per-number routing and templates for teams operating across brands or regions.
  • Build an evaluation set of real conversations to test drafting changes before release, rather than judging prompt edits by feel.

09Interface

The screens where the work happens

Dense operational views rather than dashboards. These are used for hours at a time, so the priorities are legibility, keyboard flow and state that is never ambiguous.

Team inbox

Conversations with owner, intent tag, last message and time waiting, with unanswered items surfaced first.

Conversation thread

Message history with per-message delivery state, contact panel alongside, and the drafted reply in the composer.

Window-aware composer

Free-form input inside the service window; template selection with parameter fields and a stated reason outside it.

Channel report

First response and resolution times with intent mix by period.

The screen above is built in HTML and CSS for this case study. It reproduces the layout, states and vocabulary of the real build without exposing client data, which is why it exists rather than a screenshot. It is evidence of design and of the decisions behind it. It is not a photograph of a deployed system, and no part of it is a capture of anyone else’s product.

10Technologies

What it is built with

Chosen for the shape of the problem, not for novelty. Anything unusual is justified in the decisions section above.

Frontend
  • Next.js App Router
  • TypeScript
  • Tailwind CSS
  • Server Actions
AI layer
  • Intent classification
  • Mixed-script language handling
  • Reply drafting
Messaging
  • WhatsApp Business Platform
  • Webhook idempotency
  • Template registry
  • Delivery receipts
Data
  • PostgreSQL
  • Message log keyed by provider id
  • Contact attribute store

11Technical preview

Structure, models and annotated excerpts

There is no repository link on this site. What is available instead is the module structure, the data model, the interface contracts and annotated excerpts written for this case study — enough for a technical reviewer to judge the engineering.

Technical preview

Implementation detail for this build

Selected implementation details are available for technical review: component structure, data models, architecture notes and sanitized code excerpts. Some client-specific source material stays private because of confidentiality. Enter the project access keyword if you have been given one — the same one works across every case study.

A presentation convenience, not authentication. This is a static site, so the keyword ships to your browser with the page and anyone reading the bundle can find it — worth saying plainly rather than dressing it up. Nothing confidential is stored behind it.

Inside this section

  • Module and folder structure for the build
  • Data models and the interface contracts between layers
  • 2 annotated implementation excerpts
  • Design notes covering the decisions the excerpts imply
  • The same keyword opens every case study on the site

For private client work, contact me for a walkthrough.

Next step

Need something along these lines?

Send the process, the constraints and the deadline. You will get an honest scope, an architecture sketch and a timeline before any commitment.

Email
surajk86808@gmail.com
Based in
Bengaluru, India
Working hours
IST (UTC+5:30)
Availability
Taking new engagements