URL: /capabilities/convert-visitors/sales-closing · Id: `page:/capabilities/convert-visitors/sales-closing`

# Sales closing

> Your qualified leads taken to signed orders by a commissioned closer, with agents on the briefs and proposals; billed only on collected revenue.

Your qualified [leads](https://startupbuilder.dev/business/nouns/lead) taken to signed [orders](https://startupbuilder.dev/business/nouns/order) by a commissioned closer, with agents on the briefs and proposals; billed only on collected revenue.

```text title="Run it · Ask"
Close my 12 qualified leads this month at $268.20 a signed Order, billed only once they pay, and show me the plan first.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Deal.close({ goal: 'Close my 12 qualified leads this month at $268.20 a signed Order, billed only once they pay, and show me the plan first.', budget: { amount: 3218.4, currency: 'USD' } })
```

```json title="Run it · Response"
{
  "mode": "try",
  "stored": false,
  "estimate": "About $1.27 per 3 signed Orders",
  "bills": "$268.20 a signed Order on the $1,788 plan",
  "sample": {
    "account": "Harborview Property Management",
    "value": "$1,788 a year",
    "signed": "2026-12-09",
    "first payment": "cleared 2027-01-08",
    "billed": "$268.20"
  }
}
```

- **Kind:** Service
- **Price:** $268.20 per signed order
- **Your time:** 40 minutes
- **Approval:** A person does a step
- **Deepens:** [`capability:sales-closing`](https://startupbuilder.dev/systems/integrations/upstreams#sales-closing)

## What you get
- **3 signed orders** · Your qualified leads taken to signed orders by a commissioned closer, with agents on the briefs and proposals; billed only on collected revenue. · [`noun:order`](https://startupbuilder.dev/business/nouns/order)
- `orders[]` · Each signed order: the account, the value, the date its first payment cleared, and the lead and Play behind it.
- `lost[]` · Each deal the closer lost, with the buyer’s reason and the next step; none is billed.
- `bill` · 15% of each cleared order’s first-year value.

**Connect once:** [Google Calendar](/code/integrations/google-calendar), [Stripe](/code/integrations/stripe). **How long:** About 2 to 6 weeks a deal, from handoff to a cleared first payment.

## Trigger
It runs when you call it, or on any Trigger you set.

```ts
await $.Workflow.create({ verb: 'Deal.close', trigger: { schedule: 'weekly' } })
```

## Steps
Your agent does these steps, one row per step; each step’s check is part of its row and its price.

| Step | Verb | Returns | Price | Approval |
| --- | --- | --- | --- | --- |
| 1. Brief the closer on each deal | [`Deal.brief`](/capabilities/reach-out/account-brief) | Why they are buying now, the objection to expect and who signs | About $1.11 | Runs on its own |
| 2. The closer runs discovery and the demo | `Deal.advance` | The buyer’s need, the decision date and who signs, recorded on the deal | Free | A person does this step |
| 3. Draft the proposal | `Deal.propose` | A proposal on your offer, at or above its floor, sent within 5 business days of the first call | About 8¢ | Runs on its own |
| 4. Answer security and reference asks | `Content.draft` | Questionnaire answers from your trust page, and a reference from an opted-in customer | About 8¢ | Runs on its own |
| 5. The closer gets the signature | `Order.place` | A signed order on your offer | Free | A person does this step |
| 6. Read the first payment past the refund window | `Collection.query` | Each order paid and past 30 days, or refunded and credited | Free | Runs on its own |

Calls: `Deal.brief`, then `Deal.advance`, then `Deal.propose`, then `Content.draft`, then `Order.place`, then `Collection.query`.

About $1.27 per 3 signed orders, each time it runs, capped at $5.00.

## Example: give it a goal
> Close my 12 qualified leads this month at $268.20 a signed order, billed only once they pay, and show me the plan first.

The plan it shows runs 6 steps, priced before it spends anything; Run it above shows the result it returns.

## When something fails

| When | Then |
| --- | --- |
| A buyer asks for a price under the floor | The proposal waits for your approval; the closer never offers below it on their own. |
| A lead goes quiet before the first call | It comes back to you after 14 days with the last touch, and bills nothing. |
| An order is refunded inside 30 days | It is credited, and the reason is written to the deal. |

Each step retries three times, then falls through to the next route; one item's failure lands in `skipped` with its reason, never failing the call. Before a step would cross `maxCost` it stops and returns what it has, with a `resume` link. Each step's idempotency key is the call's key plus the step and the item: `leaseline-deal-close-1-<step>-<item>`.

## What it promises
| Term | This Service |
| --- | --- |
| Done | A signed order from a qualified lead you handed over, its first payment collected and past the 30-day refund window. |
| Counted by | `Order.paid` |
| Billed | $268.20 a signed order on the $1,788 plan, on acceptance |
| Target | Every qualified lead you hand over gets a proposal within 5 business days of its first call. |
| Accepted when | Accepted when the first payment clears the 30-day refund window. |
| Credited | An order refunded inside 30 days. |
| Remedy | A deal the closer loses bills nothing and comes back with the buyer’s reason and the next step; an order refunded inside 30 days is credited. |
| Evaluator | Code reads `Order.placed` and the first `Order.paid` from Stripe, and the close of the refund window. |
| Window | 90 days from handoff for each lead. |
| Assurance | `attested`, the weakest check on the way to done |
| Oversight | `performs-step`, because `high-stakes` |

**December: 12 qualified leads handed to the closer from Demand generation.**

| Count | What happened |
| --- | --- |
| 12 | Ordered |
| 3 | Delivered |
| 9 | First calls held; 3 leads went quiet before the call and came back to you. |
| 4 | Proposals sent, each within 5 business days. |
| 3 | Orders signed. |
| 1 | Refunded inside 30 days: credited. |
| **2** | **Accepted, billed 2 × $268.20 = $536.40** |

## Change it
| Ask | Compiles to |
| --- | --- |
| Hand over only leads with 50 or more units. | [`Deal.close`](/capabilities/convert-visitors/sales-closing) |
| Offer annual prepay at 2 months free on every proposal. | `Deal.propose` |
| Send me each lost deal’s reason every Monday. | [`Metric.query`](/code/apps/analytics-and-experiments/query) |

```ts
import { $, Service } from 'startup-builder'

export default Service({
  name: 'deal-close',
  verb: 'Deal.close',
  input: { leads: 'string[]', offer: 'string', handoffWithin: 'string' },
  maxCost: 5,
  builtFrom: ['Deal.brief', 'Lead.route'],
  oversight: { posture: 'performs-step', reason: 'high-stakes' },          // a commissioned closer runs the calls and gets the signature
  contract: {
    done: 'Order.paid', accept: { after: 'refund-window', window: '30d' }, assurance: 'attested',
    bills: { share: 0.15, of: 'first-year-value' }, credits: ['refunded-within-30d'], remedy: 'return-with-reason',
  },
  execute: async (ctx, { leads, offer, handoffWithin = '5d' }) => {
    for (const lead of leads) {
      const brief = await ctx.step(`brief:${lead}`, () => $.Deal.brief({ lead, maxCost: 0.2 }))
      const call = await ctx.task(`call:${lead}`, { to: 'role:sales-lead', brief })                  // a person runs it
      if (call.outcome !== 'advance') continue
      await ctx.step(`propose:${lead}`, () => $.Deal.propose({ deal: call.deal, offer, within: handoffWithin }))
    }
  },
})
```

Extend it with `extends: 'Deal.close'` and `base()`, or [compose your own](/code/compose) from these steps.

## Works with
**Plays that order it:** [Closer handoff](/plays/closer-handoff), [Data residency](/plays/data-residency), [Paid pilot](/plays/paid-pilot), [Risk-reversal offers](/plays/risk-reversal-offers), [Trust pack](/plays/trust-pack), [Written references](/plays/written-references).

| Built from | Kind | Its own price |
| --- | --- | --- |
| [Account brief](/capabilities/reach-out/account-brief) | Agent task | About 9.3¢ a brief |
| [Inbound routing](/capabilities/convert-visitors/inbound-routing) | Workflow | About 0.4¢ an inbound |

It serves [Convert visitors](/capabilities/convert-visitors). It deepens [`process:sell`](https://startupbuilder.dev/workflows/processes/sell) and [`capability:sales-closing`](https://startupbuilder.dev/systems/integrations/upstreams#sales-closing).

## For agents

| Fact | Value |
| --- | --- |
| Guide | `Deal.close` |
| Guide approval | `ask` |
| Goal | Close my 12 qualified leads this month at $268.20 a signed order, billed only once they pay, and show me the plan first. It may change counts, the order of steps, soft filters and the route a read takes, and it stops early when the goal is met. It never relaxes your words, raises its own budget, answers its own approval, calls a Play or acts outside your standing approval. |
| Retry | Three times with backoff, then the next route; the same idempotency key never charges, sends or posts twice |
| Idempotency key | `leaseline-deal-close-1` |
| Lookups | A `find:` input asks unless exactly one record fits |

| Step | Action class | Seat rule that would hold it |
| --- | --- | --- |
| 1. Brief the closer on each deal | None | None. |
| 2. The closer runs discovery and the demo | None | None. |
| 3. Draft the proposal | None | None. |
| 4. Answer security and reference asks | None | None. |
| 5. The closer gets the signature | `spend` | None. |
| 6. Read the first payment past the refund window | None | None. |

The amounts live once, on the hub ([approvals](https://startupbuilder.dev/agents/approvals)).

| Step | Function | Doer | Checker | Assurance | Inputs |
| --- | --- | --- | --- | --- | --- |
| 1. Brief the closer on each deal | `agentic` | The [AE](/capabilities/agents/ae) agent | A second model checks each fact in the brief against its source | `graded` | `$0.leads` |
| 2. The closer runs discovery and the demo | `human` | A person in the [AE](/capabilities/agents/ae) seat | The call’s notes and next step read back onto the deal within 2 hours | `attested` | `$1.briefs` |
| 3. Draft the proposal | `agentic` | The [AE](/capabilities/agents/ae) agent | A second model checks the proposal against your offer and its price floor | `graded` | `$2.deals, $0.offer` |
| 4. Answer security and reference asks | `agentic` | The [SE](/capabilities/agents/se) agent | Each answer quotes your trust page or a signed reference, checked by a second model | `graded` | `$3.asks` |
| 5. The closer gets the signature | `human` | A person in the [AE](/capabilities/agents/ae) seat | Code reads `Order.placed` back from Stripe | `attested` | `$3.proposals` |
| 6. Read the first payment past the refund window | `code` | Code | Stripe’s `Order.paid`, read back after the 30-day refund window closes | `measured` | `$5.orders` |

The doer is never the checker, and the weakest assurance on the path is the whole call’s.

## Under the hood

| Kind | What it touches |
| --- | --- |
| Systems | [CRM](/code/apps/crm), [sites and content](/code/apps/sites-and-content) |
| Nouns | [`noun:deal`](https://startupbuilder.dev/business/nouns/deal), [`noun:content`](https://startupbuilder.dev/business/nouns/content), [`noun:order`](https://startupbuilder.dev/business/nouns/order), [`noun:collection`](https://startupbuilder.dev/business/nouns/collection) |
| Events | `Deal.advanced`, `Deal.proposed`, `Content.drafted`, `Order.placed`, `Collection.queried` |

## Reference

| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `leads` | `Lead[]` | Required | The qualified leads you hand over, each with its sourcing Play. |
| `offer` | `Offer` | Required | What the closer sells, with its price floor; nothing is offered below it without your approval. |
| `handoffWithin` | `string` | `'5d'` | How soon each lead gets a proposal after its first call. |

Emits `Deal.closed`. Refuses with [`max-cost`](/code/refusals#max-cost) before it spends, and with the Data calls and Accounts groups ([refusals](/code/refusals)).