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

2. Rules I meant — please keep

  1. No LLM anywhere near money. Fixed commands, deterministic parsing.
  2. 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.
  3. 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?
  4. A stale quote never books. Validity is checked server-side at booking.
  5. 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.
  6. 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 /trades needs agree_to_terms: true anyway.
  7. stop pauses 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

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

  1. 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.
  2. 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.