# AI Chatbot Integration — Backend Answers

**Date:** 2026-07-01 · **From:** backend (Neel) · **Replies to:** `ai-chatbot-integration-questions.md`

Great writeup, Avi. Your §1 (settled) and §2 (app-side conclusions) are all correct and accepted,
including Option A (app-owned native chat surface, bridge to Freshchat on escalate). Answers below,
question by question. Several needed code changes; those are now live and reflected in `docs/API.md`.

---

## §3 Blockers

**1. API.md** — done and current: `docs/API.md`. Full request/response schema, all escalate_reason
values, `/feedback`, `/health`, and a curl example. Updated today with the new fields below.

**2. Auth** — agreed, it will NOT be an open endpoint. Recommended approach: the app sends the
**QuitSure `accessToken`** it already holds, in `Authorization: Bearer <token>`, and our service
validates it. To implement that I need one thing from the backend: how is the accessToken verified,
a shared JWT secret we can verify locally, or a token-introspection endpoint we can call? Whichever
it is, tell me and I will wire it. If we want to unblock staging immediately before that is settled,
we can start with a shared `X-API-Key` header and swap to accessToken validation for prod. Your call.

**3. Hosting** — we will deploy; base URL is TBD pending where it lives (that decision is with
Suraj/Ram). Plan: separate **staging and prod** URLs, auto-restart, HTTPS. Tell us any network
constraints (IP allowlist, region) and we will match them. I will send both URLs once deployed.

**4. Transport** — confirmed: **single, non-streaming JSON response**. Streaming (SSE) is not in v1.
Render the full `answer` on receipt. Given answers can be a few sentences, a typing indicator while
the request is in flight is enough. If long-answer UX becomes a problem we can add SSE later; it is
not planned now.

**5. Timeout / latency** — measured on the current build: **p50 ~2.5s, p95 ~4s** per call (Gemini
Flash). We enforce a **20s server-side timeout** on the model call. Recommended **client timeout:
30s**. On our side a timeout or error never hangs, it returns a graceful `service_error` escalation
(see reason table).

---

## §4 Contract details

**6. `history` format** — array of `{ "role": "user" | "assistant", "text": "..." }`, oldest first.
We use the **last 6 turns**, so sending the last 6 to 10 is ideal. No hard token cap, keep it sane.

**7. `escalate_reason` values** — the full enumerated set:
`null` (answered), `greeting`, `out_of_scope`, `no_confident_answer`, `medical_topic`, `crisis`,
`user_requested`, `user_frustrated`, `account_action`, `service_error`.
Note: `greeting` and `out_of_scope` come with `escalate=false` (just show the answer, no human).

**8. Channel routing** — done for you: the response now returns **`suggested_channel`**:
`"coaching"` or `"technical"` on escalation, `null` otherwise. Mapping: `account_action` and
`service_error` → `technical`; everything else that escalates → `coaching`. It is a hint, the app
still owns final routing and program gating. If your channel set differs, tell me and I will adjust
the mapping (single source of truth stays on our side).

**9. `coach_summary`** — one short sentence, now hard-capped at **300 chars**, safe for a Freshchat
user property. Only present when escalating.

**10. `/feedback` + message id** — done: `/chat` now returns a **`message_id`**. Send it back in
`/feedback` (`{ user_id, message_id, message, answer, rating: "up"|"down", note? }`) and we link the
rating to the exact reply.

---

## §5 Context & language

**11. Program codes** — confirmed mapping:
- `P3` = **QuitSure Original** (6-day)
- `P9` = **QuitSure Relaxed** (42-day, internally "LTP")
- `P11` = **LeanSure** (fitness, a different product). **Important: this KB is smoking-cessation
  only and does NOT cover LeanSure.** So P11 users should not be routed to this assistant yet. Your
  existing P11 gating away from Coaching is the right instinct, extend it to gate P11 from this bot
  too until a LeanSure KB exists. (Other codes P1/P2/etc are language variants, not relevant to v1.)

**12. Richer context** — yes please, it helps. We now accept optional **`program_day`** and
**`subscription_status`** (and `program`, `platform`) on `/chat`, and feed them to the model for
stage-specific and status-specific answers. Send whatever you have; more context = better answers.

**13. Language** — the AI answers in the **user's language automatically** (tested across Spanish,
French, German, Arabic, Tamil, Hindi, Hinglish). You do not have to pass anything, but you may send
an optional **`locale`** as a hint for short/ambiguous messages. On your `ge` for German: send it,
we normalize common variants; if in doubt use `de`. Auto-detection works either way.

---

## §6 Handoff, privacy & content

**14. Transcript in Freshchat** — your approach is exactly right and accepted: `coach_summary`
(+ transcript link) via `setUserProperties`, full transcript posted as a message via
`Freshchat.sendMessage`. No preferred format from us; whatever reads cleanly for the coach.

**15. Program gating (P11)** — our escalation output is channel-agnostic (we only suggest
coaching/technical). **The app should enforce program gating** (P11 must not land in Coaching), same
as you do today. Combined with answer 11 (P11 not on this bot at all for now), you are covered.

**16. PII in `history`** — no hard constraint on what you send, but please do not send more PII than
needed. On our side: we currently log messages to build the improvement loop. Before prod we will
set a **retention policy** (drop raw logs after a fixed window) and can hash `user_id`. If you have
a required policy, tell me and I will match it.

**17. KB updates** — source is the **Chat Shortcuts sheets** (content team / Barkha owns them). Today
the refresh is manual (rebuild from the sheet). We will formalize a versioned refresh so answers stay
current; no action needed from the app, answers update server-side without a client change.

**18. Seamless thread** — it is **app-side**, and your plan achieves it: on escalate, you carry the
AI transcript + `coach_summary` into the Freshchat conversation so the coach continues seamlessly.
We deliberately do NOT post into Freshchat ourselves (Ram's rule: we never touch Freshchat). So:
we hand you the summary and the answer, you make the thread continuous.

---

## What changed in the API today (from these questions)
- `message_id` on every `/chat` reply, accepted back in `/feedback`.
- `suggested_channel` (`coaching` | `technical` | `null`) on the reply.
- New optional request fields: `locale`, `program_day`, `subscription_status`.
- `coach_summary` capped at 300 chars.
- Confirmed reasons enum, latency numbers, and 20s server timeout / graceful `service_error`.

## Still on us before you build against prod
- Auth mechanism (need the accessToken verification detail from backend, answer 2).
- Deploy + base URLs (answer 3).

Everything else above is ready. `docs/API.md` is the live contract.
