Skip to content

Quotes and discount approval

Quotes and discount approval: a Quote below the Offer’s floor waits for your approval before it sends.

A Quote below the Offer’s floor never sends on its own: the price check refuses it and asks for your approval first.

The record

LineList priceDiscountNetTerm
offer_2 · $2,400 a year$2,40030 %$1,6802 years
The Quote and the Discount approval it opened · sample
{
  "quote": {
    "$id": "https://api.sb/leaseline.app/quotes/quote_2",
    "$type": "Quote",
    "status": "draft",
    "total": {
      "amount": 1680,
      "currency": "USD"
    },
    "validUntil": "2026-11-02",
    "lines": [
      {
        "offer": "offers/offer_2",
        "quantity": 1,
        "listPrice": 2400,
        "discountPercent": 30,
        "net": 1680,
        "term": "2 years"
      }
    ],
    "concessions": []
  },
  "approval": {
    "$id": "https://api.sb/leaseline.app/approvals/approval_3",
    "$type": "Approval",
    "verdict": null,
    "deadline": "2026-10-21T17:00:00Z",
    "action": "Quote.send",
    "on": "quotes/quote_2"
  }
}

The price Check reads the Offer’s floor. Below it, the Quote waits on a Discount approval in your queue, with a deadline, and sends once you approve.

Run it

Discount approvalMode try
You, to your agent

The buyer wants 30 % off the $2,400 plan. Get that approved, then send the Quote. Show me first; send nothing.

curl -X POST "https://api.sb/leaseline.app/quotes/quote_2/send?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

curl -X POST "https://api.sb/leaseline.app/approvals/approval_3/approve?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note":"Two-year term"}'

curl -X POST "https://api.sb/leaseline.app/quotes/quote_2/send?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
import { $ } from 'startup-builder'

await $.Quote.send({ quote: 'quote_2' }, { mode: 'try' })   // Northgate Rentals, 30 % off the $2,400-a-year plan
// 422 · The Quote to Northgate Rentals did not send: 30 % off the $2,400-a-year plan is below the Offer’s floor.
// price: Get the discount approved, or quote at the floor. · then Approval.approve
const approval = await $.Approval.approve({ approval: 'approval_3', note: 'Two-year term' }, { mode: 'try' })   // the Discount approval the refusal opened
return await $.Quote.send({ quote: 'quote_2' }, { mode: 'try' })   // the same Quote, approved
npx startup-builder do Quote.send --json '{"quote":"quote_2"}' --try
npx startup-builder do Approval.approve --json '{"approval":"approval_3","note":"Two-year term"}' --try
npx startup-builder do Quote.send --json '{"quote":"quote_2"}' --try
{
  "name": "do",
  "arguments": {
    "code": "await $.Quote.send({ quote: 'quote_2' }, { mode: 'try' })   // Northgate Rentals, 30 % off the $2,400-a-year plan\n// 422 · The Quote to Northgate Rentals did not send: 30 % off the $2,400-a-year plan is below the Offer’s floor.\n// price: Get the discount approved, or quote at the floor. · then Approval.approve\nconst approval = await $.Approval.approve({ approval: 'approval_3', note: 'Two-year term' }, { mode: 'try' })   // the Discount approval the refusal opened\nreturn await $.Quote.send({ quote: 'quote_2' }, { mode: 'try' })   // the same Quote, approved",
    "mode": "try"
  }
}
Response200application/json
{
  "quote": {
    "$id": "https://api.sb/leaseline.app/quotes/quote_2",
    "$type": "Quote",
    "status": "sent",
    "total": {
      "amount": 1680,
      "currency": "USD"
    },
    "validUntil": "2026-11-02",
    "lines": [
      {
        "offer": "offers/offer_2",
        "quantity": 1,
        "listPrice": 2400,
        "discountPercent": 30,
        "net": 1680,
        "term": "2 years"
      }
    ],
    "concessions": []
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/action_12",
    "operation": "Quote.send",
    "status": "done",
    "mode": "try"
  }
}
sample

Refuses when

422RefusedThe Quote to Northgate Rentals did not send: 30 % off the $2,400-a-year plan is below the Offer’s floor.
CheckFixThen
price fail · Not live yet, gaps #1Get the discount approved, or quote at the floor.POST /{namespace}/approvals/{approval}/approve
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The Quote to Northgate Rentals did not send: 30 % off the $2,400-a-year plan is below the Offer’s floor.",
  "checks": [
    {
      "check": "price",
      "status": "fail",
      "observed": "30 % off, floor 15 %",
      "doc": "/code/refusals#check-price",
      "fix": "Get the discount approved, or quote at the floor.",
      "then": "Approval.approve"
    }
  ],
  "approval": "approvals/approval_3"
}

It says no, says why, and names the fix.

CheckOnRefusesThen
price · Not live yet, gaps #1POST /{namespace}/quotes/{quote}/senda Quote below the Offer’s price floorPOST /{namespace}/approvals/{approval}/approve

Plays that use it

PlayWhat it does
Closer handoffHands a large Deal that stalled twice to a commissioned closer, paid only on collected revenue, and tests it against the Deals your agent keeps.
Trust packSends the trust page and prefilled security answers with every large Quote, and releases the security report only after a click-through Agreement.
Data residencyData residency answers where a buyer’s records live, sends the eu Quote with its annex, and holds acceptance until the region reads back.
Risk-reversal offersTakes the risk off the buyer: a written results-or-free bar, a 14-day top-tier trial with no card, a one-press refund and free data moves.
Paid pilotRuns your product on the buyer’s own data for a fee, against pass marks no higher than they already saw, signed before it starts.

Compiled, not written: edit its page, then regenerate. Every step runs from a sentence or a line of code. In your words: the CRM words you know, and where each lives here.

Contents