Demand generation
Your strategy’s Plays run for the month, billed per qualified lead, and every lead and dollar of revenue traced to the Play that sourced it.
- Kind
- Service
- Price
- $40 per qualified lead
- Your time
- 75 minutes
- Approval
- Goes out on its own
- Deepens
- Demand generation
Deliver 25 qualified leads this month from my Hands-on Plays, $40 each, and show me revenue per Play.
curl -X POST "https: //api.sb/ leaseline.app/ leads/ generate? mode= try" \
-H "Authorization: Bearer $SB_TOKEN" \
-H "Content-Type: application/ json" \
-d '{"goal": "Deliver 25 qualified leads this month from my Hands-on Plays, $40 each, and show me revenue per Play.", "budget": {"amount": 1000, "currency": "USD"}}'
npx startup-builder do Lead.generate --try --data '{"goal": "Deliver 25 qualified leads this month from my Hands-on Plays, $40 each, and show me revenue per Play.", "budget": {"amount": 1000, "currency": "USD"}}'
{
"name": "do",
"arguments": {
"mode": "try",
"code": "return await $.Lead.generate({ goal: 'Deliver 25 qualified leads this month from my Hands-on Plays, $40 each, and show me revenue per Play.', budget: { amount: 1000, currency: 'USD' } })"
}
}
import { $ } from 'startup-builder'
const result = await $.try.Lead.generate({ goal: 'Deliver 25 qualified leads this month from my Hands-on Plays, $40 each, and show me revenue per Play.', budget: { amount: 1000, currency: 'USD' } })
{
"mode": "try",
"stored": false,
"estimate": "About $30.95 per 25 qualified Leads",
"bills": "$40 a qualified Lead",
"sample": {
"play": "Warm intros",
"qualified leads": "4",
"first calls": "4",
"customers": "2",
"first-year revenue": "$3, 576"
}
}
What you get
- 25 qualified leads · Your strategy’s Plays run for the month, billed per qualified lead, and every lead and dollar of revenue traced to the Play that sourced it. · Lead
leads[]· Each qualified lead: the account, the person and title, what they asked for, and the Play that sourced it.byPlay[]· Per Play: leads, first calls, customers and first-year revenue read from Stripe.decisions[]· Each week’s change to the mix, with the readout row that caused it.bill· Accepted leads times the price, up to the target.
Connect once: Gmail, Google Calendar, Stripe. How long: The calendar month, read weekly.
Trigger
It runs when you call it, or on any Trigger you set.
await $.Workflow.create({ verb: 'Lead.generate', 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. Plan each week’s Play mix | PlayMix.compile | The week’s Plays, hours and sends, inside your budget and sending limits | About 20¢ | Runs on its own |
| 2. Run warm intros and personal first touches | Prospect.reach | Intros asked from your own inbox, and cold first touches from the warmed second domain | About $7.95 | Goes out on its own |
| 3. Answer buyers’ threads | Post.answer | Ten threads a week answered as you, every claim sourced | About $9.19 | Goes out on its own |
| 4. List on the directories your buyers read | Post.submit | Each listing submitted from your approved kit, then checked live | About $13.04 | Goes out on its own |
| 5. Answer every inbound within 5 minutes | Lead.respond | Each inbound answered from your pages, with a call or a trial offered | About 42¢ | Runs on its own |
| 6. Qualify each lead and name its Play | Lead.route | Fit, title and request checked, and the sourcing Play recorded on the lead | About 16¢ | Runs on its own |
| 7. Read each Play every week | Play.review | Each Play beside its benchmark: keep, fix or switch, naming the row that fired | Free | Runs on its own |
| 8. Read revenue back to each Play | Metric.query | First-year revenue per Play, from each paying customer’s first lead | Free | Runs on its own |
Calls: PlayMix.compile, then Prospect.reach, then Post.answer, then Post.submit, then Lead.respond, then Lead.route, then Play.review, then Metric.query.
About $30.95 per 25 qualified leads, each time it runs, capped at $40.00.
Revenue read back to each Play by month end. Warm intros brought the fewest leads and the most revenue per lead, so next month’s mix moves two hours a week to them.
| Play | Qualified leads | First calls | Customers | First-year revenue |
|---|---|---|---|---|
| Warm intros | 4 | 4 | 2 | $3,576 |
| Cold email | 11 | 9 | 1 | $1,788 |
| Community answers | 7 | 5 | 0 | Free |
| Directory listings | 5 | 3 | 0 | Free |
| In all | 27 | 21 | 3 | $5,364 |
Planning estimate for the per-Play rows.
Example: give it a goal
Deliver 25 qualified leads this month from my Hands-on Plays, $40 each, and show me revenue per Play.
The plan it shows runs 8 steps, priced before it spends anything; Run it above shows the result it returns.
When something fails
Each failure, and what happens next
| When | Then |
|---|---|
| A Play falls under its break row two weeks running | Its hours move to the Play the readout ranks next, and the Decision names the row that fired. |
| The month ends under the target | The work continues at no charge into the next month; only accepted leads are ever billed. |
| A paying customer has no sourcing Play | The revenue reads as unattributed in its own row, never spread across the Plays. |
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-lead-generate-1-<step>-<item>.
What it promises
| Term | This Service |
|---|---|
| Done | A qualified lead: a person at an account that fits, whose title matches, who asked for a call or a trial, with the Play that sourced it recorded. |
| Counted by | Lead.qualified |
| Billed | $40 a qualified lead, on acceptance |
| Target | 25 qualified leads a month, from the Plays your strategy names. |
| Accepted when | Each lead is accepted 7 days after it is qualified, unless you disqualify it with a reason. |
| Credited | Any lead you disqualify within 7 days with a reason. |
| Remedy | Continued work at no charge until the target is met, with hours moved to the Plays that delivered. |
| Evaluator | Code reads Lead.qualified with its fit, title and sourcing Play, and reads Stripe payments back to each lead. |
| Window | The calendar month. |
| Assurance | measured, the weakest check on the way to done |
| Oversight | none: agents do every step |
December, Leaseline’s second month on Hands-on, ordered at a target of 25.
| Count | What happened |
|---|---|
| 25 | Ordered |
| 27 | Delivered |
| 27 | Qualified from four Plays: cold email 11, community answers 7, directory listings 5, warm intros 4. |
| 2 | Disqualified by you within 7 days: one was a competitor, one a student. Credited. |
| 25 | Accepted and billed, the target met in week four. |
| 25 | Accepted, billed 25 × $40 = $1,000 |
Change it
| Ask | Compiles to |
|---|---|
| Run Launch and search instead, and count signups as leads. | Lead.generate |
| Move every hour from directories to warm intros. | PlayMix.compile |
| Show me revenue per Play for the last 90 days. | Metric.query |
import { $, Service } from 'startup-builder'
export default Service({
name: 'lead-generate',
verb: 'Lead.generate',
input: { strategy: 'string', icp: 'string', target: 'integer', hours: 'number' },
maxCost: 40,
builtFrom: ['Prospect.reach', 'Post.answer', 'Post.submit', 'Lead.respond', 'Lead.route', 'Play.review'],
oversight: { posture: 'none' },
contract: {
done: 'Lead.qualified', accept: { by: 'founder', within: '7d', silence: 'accept' }, assurance: 'measured',
bills: { usd: 40, per: 'qualified Lead', upTo: 'target' }, target: 25, remedy: 'continue-until-target',
},
execute: async (ctx, { strategy, icp, target = 25, hours = 5 }) => {
while ((await ctx.count('Lead.qualified', { accepted: true })) < target) {
const mix = await ctx.step('mix', () => $.PlayMix.compile({ strategy, hours, icp }))
for (const play of mix.plays) await ctx.step(`run: ${play.id}`, () => $.Play.apply({ play: play.id, hours: play.hours }))
await ctx.step('readout', () => $.Play.review({ plays: mix.plays.map((p) => p.id) }))
await ctx.sleep('1w')
}
return ctx.step('revenue', () => $.Metric.query({ metric: 'first-year-revenue', by: 'play', since: 'month' }))
},
})Extend it with extends: and base(), or compose your own from these steps.
Works with
Plays that order it: Cold email, Community answers, Directory listings, Launch sites, Warm intros.
| Built from | Kind | Its own price |
|---|---|---|
| Personal first touch | Agent task | About $1.33 per 100 people |
| Answer threads | Agent task | About $2.30 per 10 answers |
| Directory submissions | Workflow | About $13.04 per 40 directories |
| Answer every inbound | Agent task | About 1.1¢ an inbound |
| Inbound routing | Workflow | About 0.4¢ an inbound |
| Weekly readout | Workflow | Free |
It serves Find your first customers. It deepens Strategy and Demand generation.
For agents
For agents: the guide, its approvals, retries and lookups
| Fact | Value |
|---|---|
| Guide | Lead.generate |
| Guide approval | limits |
| Goal | Deliver 25 qualified leads this month from my Hands-on Plays, $40 each, and show me revenue per Play. 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-lead-generate-1 |
| Lookups | A find: input asks unless exactly one record fits |
| Step |
|---|
| 1. Plan each week’s Play mix |
| 2. Run warm intros and personal first touches |
| 3. Answer buyers’ threads |
| 4. List on the directories your buyers read |
| 5. Answer every inbound within 5 minutes |
| 6. Qualify each lead and name its Play |
| 7. Read each Play every week |
| 8. Read revenue back to each Play |
The amounts live once, on the hub (approvals).
Who does each step, and how it is checked
| Step | Function | Doer | Checker | Assurance | Inputs |
|---|---|---|---|---|---|
| 1. Plan each week’s Play mix | agentic | The Marketing lead agent | Code checks the mix against your hours, budget and the sending rule before anything runs | measured | $0.strategy, |
| 2. Run warm intros and personal first touches | agentic | The SDR agent | A second model checks every fact in each message against the row before it sends | graded | $1.mix |
| 3. Answer buyers’ threads | agentic | The Content lead agent | A second model checks every claim in each answer against your pages | graded | $1.mix |
| 4. List on the directories your buyers read | code | Code | Each listing read back from the directory until it shows, with its link type | measured | $1.mix |
| 5. Answer every inbound within 5 minutes | agentic | The SDR agent | A Lead.created read-back for every routed reply, timed from arrival | measured | inbound |
| 6. Qualify each lead and name its Play | code | Code | A Lead.qualified read-back carrying the fit, the title and the sourcing Play | measured | $5.leads, |
| 7. Read each Play every week | code | Code | Each Play’s numbers read against its break rows | measured | $6.leads |
| 8. Read revenue back to each Play | code | Code | Stripe payments read back to each lead and the Play that sourced it | measured | $6.leads |
The doer is never the checker, and the weakest assurance on the path is the whole call’s.
Under the hood
Under the hood: the Systems, Nouns and Events it touches
Reference
Inputs, outputs, its Event and its errors
| Name | Type | Default | Meaning |
|---|---|---|---|
strategy | Strategy | Required | The strategy whose Plays run: Hands-on, Paid, Launch and search, Borrowed, or Keep and grow. |
icp | string | Required | Your customer sentence; a qualified lead is at an account that matches it. |
target | integer | 25 | Qualified leads this month. Fixed when you order; the work continues at no charge until it is met. |
hours | number | 5 | Your hours a week for the calls and the replies only you can write. |
Emits Lead.generated. Refuses with max-cost before it spends, and with the Data calls and Accounts groups (refusals).