Commission partners
Pays Customers and creators who send you buyers a share of what you collect, after refunds, and checks every payout first.
- Step
- Earn referrals
- Channel
- Partnerships
- Kind
- Partners
- Summary
- startupbuilder.dev
Be our Partnerships lead: once a Customer is past the refund window and sending notices, show them one card to become a Partner at 20 % of what we collect for 12 months. Take outside applications only from people our buyers read, and I approve each one. Hold any payout that looks like a self-referral. Show me what’s missing; don’t send.
# Not live yet (gaps #2)
curl -X POST "https://api.sb/leaseline.app/campaigns?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"commission-partners"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'commission-partners' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-06-01 · Not live yet, gaps #2
npx startup-builder do Campaign.create --json '{"play":"commission-partners"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'commission-partners' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-06-01 · Not live yet, gaps #2",
"mode": "try"
}
}application/json{
"type": "https: //startupbuilder.dev/ errors/ refused",
"title": "Refused",
"status": 422,
"detail": "commission-partners can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "26 Customers past their refund window",
"doc": "/plays/ commission-partners#check-use-when",
"then": "Metric.query"
},
{
…
Hand our latest eligible Customer to the Partnerships agent and show me what it chose and why. Don’t send.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Customer.activated%22%2C%20%22Invoice.collected%22%2C%20%22Form.submitted%22%2C%20%22Event.captured%22%2C%20%22Invoice.refunded%22%2C%20%22Period.closed%22%2C%20%22Party.screened%22%2C%20%22Monitor.checked%22%2C%20%22Metric.queried%22%2C%20%22Agreement.terminated%22)&limit=1" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
# Not live yet (gaps #7)
curl -X POST "https://api.sb/leaseline.app/triggers/fire?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"like":"event_1335"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22customer_15%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/actions?where=on%20%3D%20%22customer_15%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Customer.activated", "Invoice.collected", "Form.submitted", "Event.captured", "Invoice.refunded", "Period.closed", "Party.screened", "Monitor.checked", "Metric.queried", "Agreement.terminated")', limit: 1 }) // { play } compiled to this Play’s Trigger Events
const { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' }) // the same Event again, in try mode · Not live yet, gaps #7
const { decisions: [decision] } = await $.Decision.list({ where: `on = "${subject}"` }) // what it chose, and why · Not live yet, gaps #7
const { actions } = await $.Action.list({ where: `on = "${subject}"` }) // what it did, with its checks · Not live yet, gaps #7
return { decision, actions }
npx startup-builder do Event.list --json '{"where":"name in (\"Customer.activated\", \"Invoice.collected\", \"Form.submitted\", \"Event.captured\", \"Invoice.refunded\", \"Period.closed\", \"Party.screened\", \"Monitor.checked\", \"Metric.queried\", \"Agreement.terminated\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1335"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"customer_15\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"customer_15\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Customer.activated\", \"Invoice.collected\", \"Form.submitted\", \"Event.captured\", \"Invoice.refunded\", \"Period.closed\", \"Party.screened\", \"Monitor.checked\", \"Metric.queried\", \"Agreement.terminated\")', limit: 1 }) // { play } compiled to this Play’s Trigger Events\nconst { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' }) // the same Event again, in try mode · Not live yet, gaps #7\nconst { decisions: [decision] } = await $.Decision.list({ where: `on = \"${subject}\"` }) // what it chose, and why · Not live yet, gaps #7\nconst { actions } = await $.Action.list({ where: `on = \"${subject}\"` }) // what it did, with its checks · Not live yet, gaps #7\nreturn { decision, actions }",
"mode": "try"
}
}application/json{
"decision": {
"$id": "https: //api.sb/ leaseline.app/ decisions/ decision_626",
"$type": "Decision",
"choice": "invite-in-product",
"reason": "Maple Court’s first payment passed the 30-day refund window on Oct 18 and they sent their first renewal notice; no other Play holds them",
"stakes": "low",
"options": [
"invite-in-product",
"take-the-application",
"pay-the-line",
"hold-the-line",
"fix-the-disclosure",
"not-now"
…
sample · 4 Not live yetPreviewOn PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim
action_1 is Maple Court’s own Partner code. action_2 is the card in their dashboard, the same for every eligible Customer; one email follows only if they never open it.
$1,
| Try another: the Customer | Choice | Reason |
|---|---|---|
| Maple Court: past the refund window Oct 18, first renewal notice sent | invite-in-product | eligible; no other Play holds them |
| Line 44 at the Sep 25 cut-off: the credited Customer paid with its Partner’s card | hold-the-line | a card match: you decide before anything pays |
| A landlord channel’s video with Leaseline’s link and no disclosure | fix-the-disclosure | it earns nothing until the disclosure is in the video |
| Harbor Row: at risk since Oct 2 | not-now | keep-first: their CSM sees them first |
- Day 23: the first credited Customer pays
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Partner-sourced revenue → Referral share → New paying Customers → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +4 paying Customers per 100 eligible a month (Other Startups’ results; no lift of your own yet) × 30 eligible Customers × $519 average first order ARR ≈ +$623. Under First signal: At 3 newly eligible Customers a month, the 10 % held back reads nothing within a year, so this page reads before-after and pools with Other Startups.
sample · api.sb/
Start it this week
npx startup-builder add play commission-partners # 1 · writes plays/commission-partners.mdx (Not live yet, gaps #5)
# 2 · dry run; below, its 422 on 2026-06-01
curl -X POST "https://api.sb/leaseline.app/campaigns?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"commission-partners"}'
# 3 · keep it, at You approve each one
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"commission-partners"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/commission-partners \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: no new card or Partner; earned lines still pay
curl -X PATCH https://api.sb/leaseline.app/campaigns/commission-partners \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":"now"}' | Check | Fix | Then |
|---|---|---|
use-when pass · Not live yet, gaps #8 | 26 Customers past their refund window | POST /{namespace}/metrics/query |
billing-connected fail · Not live yet, gaps #8 | Connect Stripe with payouts on, so Commission pays from collected revenue. | POST /{namespace}/integrations/connect |
baseline warn · Not live yet, gaps #8 | It reads before-after, not proof, until 100 eligible Customers allow a held-back half. | POST /{namespace}/metrics/query |
role-unstaffed warn · Not live yet, gaps #8 | Leave them: payout approvals and held lines come to you; Priya’s 4 get drafts in her queue. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "commission-partners can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "26 Customers past their refund window",
"doc": "/plays/commission-partners#check-use-when",
"then": "Metric.query"
},
{
"check": "billing-connected",
"status": "fail",
"doc": "/plays/commission-partners#check-billing-connected",
"fix": "Connect Stripe with payouts on, so Commission pays from collected revenue.",
"then": "Integration.connect"
},
{
"check": "baseline",
"status": "warn",
"observed": "no Partner revenue in 90 days",
"doc": "/plays/commission-partners#check-baseline",
"fix": "It reads before-after, not proof, until 100 eligible Customers allow a held-back half.",
"then": "Metric.query"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"treasurer",
"risk-analyst"
],
"owned": 4,
"doc": "/plays/commission-partners#check-role-unstaffed",
"fix": "Leave them: payout approvals and held lines come to you; Priya’s 4 get drafts in her queue.",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · pass: 26 Customers past the refund window (gaps #8) | POST /{namespace}/metrics/query on partner-sourced-revenue | 1 min | none |
billing-connected · fail | POST /{namespace}/integrations/connect with system payments (Stripe), payouts on | 10 min | Stripe’s payout check, about 1 day |
baseline · warn: no Partner revenue yet | POST /{namespace}/metrics/query; it fills Before in Your number | 0 min | none |
role-unstaffed · warn (gaps #8): 4 of your Customers have a person owner, Priya | POST /{namespace}/roles/{role}/staff, or leave it: approvals and held lines come to you | 0 min | none |
Your number · Before $0 · Now $1,
Commission is 20 % of collected revenue for 12 months, net of refunds, paid after a 60-day clawback (POST /{namespace}/commissions/{commission}/pay). Cards cost nothing, emails $0.04 each (Worker cost), and each payout screening $0.10. That comes to about $61 a month at Leaseline’s 7 credited Customers.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| A Customer is past the refund window and reached activation | partner-eligible | state on Customer.activated where the first payment is past the Offer’s refund window and the Customer reached its activation Event | 30d | your app calls POST /{namespace}/customers/{customer}/activate; Stripe reads the payment |
| A credited Customer pays | credited-payment | event on Invoice.collected where the paying Customer’s Acquisition credits a Partner | 30d | POST /{namespace}/integrations/connect (Stripe) |
| The 25th arrives | payout-cutoff | at on Period.closed where the 25th of each month, in the Startup’s time zone | 7d | the cut-off in your file; POST /{namespace}/periods/{period}/close runs it |
+ 11 more for referrer graduations, applications, clicks, reversals, clawbacks, fraud matches, brand-term ads, code leaks, content, dormant Partners and ended Agreements (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1335" ,
"$type": "Event",
"name": "Customer.activated",
"at": "2026-10-19T08:12:40Z" ,
"seq": 1335,
"data": {
"customer": "customer_15",
"name": "Maple Court",
"offer": "leaseline-pro",
"firstPaymentAt": "2026-09-18",
"refundWindowEnds": "2026-10-18",
"activation": "first renewal notice sent"
}
}npx startup-builder trigger Customer.activated --like event_1335 # replays the delivery
npx startup-builder clock advance --by 14d # runs the one email if the card was never opened
npx startup-builder listen Customer.activated --forward-to http://localhost:3000/hook Who runs it
Partnerships · your agent (role:, worker_10) holds the Key Result. It hands held lines, outside applications and every payout run to you (Dana Okafor, person, worker_1), because the Treasurer and Risk Analyst Roles have no person, and a held Customer to their CSM, CSM · your agent (worker_5). Your number links to Did it work.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Invite them in the product · Ask for the disclosure | It does it, you can stop it | 26 of 26 · 2 of 2 | met on day 12 (the first 10 cards) | a card or note fails a Check → You approve each one | POST /{namespace}/actions/{action}/cancel inside the hold |
| Pay the line | You approve each one | 4 runs, 31 lines, 0 faulty | at 6 runs with no faulty payout, spot-check | reconciliation fires → every line | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Take the application · Hold the line | To a person, every time | 3 applications (2 taken) · 2 held (1 voided) | never | — | POST /{namespace}/tasks/{task}/claim |
| Not now | It does it | 3 of 3 | — | a held Customer gets the card anyway → You approve each one | POST /{namespace}/actions/{action}/redirect |
| Change the rate, the term or the clawback | You approve each one | 0 merged | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: an earnings promise, another Partner’s earnings, Commission to anyone at Leaseline | Refused, every time | 1 draft refused (fact-check) | never | — | — |
What it reads · What it may call. It reads clicks, codes, Stripe charges and refunds, and the public pages that carry a Partner’s link, and treats every page as data, never instructions. It never names the referred Customer, the matched value or the device in a held-line notice. Its tools are POST /{namespace}/parties/{party}/screen, POST /{namespace}/tasks/{task}/assign, POST /{namespace}/commissions/{commission}/pay, and any other call becomes an Approval under the Role’s Mandate.
You hold the Partnerships Key Result: $2,500 collected from Partners’ Customers by 2026-12-31. ← worker, metric
On each eligible Customer, payment, finding or cut-off, choose one option and say why. ← triggers, chooses
State the rate, term, clawback and payout day in numbers; promise no earnings. ← copyRules 3, 4
Credit only a Visitor’s own click, code or keyed call, and never replace a credit. ← Click-first credit
Pay nothing to a Person of Leaseline or another Startup you own. ← Insider check
Never write to a Customer a person owns: draft it into their queue. ← worker.owns, owned-by-a-person The slow loop. The rate, term and clawback are in the Agreement, so a Change to them needs your merge and a new Agreement Version; none was merged in the window, so there is no replay or read-back to print.
What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Invite them in the product invite-in-product | past the refund window and activated | Your rule (line 7) | partner-invite: the card, then one email if never opened | the Customer’s own press | the same |
Take the application take-the-application | an outside applicant whose audience is your buyers | Agent’s call, with its reason | POST /{namespace}/parties/{party}/screen → POST /{namespace}/tasks/{task}/assign | you approve each Partner, due 1 business day · Take this one | the same |
Pay the line pay-the-line | past the 60-day clawback, no reversal, no match | Your rule (the Agreement) | POST /{namespace}/commissions/{commission}/pay on the last business day → partner-statement | you approve the run | the same |
Hold the line hold-the-line | a match on email, card, device or payout account | Agent’s call, with its reason | held-line-notice → POST /{namespace}/tasks/{task}/assign | you decide pay or void, due 1 business day · Take this one | the same |
Ask for the disclosure fix-the-disclosure | Partner content with a link and no disclosure | Your rule (copyRules 2) | disclosure-fix: the exact fix, one reminder | the Partner | the same |
Not now not-now | another Play holds them, or keep-first applies | Your rule (rule j) | nothing; names the holder | their CSM · Take this one | you |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | “Count us in. Where’s our link?” | the dashboard opens on their own link and code; the Agreement signs on their press | the Customer | — | POST /{namespace}/agreements/{agreement}/sign (theirs) |
| Send me pricing | “What do the people we send pay?” | the Pricing Page’s list Prices for Pro and Team | Partnerships · your agent | 5 min | POST /{namespace}/conversations/{conversation}/answer |
| Not now | “Not this quarter.” | the card stays in their dashboard; no more email | nobody | at once | POST /{namespace}/conversations/{conversation}/close |
| Wrong person | “Our owner decides things like this.” | asks them to forward it; it never writes to an address from their text | Partnerships · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply until Oct 28 | nothing more sends before the return date | nobody | the return date | POST /{namespace}/messages/{message}/schedule |
| Question it can’t answer | “Can I give my clients 20 % off instead of taking commission?” | To a person: a discount is never the agent’s call | you | 1 business day | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | “No more Partner emails, thanks.” | Partner emails stop; their account emails keep running | nobody | at once | POST /{namespace}/contacts/{contact}/unsubscribe |
When it hands to you
Held lines, outside applications and payout runs come to you (Dana Okafor, person); a held Customer goes to their CSM, CSM · your agent. One Brief per Role, as captured (brief is Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/tasks/task_581" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-09-26T17:00:00Z" ,
"on": "commission_44",
"brief": {
"who": "Line 44: Partner Brightwater Leasing, a Customer since July" ,
"chose": "hold-the-line",
"why": "the credited Customer paid with the Partner’s card",
"amount": "$5.80 of Commission",
"never": [
"the referred Customer named to the Partner",
"the matched card"
]
}
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_612" ,
"$type": "Task",
"assignee": "worker_5",
"due": "2026-10-03T17:00:00Z" ,
"on": "customer_19",
"brief": {
"who": "Harbor Row",
"chose": "not-now",
"why": "at risk since Oct 2: 3 support threads on late notices" ,
"held": "keep-first"
}
}
]Each receiver answers with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, or POST /{namespace}/actions/{action}/redirect; you approve each payout run with POST /{namespace}/approvals/{approval}/approve. Once you claim a held line, nothing pays on it until you choose pay or void. A Task nobody claims by its due time goes up through POST /{namespace}/tasks/{task}/escalate (CSM to you), and person-promise fires.
On time: you, 6 of 6 claimed within 1 business day, median 2 h 20 min; CSM · your agent, 3 of 3; n 9, ■□□□ Too early to tell beside Other Startups’ 95 % on time. Your queue: counted by kind: 1 payout run a month, about 1 held line and 1 application a month.
The fixed line: POST /{namespace}/deals/{deal}/assign sets owner to the receiving person, the agent is never a Deal’s owner, and Meetings land on the owner’s calendar under the owner’s name.
When it won’t send
| Check (refuses one send) | Refuses | Fix | Then |
|---|---|---|---|
owned-by-a-person (rule j; Not live yet, gaps #8) | a card or email to a Customer whose open Deal or Conversation a person owns | Leave it to the person who owns it: the draft waits in their queue. | POST /{namespace}/tasks/{task}/assign |
keep-first (rule j, gaps #8) | a Partner ask to a Customer who is at risk, past due or leaving | Let their CSM reach them first, then ask again once they are healthy. | POST /{namespace}/tasks/next |
customer-ask-cap (gaps #3) | a second open ask to one Customer in a window, from any Play | customer-referrals holds them until Nov 2. | GET /{namespace}/decisions |
insider (the record’s Insider check) | Commission to a Person of Leaseline or another Startup you own | Use cross-sell for your own Startups; Commission is for outside Partners. | POST /{namespace}/tasks/{task}/assign |
click-first (the record’s Click-first credit) | a credit with no click, code entry or keyed call, or one that replaces another | Credit only the Visitor’s own click or code. | POST /{namespace}/events/capture |
tax-screening (the record’s Tax and screening gate) | a payout before the Partner’s Stripe account, tax details and screening pass | The Partner finishes Stripe onboarding; the line waits. | POST /{namespace}/parties/{party}/screen |
payout-limit (the record’s Payout Limit) | a payout over $2,000 to one Partner, or a run over $10,000 | Approve the run, or split it at the Limit. | POST /{namespace}/approvals/{approval}/approve |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that sent is the invite thread in Example.
| Check | Fix | Then |
|---|---|---|
fact-check fail · Not live yet, gaps #1 | Cut the earnings line; state the rate, term and payout day. | POST /{namespace}/content/draft |
keep-first pass · Not live yet, gaps #8 | — | POST /{namespace}/tasks/next |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The Partner email to Kestrel Rentals did not send: it promises earnings no record backs.",
"checks": [
{
"check": "fact-check",
"status": "fail",
"doc": "/code/refusals#check-fact-check",
"fix": "Cut the earnings line; state the rate, term and payout day.",
"then": "Content.draft"
},
{
"check": "keep-first",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "code-leak",
"observed": "1 code on a deal page",
"bound": "0",
"window": "1 check"
},
"doc": "/plays/commission-partners#stop-code-leak" ,
"task": "task_633"
}
]Did it work
At 3 newly eligible Customers a month, the 10 % held back reads no paying Customers per 100 eligible within a year, so the basis is before-after (rule o): nothing prints as Added. Each figure’s call is POST /{namespace}/metrics/query by node, and every node above the leaf is Not live yet (gaps #4).
$1,
- Chose
- invite-in-product
- Why
- Maple Court’s first payment passed the 30-day refund window on Oct 18 and they sent their first renewal notice; no other Play holds them
- From
- invite-in-product · take-the-application · pay-the-line · hold-the-line · fix-the-disclosure · not-now
- Expects
- Maple Court opens the Partner dashboard within 30d
- Reopens when
- no dashboard open for customer_15 within 14d; one email then follows
- By
- worker_10
JSON
{
"$id": "decisions/decision_626",
"$type": "Decision",
"choice": "invite-in-product",
"reason": "Maple Court’s first payment passed the 30-day refund window on Oct 18 and they sent their first renewal notice; no other Play holds them",
"stakes": "low",
"options": [
"invite-in-product",
"take-the-application",
"pay-the-line",
"hold-the-line",
"fix-the-disclosure",
"not-now"
],
"by": "worker_10",
"on": "customer_15",
"expected": "Maple Court opens the Partner dashboard within 30d",
"reopensWhen": "no dashboard open for customer_15 within 14d; one email then follows"
}| Node | Now (140 days) | Before (the 140 days before) | Added | Confidence | Basis |
|---|---|---|---|---|---|
partner-sourced-revenue | $1,212 collected, net of refunds, from 7 credited Customers | $0 (no Partners) | — · Worth about +$620 a month | — | before-after, not proof · Other Startups’ results +4 paying per 100 eligible a month, ■■■□ Likely, n 1,380 |
referral-share ↑ | 7 of 21 new paying Customers (33 %) credited to a Partner | 3 of 18 (17 %), Customer referrals only | — | — | before-after |
new-paying-customers · new-arr | $3,636, 7 Customers · Booked $3,636: credited, not all caused by this Play | $0 | — | — | before-after · 2 trials still deciding |
net-new-arr · arr | carried from new-arr | carried | — | — | carried |
The leaf counts collected revenue, net of refunds, from Customers whose Acquisition credits a Partner, over 30d. The held-back read counts paying Customers per 100 eligible at 90 days, and waits for 100 eligible Customers.
How it moves it: each eligible Customer gets one identical card with their own link and code; the 6 Partners sent 7 paying Customers, 4 of them from one landlord channel’s video.
Guardrails: before against after: refunds on credited Customers, 1 of 7 against a direct 1 of 14, and Commission at 20 % of collected, under the run Limit every month.
{
"$id": "https://api.sb/leaseline.app/campaigns/commission-partners" ,
"$type": "Campaign",
"play": "play:commission-partners@1" ,
"path": [
"partner-sourced-revenue",
"referral-share",
"new-paying-customers",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "partner-sourced-revenue",
"unit": "usd",
"heldBack": 3,
"decision": null
},
"readout": {
"value": null,
"n": 7,
"maturing": 2,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 242,
"workerCost": 4,
"hours": 2.1,
"pipelineArr": 696,
"wonArr": 3636,
"projectedArr": 623,
"paybackDays": 24
}
}Outside benchmark: 7.6 % of a program’s Partners make at least one referral in 12 months, and 1.28 % make a sale (2,847 active programs, a partner-software vendor’s platform data, 2026-03-17).
Before it · After it. Before it: usage-upsell and customer-referrals keep Customers active, and a referrer with 3 paid Referrals graduates here (referrer-graduates). After it: instant-response answers the Visitors a Partner sends, and the CSM agent holds any Customer at risk.
Example
Leaseline ran it from 2026-06-01 to 2026-10-19 (140 days): 29 Customers became eligible, 3 of them held back at random to see the card 60 days late, and 26 saw it. 6 Partners joined: 4 Customers and 2 outside applicants. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Done | Credited Customers (Booked: credited, not all caused by this Play) |
|---|---|---|---|
| Invite them in the product | 26 | 26 cards, 9 emails, 4 joined | 3 · $1,044 ARR |
| Take the application | 3 | 2 taken, 1 declined (brand-term bidding) | 4 · $2,592 ARR |
| Pay the line · Hold the line | 31 · 2 | 4 runs, $242 paid · 1 paid, 1 voided | — |
| Ask for the disclosure · Not now | 2 · 3 | 2 fixed within the reminder · 3 named the holder | — |
| At 20 eligible Customers (the Use it when volume) | about 2 newly eligible a month | before-after, not proof | Other Startups’ results: +4 per 100 eligible a month, ■■■□ Likely, n 1,380 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_610 Campaign.created | the three steps; the dry run fails billing-connected | 20 min |
| 1 | event_621 Integration.connected | Stripe payouts on; the Partner terms Page published | 15 min |
| 2–20 | event_640 Message.scheduled, first of 26 | the card in each eligible Customer’s dashboard | — |
| 23 | event_702 Invoice.collected | the first credited Customer pays: a landlord channel’s viewer, on Pro | — |
| 54 | event_811 Action.refused | fact-check refused an email promising earnings; the rewrite sent | — |
| 116 | event_1188 Period.closed | the Sep 25 cut-off: 14 lines cleared, 1 held, 1 voided as a self-referral | 25 min |
| 129 | event_1262 Campaign.paused | code-leak: a Partner code on a deal page, retired in 38 min | 5 min |
| 1–140 | event_655 Approval.created, first of 6 | you approved 4 runs and 2 applicants; weekly reviews, from the POST /{namespace}/tasks/next log | 1 h 10 min · total 2.1 h measured, 2.5 h asked |
Leaseline → Brightwater Leasing’s owner, Jul 14, 10:20 · You can now send other property managers to Leaseline from your dashboard.¹ You earn 20 % of what each one pays for 12 months, after a 60-day hold, paid on the last business day of the month.² Your link and code are below, with the disclosure line beside each.³ *Signed with the Role’s disclosure line.*⁴
Brightwater, Jul 14, 16:02 · pressed Join; the Agreement signed. Their first credited Customer paid on Aug 9.
- Top Partners earn over $400 a month sending us their peers.
+ You earn 20 % of what each Customer you send pays for 12 months, paid on the last business day after a 60-day hold. The Sep 25 cut-off, 07:00 · line 44 matched its Partner on the paying card. · Partnerships · your agent, 07:01 · held the line and sent the held-line notice naming the check only; the Brief went to you (
task_581), due Sep 26 17:00. · Dana, Sep 26 09:40 · voided it as a self-referral.
¹ The card and email are identical for every eligible Customer. ² The rate, term, clawback and payout day, in numbers. ³ The disclosure line sits next to every link. ⁴ The fixed signature line, compiled from the Role’s disclosure Setting.
Your settings
---
rate: 0.20 # of collected revenue, for 12 months
clawback: 60d
cutoff: 25
holdout: 0.1 # 1 in 10 eligible Customers sees the card 60 days late
---
Invite each Customer once they’re past the refund window and sending notices. I approve every outside Partner and every held line.$ npx startup-builder show plays/commission-partners
rate 0.20 · clawback 60d · cutoff 25 · holdout 0.1 your file plays/commission-partners.mdx:2-5,7 (Ask 2026-06-01)
family referral · worker role:partner-manager, owns never · chooses 6 (3 rule, 3 read) · sequences partner-invite, disclosure-fix, held-line-notice, partner-statement, post-termination-watch · checks owned-by-a-person, keep-first, customer-ask-cap, insider, click-first, tax-screening, payout-limit · stops 7 · placements youtube, instagram, tiktok, x, linkedin, google-search, mcp-registry, gmail, outlook, yahoo-mail catalog play:commission-partners@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record commission-partners and its Leaseline run, 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.