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
| Line | List price | Discount | Net | Term |
|---|---|---|---|---|
offer_2 · $2,400 a year | $2, | 30 % | $1, | 2 years |
{
"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
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"
}
}Response200
application/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"
}
}
sampleRefuses when
| Check | Fix | Then |
|---|---|---|
price fail · Not live yet, gaps #1 | Get 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.
| Check | On | Refuses | Then |
|---|---|---|---|
price · Not live yet, gaps #1 | POST /{namespace}/quotes/{quote}/send | a Quote below the Offer’s price floor | POST /{namespace}/approvals/{approval}/approve |
Plays that use it
| Play | What it does |
|---|---|
| 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 | 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 | 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 | 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 | 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. |
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.