Agentora TechnologiesAgentora
AI safety in production

A bot that speaks as someone else's business

When an AI answers a WhatsApp message on behalf of a client's business, a plausible invented price is not a glitch — it is the business making a commitment it never made. The design question is not how to make it clever. It is what happens when it is uncertain.

Agentora EngineeringJuly 18, 20268 min read

What this system does

Agentora's greenfield track can give a client a website and connected channels, including WhatsApp. Incoming messages to those channels are answered automatically. This case study covers how a message is routed to the right tenant and how the reply is constrained.

The problem

The reply is not sent by Agentora. It is sent by the client's business, from the client's number, to the client's customer. Anything the model asserts becomes something that business appears to have said.

That reframes the usual concern about model accuracy into something sharper. A fabricated opening time is an inconvenience. A fabricated price, discount, or eligibility statement is a commitment a real business may be held to by a real customer, and neither the business nor its customer has any way to tell that the number was invented rather than looked up.

The routing problem has to be solved first and cannot be solved from the message alone. An inbound webhook from a messaging platform arrives at one shared endpoint for every tenant on the platform. Nothing in the message body says which business it belongs to, and answering as the wrong tenant would be worse than not answering.

There is a third, quieter failure mode. A reply bot that depends on a model call has an availability profile: no credentials, an API error, a refusal, or an empty completion all produce nothing to send. A customer messaging a business and receiving silence is a worse outcome than a plain acknowledgement.

Constraints

The boundaries the design had to respect, before any solution was chosen.

  • A message must be attributed to exactly one tenant before any reply is generated.
  • The reply may only assert facts present in that tenant's own approved content.
  • Every failure path must still produce a message — silence is not an acceptable outcome.
  • The feature must ship inert, replying deterministically until it is deliberately enabled.
  • Replies are high-volume and per-message, so latency and cost per reply matter.

The architecture

Routing resolves the tenant from platform identifiers; generation is grounded strictly in that tenant's own content; and every failure degrades to a deterministic reply rather than to nothing.

  1. 1

    Resolve the tenant from the channel identifier

    The inbound webhook looks up the hosted tenant that owns the message's originating phone number identifier. An unrecognised identifier resolves to no tenant, which is treated as unknown rather than guessed at. Web enquiries route by subdomain in the same way, since that is the only identifier a public form has.

  2. 2

    Ground the reply in the tenant's own content only

    The model is given the tenant's generated business profile and site specification as its grounding, and nothing else. It is answering from the same approved content the client's own website presents, so a correct reply cannot contradict the client's public information.

  3. 3

    Forbid the specific categories that matter

    The system prompt explicitly forbids inventing prices, hours, availability, policies, discounts, or any promise not present in the grounding. These are named individually rather than covered by a general instruction to be accurate, because they are the categories where a fabrication becomes a commitment.

  4. 4

    Always degrade to a deterministic reply

    Every failure path — no API credentials, an API error, a refusal, an empty completion — falls through to a caller-supplied static reply. The model is an enhancement to a working deterministic path, not a dependency of it, so the customer always receives something.

  5. 5

    Ship dormant

    Because the absence of credentials is a fallback rather than an error, the feature ships inert: it sends the deterministic reply until a key is configured, exactly as the messaging adapter itself stays dormant until its own credentials are set. Deployment and activation are separate events.

  6. 6

    Right-size the model and the reply

    A per-message reply bot is a high-volume, latency-sensitive, low-complexity workload, so it uses a fast, low-cost model tier, overridable by configuration. It runs in the web application's own serverless function rather than the heavier engine, avoiding a container cold start on a path where someone is waiting. Replies are capped well under the platform's hard character limit.

Key decisions and their trade-offs

Every decision below cost something. The trade-off is stated alongside the reasoning.

Treat an unrecognised channel identifier as unknown rather than defaulting

Why
There is no safe default tenant. Replying as the wrong business is a worse failure than not replying, so the lookup returning nothing is a legitimate terminal state rather than something to recover from with a guess.

Trade-off
A tenant whose channel is configured incorrectly gets silence from the AI path until the mapping is fixed, with no partial behaviour to mask the misconfiguration.

Enumerate the forbidden categories instead of instructing general accuracy

Why
"Be accurate" is not actionable for a model deciding whether to estimate a price. Naming prices, hours, availability, policies, discounts and promises targets the specific failures that convert into business commitments.

Trade-off
The list is finite and will not anticipate every category, so it needs revisiting as the product covers more kinds of business.

Make the deterministic reply the foundation, not the error handler

Why
Inverting the usual arrangement — a static reply that the model improves upon, rather than a model call with a fallback bolted on — means no failure mode results in silence, and the code path for "model unavailable" is the same one used before the model existed.

Trade-off
The fallback is generic, so a degraded reply is unhelpful even though it is safe. It acknowledges the customer without answering them.

Ship the feature dormant

Why
Treating missing credentials as a fallback rather than a failure separates deploying code from activating behaviour. The feature can be released, reviewed and reverted without ever having spoken to a customer.

Trade-off
Dormant-by-default means the feature can appear deployed but inactive, so someone has to know that configuration is the remaining step.

Use a fast, low-cost model tier and run it in the web tier

Why
This is the opposite workload from document generation: short output, high volume, someone waiting. A smaller model in the serverless function answers promptly, where routing it through the heavier engine would add a cold start to a live conversation.

Trade-off
Less capable reasoning per reply than the tier used for generation, which is the right trade for short factual answers drawn from a small grounding but would not be for anything analytical.

Technologies used

Channels

  • WhatsApp Business webhooks
  • Web enquiry forms

Application

  • TypeScript
  • Next.js serverless functions

AI

  • Anthropic Claude (fast tier)
  • Grounded prompting
  • Deterministic fallback

Data

  • PostgreSQL
  • Per-tenant content grounding

Outcome

  • Inbound messages are attributed to exactly one tenant by platform identifier, and an unknown identifier is handled as unknown rather than answered by a default.
  • Replies are grounded in the tenant's own approved content, with the categories that become business commitments explicitly forbidden.
  • No failure path produces silence: missing credentials, API errors, refusals and empty completions all fall through to a deterministic reply, which is also why the feature ships inert until enabled.

Known limitations

What this design does not do. Stated because an architecture without documented trade-offs has usually not been examined closely enough.

  • The deterministic fallback is safe but generic — it acknowledges a customer without answering them, so a degraded path is a poor experience even though it is not a dangerous one.
  • Grounding is limited to the tenant's generated profile and site content. Questions beyond that content cannot be answered, by design.
  • The forbidden-category list is enumerated and therefore finite; new kinds of business may introduce categories it does not yet name.
  • WhatsApp channels additionally depend on platform-side business onboarding and approval, which is an external process rather than something the architecture controls.

Want this level of rigour on your AI initiative?

Start with a free AI Readiness Assessment, or book a Discovery Workshop to get a scored, costed roadmap.