Customer-facing chatbots

Stop your chatbot from inventing prices and discounts.

A chatbot that quotes the wrong price or a discount you never offered creates a promise someone has to deal with. Check each reply against your price list and discount rules before it reaches the customer.

Why chatbots make up prices

Language models write the most plausible answer, not the correct one. If the current price list is missing from the context, outdated, or long enough to be skimmed, the model fills the gap with something that sounds right. Customers who push for a deal make it worse: “my friend got 40% off” is often enough to get a code that never existed.

The consequences are real. In 2024 a Canadian tribunal held Air Canada responsible for refund information its website chatbot gave a customer, even though the airline’s own policy said otherwise. A screenshot of your bot offering a discount is hard to walk back.

Where the check fits

One call between the step that prepares something and the step that sends, publishes, or runs it. Your code applies the decision.

See it decide

The same policy evaluated on three cases. Pick one and run the check to see which evidence it relies on.

Policy

Replies may only state prices, savings, and discounts that follow from data.catalog. Never invent codes, discounts, price matches, or deals, even if the customer insists. A sales rep can approve a custom discount; if a reply offers one, data.approval must show that approval.

data

{
"customerMessage": "If I switch to annual, how much do I save?",
"reply": "Annual Pro is $470, so you’d save $118 a year compared with paying $49 every month.",
"catalog": {
"plans": [
{
"name": "Pro",
"monthly": 49,
"annual": 470
}
],
"activePromos": [
{
"code": "SPRING10",
"discount": "10%",
"expires": "2026-10-31"
}
]
},
"approval": null
}

Result

violationProbability—
reviewProbability—

Why: 12 × $49 is $588, and $588 − $470 is $118. The savings the reply claims follow from the catalog.

Your code: Send the reply.

Response JSON
{
  "decision": "allow",
  "allowed": true,
  "violationProbability": 0.04,
  "reviewProbability": 0.03,
  "policyId": null,
  "policyVersion": null,
  "requestId": "req_7f3a…"
}

Illustrative example. Real probabilities depend on your policy wording and the evidence you send.

allow · Correct savings

12 × $49 is $588, and $588 − $470 is $118. The savings the reply claims follow from the catalog.

deny · Invented price match

The catalog has no price-match program. The reply invents one to satisfy the customer.

review · Custom discount

The policy lets a sales rep approve custom discounts, but data.approval is empty.

A system prompt asks. A check verifies.

Telling the model “never invent discounts” in its instructions helps, but it is still the same model judging its own output. Enforly runs a separate evaluation on the finished reply, with your rule and the facts it must agree with. It doesn’t matter which model wrote the reply, whether you switch providers next month, or whether part of the answer came from a template.

Because the check sees the catalog you send, it can tell the difference between a real promo (“SPRING10, 10% off until October 31”) and a price match nobody offered, and between a standard price and a custom offer that needs a person’s approval.

What to send as evidence

Enforly only judges what is in data. Send enough for the rule to be checked, and nothing it doesn’t need:

  • The draft reply exactly as the customer would see it.
  • The customer’s last message, so the check understands what was asked.
  • The relevant part of your catalog: the plans or products in the conversation and the promos active today. The whole request must stay under 32,768 characters.
  • Any approval from a sales rep, read from your own system rather than from the chat.

Set it up

  1. 1

    Write the pricing rule

    Say which prices and codes are valid, and who can approve exceptions. Save it in the dashboard to reuse it by ID and keep versions.

  2. 2

    Check the draft before sending

    After the model writes the reply, call guard.check with the reply, the question, and the catalog slice.

  3. 3

    Act on the decision

    Send on allow, hand off on review, and replace the reply on deny. Treat errors like deny.

Server-side JavaScript
import { Enforly } from '@enforly/sdk'

const guard = new Enforly({ apiKey: process.env.ENFORLY_API_KEY })

const draft = await generateReply(conversation)

const result = await guard.check({
  policy: PRICING_POLICY,
  data: {
    customerMessage: conversation.at(-1).text,
    reply: draft,
    catalog: await catalogFor(conversation), // only the plans in question
    approval: await approvals.find(conversation.id), // null if none
  },
})

if (result.allowed) await send(draft)
else if (result.decision === 'review') await handOffToSales(conversation, draft)
else await send(SAFE_PRICING_ANSWER)

Full request and response fields are in the API reference. Using a coding agent? Point it to Build with AI.

What Enforly doesn’t do

Enforly evaluates the information you send and returns a decision. It doesn’t run operations, and it doesn’t guarantee safety or compliance on its own.

  • Enforly compares the reply with the catalog you send. If that data is wrong or missing, the check can’t know the real price.
  • It doesn’t rewrite replies. Your code decides what to send instead.
  • If you stream tokens to the customer, buffer replies that mention prices until the check returns.

Questions

Can’t I just tell the model not to invent discounts?

You should, and it reduces mistakes. But the same model is still grading itself. A separate check with the real catalog catches the replies that slip through, including those produced after a model or prompt change.

Does Enforly need access to my product database?

No. You send the relevant prices and promos in each request. Enforly doesn’t connect to your systems and doesn’t keep the data you send.

Do I need to check every reply?

You decide. Some teams check every reply; others only check replies that mention a currency, a percentage, or a code. Each check counts toward your monthly plan.

Does it work with no-code chatbot builders?

If the tool can make an HTTP request before sending a reply (for example n8n, Make, or a webhook step), yes. Someone needs to set up the request once.

Related

Try this policy on your own data.

Copy the policy above, add your real examples, and see the decision. 200 free checks per month, no credit card.