Skip to main content
The Quote Engine upgrades the GENERATE_QUOTE tool from a simple “request a quote” relay into a tool that computes and sends a real, numbered quote during the conversation — with line items, discounts, VAT and a total. The key principle: prices never come from the LLM. The agent only chooses references (a sku and a quantity); every amount is read from a pricing grid you control, server-side. A hallucinated price is impossible by design.

Two modes

GENERATE_QUOTE has two behaviors, decided automatically by its config:
ModeActive whenBehavior
Engineconfig.pricing is a valid gridAgent picks sku + qty, server computes the quote, sends a numbered email
Legacyno pricingAgent collects the request, two notification emails are sent (no computed amount)
Adding a pricing grid to an existing GENERATE_QUOTE tool switches it to engine mode. Removing it reverts to legacy. Existing tools are unaffected until you add a grid.

The pricing grid

The grid lives in config.pricing. All amounts are in cents (an integer), so 150000 = €1,500.00.
{
  "currency": "EUR",
  "items": [
    { "sku": "site-vitrine", "label": "5-page website",        "unit": 150000, "per": "flat" },
    { "sku": "page-supp",    "label": "Extra page",            "unit": 12000,  "per": "unit", "max": 20 },
    { "sku": "maintenance",  "label": "Monthly maintenance",   "unit": 8000,   "per": "month" }
  ],
  "rules": [
    { "whenTotalGte": 300000, "discountPct": 5, "label": "Volume discount" }
  ],
  "vat": 20,
  "validityDays": 30,
  "disclaimer": "Indicative estimate, not contractually binding."
}

Fields

FieldRequiredDescription
currencynoCurrency code. Defaults to EUR.
items[]yesThe catalogue. At least one item.
items[].skuyesStable reference the agent uses. Must be unique.
items[].labelyesHuman label shown on the quote.
items[].unityesUnit price in cents (positive integer).
items[].pernoUnit wording (flat, unit, month, hour…). Display only.
items[].maxnoMaximum quantity allowed for this line.
rules[]noThreshold discounts.
rules[].whenTotalGteApply when the pre-discount subtotal (cents) reaches this value.
rules[].discountPctDiscount percentage, in ]0, 100].
vatnoVAT rate in percent. Omit or set null for HT-only (no tax line).
validityDaysnoQuote validity, shown on the email.
disclaimernoFooter text. Defaults to an “indicative estimate” notice.
Discount rules are structured (whenTotalGte / discountPct), not free-text expressions. Animam never evaluates a tenant-supplied formula. When several rules qualify, the one with the highest discount wins.

How the agent uses it

In engine mode the tool exposes a single structured input:
{
  "visitorName": "Jane Doe",
  "visitorEmail": "jane@example.com",
  "lines": [
    { "sku": "site-vitrine", "qty": 1 },
    { "sku": "page-supp",    "qty": 4 }
  ],
  "note": "Optional cover note — text only, never an amount",
  "consentConfirmed": true
}
  • sku is an enum of your catalogue references — the agent cannot invent one.
  • qty is an integer; the server enforces any max.
  • note is free text the agent may write (a cover line). It is escaped and rendered as-is; it never carries pricing.
  • The agent never sends a price. The server computes subtotal → discount → VAT → total.

Soft-fail loop

If the agent references an unknown sku or a quantity above max, the tool returns a soft failure with a clear message, and the agent asks the visitor to clarify before retrying. Nothing is sent. Engine mode enforces explicit consent (GDPR): the tool refuses unless consentConfirmed: true, which the agent only sets after the visitor explicitly agrees to receive the quote by email. This guard applies to engine mode only — legacy GENERATE_QUOTE is unchanged.

The output

On success the engine:
  1. Computes the quote deterministically from the grid.
  2. Assigns a number DEVIS-YYYY-NNN (per-tenant, per-year sequence).
  3. Sends an HTML email with the line items, subtotal, discount, VAT and total — to the visitor and a copy to the tenant.
  4. Persists a ToolSubmission with quoteNumber, lines and totals.
  5. Returns the number and total to the agent, which announces them to the visitor.
Amounts in the email are rendered from the server computation; the LLM has no way to alter them.

Creating an engine-mode tool

Via the dashboard

Go to Tools → Quote request → Computed quote and paste the pricing grid as JSON. The grid is validated when you save (unique skus, positive integer units, discount bounds, VAT range). An invalid grid is rejected with the reason.

Via the API

curl -X POST https://api.animam.ai/tenants/your-slug/tools \
  -H "Authorization: Bearer ak_your_token" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "GENERATE_QUOTE",
    "name": "generate_quote",
    "description": "Build a priced quote from the catalogue and email it to the prospect.",
    "config": {
      "pricing": {
        "currency": "EUR",
        "items": [
          { "sku": "site-vitrine", "label": "5-page website", "unit": 150000, "per": "flat" },
          { "sku": "page-supp", "label": "Extra page", "unit": 12000, "per": "unit", "max": 20 }
        ],
        "rules": [{ "whenTotalGte": 300000, "discountPct": 5, "label": "Volume discount" }],
        "vat": 20,
        "validityDays": 30
      }
    }
  }'
Quote tools require the Starter plan or above, like all configurable tools. The pricing grid lives in Tool.config — no database migration is involved.

Security model

  • Amounts are server-authoritative. The LLM supplies sku + qty only; prices are read from the grid. This is the same rule as the VERIFIED_ACTION tool.
  • No tenant code is evaluated. Discounts are structured data, never an expression.
  • Consent is enforced before any email is sent.
  • Email values are HTML-escaped, including the visitor name and the agent’s cover note.

Roadmap (v2)

  • PDF rendering of the quote.
  • Quote statuses (sent / accepted) and follow-up.
  • A dedicated grid editor UI (today the dashboard uses JSON editing).
  • A “pay the deposit” link, coupling with COLLECT_PAYMENT.