Build notes
Receipts, not adjectives
Every WhatsApp platform calls itself reliable, transparent and fairly priced. Adjectives are free. Nobody has ever chosen software because a page called itself honest.
So these are notes on what actually happened while building Klaros. The defect that would have quietly given a paying customer a third of what she bought. The opt-out our own sales code almost answered with a price list. The decisions where the flattering option and the true one were not the same, and what we picked.
There is one idea underneath all of them, and it has a name: digital distance, the gap between what a customer believes you remember and what your software actually knows. That gap is never announced. It is felt, and then it is acted on quietly, by someone who simply comes back less often.
The same gap can open between a business and its vendor. You believed the plan included three lines. The wallet drained faster than the page implied. Leaving turned out to mean a support ticket. Nobody argues about these things. They just remember them. So we hold ourselves to the standard we sell, and when we fall short of it we would rather write it down than hope you do not notice.
Meta Platform Tracker & Technical Roadmap
These build notes document what we observe while building directly on Meta's WhatsApp Cloud API. For Meta's complete 2025–2026 platform changes, deprecations, and pricing deadlines: See the WhatsApp Business API Roadmap 2026 Tracker →
-
8 September 2026 · AI architecture & maturity framework
Klaros Pragmatic AI Maturity: A Situational Agentic Framework for WhatsApp CRM
Modern AI engineering focuses heavily on autonomous multi-agent swarms and self-improving prompt harnesses. However, in commercial WhatsApp CRM messaging, unconstrained swarms carry massive risks of rate limits, hallucinated commitments, and high latency. This engineering note details the Klaros Situational AI Maturity Framework: an 8-level fail-closed priority decision tree in agent-decision.mjs, a $0 zero-token Jaccard Q&A cache in learned-answer.mjs, a fact-fenced RAG responder in ai-auto-reply.mjs, and a pre-validation JSON repair engine in json-repair.mjs for open local LLMs (Ollama/Qwen). Evaluates YC Harness Club principles against production CRM requirements.
-
7 September 2026 · commerce & platform
Building an Enterprise Edge-Native PIM Master for Precious Commodity Commerce
Generic PIM systems assume static product pricing and flat catalog models, failing when applied to precious metal commodities, gold/silver purity formulas, and heavy multi-channel catalog syndication. This engineering note details how we built an enterprise-grade, edge-native PIM Master on Cloudflare Workers, D1, and R2. We cover our dynamic live spot-rate pricing engine with a 36-hour stale-rate circuit breaker, parent-child matrix schema migration, 4-pillar fault-tolerant binary sheet and remote image ingestion pipeline, rotatable Google Merchant Center XML feed syndication, and zero-dependency 60 FPS DOM virtualized catalog table.
-
3 September 2026 · reliability & consent
The WhatsApp quiet hours that were loudest at 3am
Every regulation that defines quiet hours defines them at the called party’s location. Ours compared against getUTCHours(), which is the server’s idea of the time and nobody else’s. For an Indian recipient a 21:00 to 08:00 window silenced sending from 02:30 to 13:30 their time, which is most of a working day, and cheerfully permitted it at 03:00 local. Not merely wrong: exactly inverted, and worse the further a deployment sits from Greenwich. This note covers why a hardcoded offset table is the wrong fix, why an unknown timezone must fail open rather than silence somebody, and the second half of the same commit: Meta’s per-user marketing cap, which we knew about, excluded from campaigns, and had never applied to the lifecycle senders that walked straight into it.
-
3 September 2026 · platform & migration
What survives when you move to the official WhatsApp API
The most-asked question about leaving an unofficial WhatsApp library is whether you lose your history, and most answers to it are wrong in the flattering direction. Verified against our own sync code rather than asserted: contacts, groups and memberships transfer, in batches of 500, idempotently, and can be re-run safely. Conversation history does not transfer at all, because Meta does not permit importing prior conversations into the Cloud API, and no vendor can work around a restriction that lives on Meta’s side. This note documents exactly which fields survive, why the history limit is structural rather than a missing feature, what an empty thread costs an agent on day one, and the one thing worth doing in the fortnight before you switch.
-
3 September 2026 · reliability & platform
The WhatsApp broadcast that quietly lost its tail
Every HTTP client is taught the same rule: 4xx is your fault, do not retry; 429 and 5xx are transient, back off and try again. Meta breaks it. The WhatsApp Cloud API returns its throughput caps, 130429, 131048 and 131056, as ordinary 4xx rather than 429, so a correct implementation of that rule permanently fails every message caught by a cap that would have cleared on its own within the hour. On a broadcast that means the back half of the send is discarded and marked failed while the front half delivered, and nothing in the response says a cap was involved. Documents the three codes, why the failure is invisible, the classifier that fixed it, and the free CC-BY dataset of every code we document, with their retry semantics, generated from the classifier that actually runs on our send path.
-
3 September 2026 · reliability & platform
The WhatsApp session that logged itself out 377 times
A WhatsApp Web session that regenerated QR codes 377 times in one night, and the process leak underneath it. Killing a Chromium without confirming it had died left eleven of them alive at once, every one holding the same LocalAuth directory, every one invoking takeoverOnConflict against the others, until WhatsApp did the only sensible thing and logged the device out. The logout was not Meta detecting automation. It was our own zombies fighting over one auth directory. Documents the full cascade, why SIGKILL is not a kill, and the three fixes: a verified kill that polls until the PIDs are actually gone, a per-session lifecycle mutex so a teardown always completes before the next spawn, and a relink policy that parks a session instead of regenerating QR codes unattended for hours.
-
1 September 2026 · AI evaluation & reliability
Engineering Klaros AI WhatsApp Agent with Diligent Evaluation
Nuts and Bolts of Building a Production Grade Voice and Text Product Orchestrator. How we moved from basic prompt engineering to an enterprise-grade evaluation harness (agent-eval v1.0), F0-F5 Cloudflare infrastructure fidelity, micro-confidence voice safeguards (<0.70 handoff), synthetic mutation testing (20/20 detected), and an 8-step controlled rollout protocol (0% to 100%) backed by canonical RFC 8785 JCS SHA-256 evidence.
-
29 August 2026 · platform & cost
The day there is no free way to answer a WhatsApp customer
Meta starts charging for WhatsApp service messages on 1 October. It starts charging for utility templates inside an open window on the same day, which closes the escape route every explainer is recommending. Our own cost screen called those replies free in six places, including a recommendation that overstated what you had wasted. Also: a deadline we asserted nine times and could not verify, and why Meta's own pricing page still says the window is free.
-
28 August 2026 · commerce
Building a WhatsApp catalogue that tells the truth
Meta's catalogue batch endpoint returns HTTP 200 even when every item was rejected. The script we wrote specifically to verify a token could write reported success against a catalogue that was empty and had always been empty. Eleven bugs from three weeks of building catalogue and product infrastructure, almost all of the same shape: something reporting success for work it had not done. Includes a paywall that only worked while the feature was switched off, a complete edit endpoint with no button behind 5,187 passing tests, and the two calls we got wrong ourselves.
-
19 August 2026 · AI architecture & safety
Klaros Chatbot As-Is AI Architecture: Fail-Closed Design and Zero-Token Grounding
A first-hand developer perspective on our existing WhatsApp chatbot architecture. Outlines our choices behind the "Rules First, LLM Tail, Human Override Always" priority tree in agent-decision.mjs, human staff takeover yield, fact-fenced auto-responder in ai-auto-reply.mjs, zero-token learned answers cache in learned-answer.mjs ($0 token cost), pure JS BM25 retrieval in retrieve.mjs, and D1 token cost accounting.
-
19 August 2026 · updated 21 August 2026 · AI architecture & roadmap
Klaros WhatsApp Autonomous AI Agent: To-Be Architecture for a 7-Star Experience
A candid developer architectural roadmap challenging our own past design decisions, now carrying a correction. The hybrid sparse-dense retrieval this note proposed had already been written and registered ahead of every other strategy, and it had never executed once: the Cloudflare Vectorize binding it depended on does not exist on the worker, so every request took its fallback branch and re-served plain BM25 while reporting success. The audit that found it also found the real defect, which was more mundane and worse: ingest deletes the 173 question-and-answer pairs the site publishes in its own structured data, then asks a ranking function to reconstruct them from the prose. Dense retrieval is deferred in favour of contextual BM25 and reranking.
-
17 August 2026 · performance
The WhatsApp inbox that re-downloaded itself every visit
We were sure the WhatsApp inbox was slow because of the database. Two missing indices and a message-processing path re-fetching the same settings row up to five times, all real, all fixed, none of it the answer: a synthetic request touching no database at all cost the same 502ms as the real conversation list. Real Cloudflare RUM data put the dashboard's median load at 5.0 seconds. The actual cause: over 40 dashboard JavaScript files, every one served
Cache-Control: no-cache, including files already carrying a cache-busting hash whose entire purpose was the caching that wasn't happening. -
15 August 2026 · agentic design
The WhatsApp assistant that could explain booking but not book
At 13:00 we shipped a screen that cross-references what our assistant can explain against what it can actually send. It reported scheduling as explainable and not sendable. At 13:56 somebody typed “Book a meeting for me” and was told a person would pick it up, while a working scheduler sat one function away. No corpus entry fixes that: a request for an action is not a question. What closed it, why the enforcement lives in an allow-list rather than the prompt, and the shadowed question that would have denied a feature we had shipped four hours earlier.
-
13 August 2026 · conversational AI
The WhatsApp auto-reply that answered a hello with a price list
A contact of five weeks typed “Hello” and received an explanation of our licensing. The model was not hallucinating: the thread query selected the oldest 40 rows of a 46-message conversation, so it was shown messages 21 to 40 and never saw the greeting it was answering. Every timestamp had been stripped too, so a pricing exchange from three weeks earlier read as the previous turn. Investigating one bad reply surfaced seven more ways the same assistant was failing to listen, including voice notes answered with total silence, “cancel my order” recorded as an unsubscribe, and a customer who asked to speak to a person and was ignored twice.
-
10 August 2026 · performance
The WhatsApp inbox that rebuilt itself every five seconds
When a WhatsApp message arrives, Meta's webhook delivers it to the server, but the server has no way to push it to the agent's browser. So the inbox polls every five seconds. Until this fix, every poll destroyed and recreated 50 conversation-row nodes, even when no new message had arrived. A four-field hash now compares the list shape before rendering; if it matches, the function skips the rebuild. Full DOM rebuilds dropped from roughly 5,760 per 8-hour shift to a few dozen. Because Klaros is self-deployed, operators can query their own D1 and measure exactly how much redundant work the server does on their behalf.
-
10 August 2026 · performance
The WhatsApp inbox skeleton that made things worse
Shimmer skeleton loaders replaced stale content during WhatsApp conversation filter switches. But
loadConversations()was a zero-argument function called from 30 sites, including the background poll that checks for new webhook deliveries. The skeleton fired on every poll, flashing every 5 seconds, but only on inboxes smaller than the page size: exactly the state a shop starts in after completing Meta's Embedded Signup. The fix was one parameter: 9 user-initiated call sites pass{ skeleton: true }; the ~20 incremental updates (resolving, assigning, sending templates) and the poll do not. -
8 August 2026 · the landscape
What you are actually buying when you buy WhatsApp
Not about us, for once. Ask an owner sending ten thousand messages a month what Meta charges them per message and most cannot say, because the number arrives inside somebody else's invoice. A map of the three layers: what Meta actually bills for (less than you think, and replying is free), why the Solution Partner and Tech Provider distinction is about billing rather than capability, what the middle layer genuinely earns its fee doing, and the three questions that decide whether you can ever leave.
-
8 August 2026 · consent
The WhatsApp opt-out that almost got a sales pitch
We sell Klaros inside a WhatsApp thread, which puts our own sales code in the same inbound path that decides whether somebody's opt-out gets recorded. The pricing intent matches
pricing; "stop sending me pricing" contains it. And because a handled sales message suppresses the consent check, losing that fight would not have meant a tactless reply. It would have meant the opt-out was never recorded at all. The guard, the same rule applied four times, and the gap we found while writing this: a politely worded opt-out is still heard by nobody. -
7 August 2026 · engineering
The WhatsApp business cards that started asking for money
Two features wanted the same short URL prefix, and the newer one was mounted first. For five days, scanning any of our free digital business cards returned "This payment link is not valid." Why neither route could move (one URL is fixed inside an approved Meta template, the other is printed on paper), the three-line fallthrough that fixed it, the passing test that was quietly asserting the bug, and the telemetry blind spot that means we can never count who saw it.
-
6 August 2026 · engineering
The WhatsApp contacts we silently stopped scoring
Our own health check found 68 dead-lettered enrichment messages, 100% one type, lined up exactly with two nights of the nightly cron. The cause was three
UPDATEstatements writing to agraph_contactscolumn that never existed. What broke, what it quietly cost every contact that should have been scored, and the regression tests we proved could catch the bug before trusting them, by reintroducing it first. -
4 August 2026 · engineering
Five guards on automated WhatsApp payment requests
A sequence, a rule, a completed Flow or a customer typing "how do I pay" can all produce a real payment request in the thread. Building that took a day. The rest of the work was the five things it must refuse to do: a consent check that fails closed, a duplicate-ask guard that once answered "already requested" forever about someone never asked, an oversell guard found willing to sell one ring to fifty people, a closed 24-hour window, and a ₹500 advance that used to mark a ₹2,500 order paid and shipped.
-
31 July 2026 · engineering
WhatsApp payments with Razorpay: what the docs leave out
Collecting payment inside a chat in India, written while shipping it. The
order_detailspayload that passes validation, why a bare UPI VPA is rejected, the INR-only rule and how it fails silently, payment links versus subscriptions in a thread, whether your notes reach the webhook, and the signature check that rejects every real event while returning a clean boolean. -
31 July 2026 · engineering
The WhatsApp CRM billing we fixed before charging anyone
A jeweller pays for three WhatsApp lines and silently receives one. She does not complain. She decides the software is small, and six weeks later she does not renew. That was a real defect in our code, and four others sat beside it, unnoticed because no money had ever moved through the system that held them. What we found in the room where the money moves, the two forks where the flattering answer lost, and the tool that now checks what we charge against what we publish.
-
In progress
The half of a sale that nobody demos
Every platform shows you the payment landing. Almost none show you the twenty minutes afterwards: who gets told, who packs it, what the buyer hears while they wait, and what happens when it ships four days later and the messaging window has closed.
-
In progress
Where the ask ends and the shop begins
A payment request is messaging machinery. A product library is a commerce application, and the part most likely to be replaced by a real one. On finding that seam in our own code, and making it a documented extension point instead of a function that happened to sit in the middle of a file.
-
In progress
What a feature looks like when nothing consumes it
Contact limits computed on every request and enforced nowhere. A tier ladder that is marketing copy at runtime. On the difference between building a capability and shipping one, found in our own codebase.
Get the next one on WhatsApp
Message the line and type NOTES. The latest one comes straight back, in the same thread, from the number that sends everything else. Reply STOP whenever you like and it stops.
Send NOTES on WhatsAppAsk our WhatsApp number what it costs
The most honest demo we have is the purchase itself. Message the line and type pricing: you will get our live catalog as a WhatsApp list, real remaining slots, and a payment link on whatever you tap. Buy the self-deployed licence and your signed key arrives in the same thread, for infrastructure we cannot reach. You are experiencing the product before you own it.
+91 97893 77634 · you message first, so nothing reaches you without your say-so.