WhatsApp bot — what to keep from the prototype
From: Stevan · To: Kamen (cc Toma) · Date: 6 Oct 2026
On today's call you asked which parts of the prototype I actually meant and which just came into existence. This is that list, so you don't need to dig through the repo. Sections 1–5 are the bit to read; the appendix is wording you can lift as-is.
1. Scope for v1
Connect, settings, quote and book. Everything else is later (see 6).
| Client sends | Bot does |
|---|---|
| Anything, from an unlinked number | Link → CT login → consent page → linked |
settings or pair |
Saves a default pair, plus a default reason for transfer (see 4.4) |
50k gbp to eur |
Indicative quote with Book / Refresh |
50k |
Same, on their default pair. No default → asks for the pair |
rate gbp eur |
Keeps the pair, asks how much |
| Book | Re-quote → same or better: book → receipt. Worse: see 4.1 |
| Anything we can't parse | Help menu, with a link to the main CT WhatsApp for anything else |
- Amounts:
50000,50,000,50k,1.2m, decimals. Pairs:GBP to EUR,GBP EUR,GBP/EUR,GBP-EUR. Anything ambiguous → we ask, never guess. - Quotes and bookings get an instant acknowledgement first, as agreed.
- For clarity, the amount is always what the client sells. "I need to receive €50k" (e.g. paying an invoice) isn't supported yet. The API allows it (
side: buy), so worth adding early.
2. Rules I meant — please keep
- No LLM anywhere near money. Fixed commands, deterministic parsing.
- Caps: £25k per trade, £50k per day via WhatsApp (GBP equivalent). Over → hand to a person, nothing booked. If we can't price the GBP equivalent, hand off too. Reason: it's our main protection if someone takes over a client's WhatsApp.
- No beneficiaries, account settings or user admin from WhatsApp, so money can only ever go to payees the client already approved. Can we please enforce this as a permission on the WhatsApp channel, not just by not having a command for it?
- A stale quote never books. Validity is checked server-side at booking.
- No silent fills. The client books at the rate they saw or better, or at a worst case they explicitly agreed to (see 4.1). Never at a rate they haven't seen.
- T&C evidence. The message with the Book button carries the terms line, and we log the terms version, quote id and WhatsApp message ids with the trade.
POST /tradesneedsagree_to_terms: trueanyway. stoppauses every message we start (alerts, notifications). Not needed for v1 since we only reply, but needed the day we send anything first.
3. Things that just came into existence — ignore
- The "use templates" setting (
INTERACTIVE_BUTTONS). The Twilio sandbox can't show buttons, so the prototype fell back to "1. Book / 2. Refresh". On a real number it's always buttons. They don't need Meta approval inside the 24-hour window, but Twilio needs a Content API template per button set (the prototype creates them on the fly). Never tested on a real number, so worth checking early. - The credential vault, API keys,
DEV_BIND_*, and the linking callback and event webhook from my July ask. Only needed because the bot lived outside CT. - Demo leftovers:
BOOKING_ENABLED,DEMO_SOURCE=mock, the 90-second quote window, the "simulated" labels, the "this demo can't connect the chat to a dealer" reply, the mock CT server, transcripts and smoke scripts. - The reason for transfer
WhatsApp indicative quote, sent on every quote. A placeholder — must not reach a real trade. - The "which way round?" step in settings. It asks after the client has already said what they send and receive.
4. Changes since the call — shout if you disagree
4.1 "Book anyway", with a floor. I don't want us booking at a rate the client hasn't seen — that's the one dispute we can't win. Instead, after the 3 automatic re-quotes, we show the current rate and a floor, and Book anyway books at the best rate we can get as long as it's above the floor. The loop we worried about doesn't happen, because the tap doesn't need that exact rate to still be live.
Client taps Book on 20,000 GBP → EUR at 0.8600 (≈ 17,200 EUR)
3 re-quotes come back worse (latest 0.8580) → nothing booked
We show the current rate (0.8580) and a floor 0.25% below it (0.8559)
Client taps Book anyway → we re-quote:
0.8575 → above the floor → book, receipt shows 17,150 EUR
0.8550 → below the floor → nothing booked, offer Refresh / Talk to the team
0.25% is a starting point, TBD.
4.2 One message at a time per phone. Can we please process each phone's messages one at a time, in arrival order? It fixes the out-of-order replies you raised, and stops a double tap on Book from booking twice (each re-quote is a fresh quote, so already_booked won't catch it). Also: return 200 to Twilio straight away, do the work in a job, and skip any MessageSid we've already seen. The prototype held Twilio's request open for the whole CT call, and Twilio times out at 15s.
4.3 Linking. The consent page shows the full number, the link is single-use and expires after 15 minutes, and we email the client whenever a number gets linked, with how to unlink. Reason: someone could message the bot, get a link and forward it to a client who's logged in. If the client clicks Confirm, the other person's phone now controls their account.
4.4 Reason for transfer. POST /quotes requires reason, and POST /trades only takes the quote id + agree_to_terms, so we need it before quoting, not at booking. Proposal: a default in settings, else ask once before the first quote. I'll confirm the full defaults flow separately.
5. Questions for you
- What's production quote latency (p50/p95)? On beta, a pair check plus a quote took 11–13s. Those were weekend rejections, so weak evidence, but if prod is anywhere close, the 15s window is gone before the card reaches the phone.
- For v1 I'm assuming one phone → one account, picked on the consent page. Shout if that's wrong.
6. Later (not v1)
balance, status (last 5 trades), rate alerts (create / view / cancel), stop / start, an unlink command (the CT settings toggle covers v1), an opt-in morning rate digest, and trade / alert notifications. Anything we send first needs an approved Meta template and has to respect stop.
Happy to discuss.
Appendix — wording
Copy rules: reads like a person at CT texting a client. Short lines, the numbers first (receive amount in bold), bold titles. No "Reply X for Y" menus, footers, recaps or promised reply times. One emoji at most per message (only the ✅ on the receipt), none in errors. *bold* is WhatsApp markup; [Book] is a button.
rate gbp eurRef <trade ref>
Sell 20,000 GBP
Receive 17,200 EUR
Rate 0.8600
Value 2026-10-08team, or the Talk to the team button)