URL: /revenue/quotes · Id: `page:/revenue/quotes`

# Quotes and discount approval

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

A [Quote](https://startupbuilder.dev/business/nouns/quote) below the [Offer](https://startupbuilder.dev/business/nouns/offer)’s floor never sends on its own: the price check refuses it and asks for your approval first.

## The record
| Line | List price | Discount | Net | Term |
| --- | --- | --- | --- | --- |
| `offer_2` · $2,400 a year | `$2,400` | `30 %` | `$1,680` | 2 years |

```json title="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

```text title="Discount approval · Ask"
The buyer wants 30 % off the $2,400 plan. Get that approved, then send the Quote. Show me first; send nothing.
```

```ts title="Discount approval · SDK"
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
```

```json title="Discount approval · Response · sample"
{
  "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"
  }
}
```

## Refuses when

```json title="422 · sample"
{
  "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"
}
```

| Check | On | Refuses | Then |
| --- | --- | --- | --- |
| [`price`](/code/refusals#check-price) · Not live yet, [gaps #1](/code/reference#not-live-yet) | <Op verb="Quote.send" /> | a Quote below the Offer’s price floor | <Op verb="Approval.approve" /> |

## Plays that use it
| Play | What it does |
| --- | --- |
| [Closer handoff](/plays/closer-handoff) | Hands 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 pack](/plays/trust-pack) | Sends the trust page and prefilled security answers with every large Quote, and releases the security report only after a click-through Agreement. |
| [Data residency](/plays/data-residency) | Data 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 offers](/plays/risk-reversal-offers) | Takes 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 pilot](/plays/paid-pilot) | Runs your product on the buyer’s own data for a fee, against pass marks no higher than they already saw, signed before it starts. |