Single sign-on upgrade
Answers each single sign-on ask within one business hour with the plan that includes it, and the admin tests sign-in before paying.
- Channel
- More seats and upgrades
- Kind
- Conversion
- Summary
- startupbuilder.dev
Be our CSM: when a Customer asks for single sign-on, answer within the hour with the plan that includes it, its price and today’s charge, and let their admin test sign-in before paying. At 50 seats or a security questionnaire, bring in our AE. 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":"sso-rung"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'sso-rung' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-07-20 · Not live yet, gaps #2
npx startup-builder do Campaign.create --json '{"play":"sso-rung"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'sso-rung' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-07-20 · Not live yet, gaps #2",
"mode": "try"
}
}application/json{
"type": "https: //startupbuilder.dev/ errors/ refused",
"title": "Refused",
"status": 422,
"detail": "sso-rung can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "6 single sign-on asks in 90 days; the $2, 400 plan includes it",
"doc": "/plays/ sso-rung#check-use-when",
"fix": "Nothing to fix: 2 or more asks a month, and a plan that has it.",
"then": "Metric.query"
},
…
Hand our latest single sign-on ask to the CSM agent and show me what it chose and why. Don’t send.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Message.received%22%2C%20%22Entitlement.checked%22%2C%20%22Quote.requested%22%2C%20%22Thread.joined%22%2C%20%22Tenant.thresholdCrossed%22%2C%20%22Domain.verified%22%2C%20%22Renewal.opened%22%2C%20%22Deal.lost%22%2C%20%22SSOConnection.failed%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_1288"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22customer_33%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_33%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Message.received", "Entitlement.checked", "Quote.requested", "Thread.joined", "Tenant.thresholdCrossed", "Domain.verified", "Renewal.opened", "Deal.lost", "SSOConnection.failed")', 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 (\"Message.received\", \"Entitlement.checked\", \"Quote.requested\", \"Thread.joined\", \"Tenant.thresholdCrossed\", \"Domain.verified\", \"Renewal.opened\", \"Deal.lost\", \"SSOConnection.failed\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1288"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"customer_33\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"customer_33\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Message.received\", \"Entitlement.checked\", \"Quote.requested\", \"Thread.joined\", \"Tenant.thresholdCrossed\", \"Domain.verified\", \"Renewal.opened\", \"Deal.lost\", \"SSOConnection.failed\")', 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_347",
"$type": "Decision",
"choice": "set-up-first",
"reason": "Pinecrest’s admin opened single sign-on setup on Team; 22 active members is under the 50-seat line, so they test sign-in before paying",
"stakes": "low",
"options": [
"answer-the-ask",
"set-up-first",
"to-the-ae",
"note-the-plan",
"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_2 opens a test connection that signs in nobody until the admin presses Test; action_3 is the answer, held 2 minutes.
63 per 100 asks upgraded against 17 before · before-after,
| Try another: the Customer | Choice | Reason |
|---|---|---|
| Pinecrest Management: their admin opened single sign-on setup on Team, 22 members | set-up-first | an admin at setup, under the 50-seat line |
| Quarry Lane Homes: “Do you support SSO with our Google accounts?” | answer-the-ask | a written ask on Team, under the line |
| Northgate Rentals: the open Deal’s security questionnaire asks for SAML | to-the-ae | a questionnaire on an open Deal is the AE’s |
| Ridgeway Rentals: 21 active members, a sign-in Domain verified, no ask | note-the-plan | past 20 members with no ask; one note in 90 days |
| Harbor Row: asked about SSO, at risk since Oct 2 | not-now | keep-first: their CSM sees them first |
- 20 min week 1, then 5 a week
- Your time
- Day 9: first upgrade paid
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Tier upgrade rate → Upgrades ↑ → ARR added each week → ARR
Worth’s formula: about +21 upgrades per 100 asks (Other Startups’ results; no lift of your own yet) × 4 asks a month × $1,448 per Team-to-annual upgrade ≈ +$1,216. Under First signal: At 4 asks a month, 90 days can tell only +45 per 100 or more, so your file starts at holdout: and reads before-after.
sample · api.sb/
Start it this week
npx startup-builder add play sso-rung # 1 · writes plays/sso-rung.mdx (Not live yet, gaps #5)
# 2 · dry run; below, its 422 on 2026-07-20
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":"sso-rung"}'
# 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":"sso-rung"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/sso-rung \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: asks come to you; active connections keep working
curl -X PATCH https://api.sb/leaseline.app/campaigns/sso-rung \
-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 | Nothing to fix: 2 or more asks a month, and a plan that has it. | POST /{namespace}/metrics/query |
billing-connected pass · Not live yet, gaps #8 | Nothing to fix: every charge reads from Stripe. | POST /{namespace}/integrations/connect |
approved-pages fail · Not live yet, gaps #8 | Publish the pricing Page row for the $2,400 plan; answers quote only your own pages. | POST /{namespace}/sites/{site}/publish |
baseline warn · Not live yet, gaps #8 | n 6: it reads before-after, not proof, until volume allows a held-back half. | POST /{namespace}/metrics/query |
role-unstaffed warn · Not live yet, gaps #8 | Staff the CSM, or leave it: 4 Customers Priya owns get drafts in her queue. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "sso-rung can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "6 single sign-on asks in 90 days; the $2,400 plan includes it",
"doc": "/plays/sso-rung#check-use-when",
"fix": "Nothing to fix: 2 or more asks a month, and a plan that has it.",
"then": "Metric.query"
},
{
"check": "billing-connected",
"status": "pass",
"observed": "Stripe, connected",
"doc": "/plays/sso-rung#check-billing-connected",
"fix": "Nothing to fix: every charge reads from Stripe.",
"then": "Integration.connect"
},
{
"check": "approved-pages",
"status": "fail",
"observed": "no Page lists what the $2,400 plan includes",
"doc": "/plays/sso-rung#check-approved-pages",
"fix": "Publish the pricing Page row for the $2,400 plan; answers quote only your own pages.",
"then": "Site.publish"
},
{
"check": "baseline",
"status": "warn",
"observed": "1 upgrade of 6 asks in 90 days",
"doc": "/plays/sso-rung#check-baseline",
"fix": "n 6: it reads before-after, not proof, until volume allows a held-back half.",
"then": "Metric.query"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"success-manager",
"sales-engineer"
],
"owned": 4,
"doc": "/plays/sso-rung#check-role-unstaffed",
"fix": "Staff the CSM, or leave it: 4 Customers Priya owns 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 · billing-connected · pass: 6 asks in 90 days; Stripe connected (gaps #8) | POST /{namespace}/metrics/query on tier-upgrade-rate; POST /{namespace}/integrations/connect for Stripe | 1 min | none |
approved-pages · fail (Not live yet): no Page lists the $2,400 plan’s single sign-on | POST /{namespace}/sites/{site}/publish the pricing Page row | 10 min | none |
baseline · warn: 1 of 6 in 90 days | POST /{namespace}/metrics/query; it fills Before in Your number | 0 min | none |
role-unstaffed · warn: 4 of your Customers have a person owner, Priya | POST /{namespace}/roles/{role}/staff, or leave it: CSM routes come to you, and Priya’s 4 get drafts in her queue | 0 min | none |
Your number · Before 17 per 100 · Now 63 per 100 asks upgraded · Target 50 by Dec 31 · before-after,
Each answer costs $0.04 from your Domain (Worker cost); POST /{namespace}/entitlements/check and a test connection cost nothing. That comes to about $0.16 a month at 4 asks and $0.08 at 2.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| A Customer or a Deal asks for single sign-on in writing | sso-written-ask | event on Message.received where intent = 'single-sign-on' | answer within 1 business hour; 3d | forward support@ to the address inbound-source printed, or POST /{namespace}/integrations/connect your inbox |
| An admin opens single sign-on setup on a plan without it | sso-setup-refused | event on Entitlement.checked where entitlement = 'single-sign-on' and allowed = false | 3d | your app calls POST /{namespace}/entitlements/check |
| A team on Team reaches 20 active members | seat-threshold-crossed | threshold on Tenant.thresholdCrossed where activeMembers >= 20 within 30d | a threshold; one note per 90 days | POST /{namespace}/metrics/{metric}/watch on active members |
+ 7 more for questionnaires, Quote requests, IT contacts, sign-in Domains, renewals, lost Deals and failing connections (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1288" ,
"$type": "Event",
"name": "Entitlement.checked",
"at": "2026-10-19T10:22:31Z" ,
"seq": 1288,
"data": {
"customer": "customer_33",
"entitlement": "single-sign-on",
"allowed": false,
"offer": "team",
"activeMembers": 22
}
}npx startup-builder trigger Entitlement.checked --like event_1288 # replays the delivery
npx startup-builder clock advance --by 2d # then runs the follow-up’s tested check
npx startup-builder listen Entitlement.checked --forward-to http://localhost:3000/hook Who runs it
CSM · your agent (role:, worker_5) holds the Key Result. It hands questionnaires and Quotes to AE · Priya Shah (person) (role:, worker_3), and held Customers to you (Dana Okafor, person, worker_1), because the CSM and Sales Engineer Roles have no person. Your number links to Did it work.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Answer with the plan · Set it up before they pay | It does it, you can stop it | 6 of 6 · 3 of 3 | met on day 16 (the first 5 answers) | any answer fails a Check, or the misquote Stop fires → You approve each one | POST /{namespace}/actions/{action}/cancel inside the hold |
| Note the plan at 20 members | You approve each one | 1 of 1 | at 10 passed | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| To the AE · Not now | It does it | 1 of 1 · 1 of 1 | — | a held Customer is asked anyway → You approve each one | POST /{namespace}/actions/{action}/redirect |
| Change the AE line | You approve each one | 0 merged | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: single sign-on turned on for them, a discount, a plan the Pricing Page lacks | To a person, every time | 1 asked, 1 handed over | never | — | POST /{namespace}/approvals/{approval}/approve on the AE’s Quote |
What it reads · What it may call. It reads the ask, the Entitlement, the live Price and the active-member count, and quotes only the pricing Page. It opens a test connection; turning single sign-on on for members and POST /{namespace}/subscriptions/{subscription}/switch are the admin’s own presses, never the agent’s. Its tools are POST /{namespace}/entitlements/check, POST /{namespace}/conversations/{conversation}/answer, POST /{namespace}/sso-connections, POST /{namespace}/conversations/{conversation}/escalate, POST /{namespace}/quotes/{quote}/send, POST /{namespace}/tasks/{task}/assign, and any other call becomes an Approval under the Role’s Mandate.
You hold the CSM Key Result: 50 upgrades per 100 single sign-on asks by 2026-12-31. ← worker, metric
Answer each ask within 1 business hour with the plan that includes it, its live Price and today’s charge. ← chooses.answer-the-ask, Answer-time stop
At 50 seats, a questionnaire or a Quote on an open Deal, choose To the AE. ← your file, line 4
Offer a test sign-in before any charge. ← chooses.set-up-first, your file line 5
Never turn single sign-on on for a team; the admin does. ← Lockout stop The slow loop. The weekly Decisions kept 50 seats as the AE line, and no Change 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 |
|---|---|---|---|---|---|
Answer with the plan answer-the-ask | a written ask from a Customer under 50 seats | Your rule (line 4) | POST /{namespace}/entitlements/check → POST /{namespace}/conversations/{conversation}/answer → sso-ask-follow-up | the admin’s press | the same |
Set it up before they pay set-up-first | an admin opened setup, or asks to try it first | Agent’s call, with its reason | POST /{namespace}/sso-connections (test only) → on press change-plan → sso-go-live | the admin’s test, then their press | the same |
To the AE to-the-ae | a questionnaire or Quote on an open Deal, 50 seats or more, or terms | Agent’s call, with its reason | POST /{namespace}/conversations/{conversation}/escalate → POST /{namespace}/quotes/{quote}/send | POST /{namespace}/tasks/{task}/assign → AE · Priya Shah, due 60 min · Take this one | you |
Note the plan at 20 members note-the-plan | 20 active members or a verified sign-in Domain, with no ask | Agent’s call, with its reason | sso-proactive-note, one note in 90 days | nobody | the same |
Not now not-now | another Play holds them, or keep-first applies | Your rule (rule j) | nothing; names the holder | their CSM, so you · Take this one | you |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | “Test passed. Move us to the annual plan.” | the one-press link; nothing is charged until they press | the Customer | — | POST /{namespace}/subscriptions/{subscription}/switch (theirs) |
| Send me pricing | “What would the SSO plan cost us?” | the live $2,400 Price, today’s $2,366.87 charge after the Team credit | CSM · your agent | 5 min | POST /{namespace}/conversations/{conversation}/answer |
| Not now | “Not until next budget year.” | the ask closes, and customer-ask-cap frees the Customer | nobody | at once | GET /{namespace}/decisions |
| Wrong person | “Our IT lead, Sam, sets this up.” | asks them to bring Sam in; it never writes to an address from their text | CSM · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply until Oct 28 | the follow-up waits for the return date | nobody | the return date | POST /{namespace}/messages/{message}/schedule |
| Question it can’t answer | “Can we add SSO to Team for a fee?” | To a person: a plan the Pricing Page lacks is never the agent’s call | AE · Priya Shah, or you | 60 min | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | “Stop emailing us about plans.” | notes stop; the test connection keeps working | nobody | at once | POST /{namespace}/contacts/{contact}/suppress |
When it hands to you
Questionnaires and Quotes go to AE · Priya Shah (person); held Customers come to you. One Brief per Role, as captured (brief is Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/tasks/task_506" ,
"$type": "Task",
"assignee": "worker_3",
"due": "2026-10-16T16:05:00Z" ,
"on": "contact_14",
"brief": {
"who": "Northgate Rentals, open Deal on the $2,400 plan" ,
"said": "Item 14 of the security questionnaire: SAML single sign-on required." ,
"chose": "to-the-ae",
"why": "a questionnaire on an open Deal is the AE’s",
"answer": "the $2,400 plan includes SAML; the trust page link is attached" ,
"never": [
"a discount",
"single sign-on on Team"
]
}
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_489" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-10-09T17:00:00Z" ,
"on": "customer_19",
"brief": {
"who": "Harbor Row",
"said": "Do you have SSO?" ,
"chose": "not-now",
"why": "at risk since Oct 2: 3 support threads on late notices" ,
"held": "keep-first"
}
}
]The owner answers with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, or POST /{namespace}/actions/{action}/redirect, each a one-call window. Once a person claims, the agent’s pending answers to that Customer cancel with claimedByPerson (Not live yet, gaps #7), and every reply goes to the owner. A Task nobody claims by its due time goes up a Role through POST /{namespace}/tasks/{task}/escalate, and person-promise fires.
On time: 2 of 2 claimed within their due time, median 25 min, n 2, ■□□□ Too early to tell beside Other Startups’ 95 % on time. Your queue: in week 1, 4 approvals; after the promotion, about 1 hand-off every 2 weeks.
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, gaps #8) | an answer to a Customer whose open Deal a person owns, or whose Conversation a person claimed | 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) | an upgrade answer to a Customer who is at risk, past due or has an unsubscribe pending | 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 | signal-expansion holds them until its seat note closes. | GET /{namespace}/decisions |
reconcile (the record’s Reconcile stop; Not live yet, gaps #8) | a Customer whose Subscription and Stripe disagree | Clear the Stripe mismatch first. | POST /{namespace}/tasks/next |
price (hub guard on POST /{namespace}/quotes/{quote}/send, gaps #1) | a plan, Price or discount the pricing Page does not show | Quote the plan that includes it, or get the discount approved. | POST /{namespace}/approvals/{approval}/approve |
| Stop (pauses the Play) | Pauses when | Then |
|---|---|---|
misquote | a Price, charge or Quote total differs from the live Price | You approve each one |
lockout | members cannot sign in after a switch, a switch down or a failed renewal | setups pause; POST /{namespace}/tasks/{task}/assign to you within 5 min |
answer-time | an ask waits past 1 business hour; 3 late in a week drop the answer lane one rung | the proactive lane pauses |
test-failure | under half of setups pass a test sign-in within 7 days, after 20 | set-up-first pauses; failing identity systems are reported to you |
spend-limit | month-to-date model spend reaches its Limit | asks get the plan answer by rule; POST /{namespace}/limits/{limit}/raise |
kill-switch | you press it | every answer stops; active connections keep working |
+ 6 more for the proactive lane (?lanes=) |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that sent is the Quarry Lane thread in Example.
| Check | Fix | Then |
|---|---|---|
price fail · Not live yet, gaps #1 | Quote the plan that includes it, or get the discount approved. | POST /{namespace}/approvals/{approval}/approve |
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 answer to Quarry Lane Homes did not send: it offers single sign-on on Team, which no live Offer shows.",
"checks": [
{
"check": "price",
"status": "fail",
"doc": "/plays/sso-rung#check-price",
"fix": "Quote the plan that includes it, or get the discount approved.",
"then": "Approval.approve"
},
{
"check": "keep-first",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "answer-time",
"observed": "1h 25m",
"bound": "1 business hour",
"window": "1 ask"
},
"doc": "/plays/sso-rung#stop-answer-time" ,
"task": "task_377"
}
]Did it work
At 4 asks a month, no held-back half reads within 90 days, so the basis is before-after (rule o): the columns read Now and Before, and 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).
63 per 100 asks upgraded against 17 before · before-after,
- Chose
- set-up-first
- Why
- Pinecrest’s admin opened single sign-on setup on Team; 22 active members is under the 50-seat line, so they test sign-in before paying
- From
- answer-the-ask · set-up-first · to-the-ae · note-the-plan · not-now
- Expects
- Subscription.switched to the annual plan within 60d
- Reopens when
- no Subscription.switched for customer_33 within 60d
- By
- worker_5
JSON
{
"$id": "decisions/decision_347",
"$type": "Decision",
"choice": "set-up-first",
"reason": "Pinecrest’s admin opened single sign-on setup on Team; 22 active members is under the 50-seat line, so they test sign-in before paying",
"stakes": "low",
"options": [
"answer-the-ask",
"set-up-first",
"to-the-ae",
"note-the-plan",
"not-now"
],
"by": "worker_5",
"on": "customer_33",
"expected": "Subscription.switched to the annual plan within 60d",
"reopensWhen": "no Subscription.switched for customer_33 within 60d"
}| Node | Now (91 days) | Before (the 90 days before) | Added | Confidence | Basis |
|---|---|---|---|---|---|
tier-upgrade-rate | 63 per 100: 5 of 8 matured asks upgraded within 60 days · 3 still maturing | 17 per 100: 1 of 6 | — | — | before-after, not proof · Other Startups’ results +21 per 100, ■■■□ Likely, n 1,140 |
expansion-arr ↑ | $12,947, of it $8,688 from 6 upgrades · Booked: credited, not all caused by this Play | $2,644 | — · Worth about +$1,200 a month | — | before-after; includes usage-upsell’s $2,392 and signal-expansion’s $1,867 |
net-new-arr · arr | carried from expansion-arr | carried | — | — | carried |
Before against after reads the 91 days against the 90 before them; an ask counts once its 60 days have passed. It is not proof, and Other Startups’ results print beside it.
How it moves it: a median first answer of 6m 40s against 2 days 4 hours before, each naming the plan, its live Price and today’s charge, with a test sign-in before any charge.
Guardrails: before against after: contraction-arr, $0 from switches back to Team against $0 before, and logo-churn, 0 of 6 upgraded Customers gone; 6 of 6 upgraded teams had an active connection by day 14.
{
"$id": "https://api.sb/leaseline.app/campaigns/sso-rung" ,
"$type": "Campaign",
"play": "play:sso-rung@1" ,
"path": [
"tier-upgrade-rate",
"expansion-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "tier-upgrade-rate",
"unit": "per-100",
"heldBack": 0,
"decision": null
},
"readout": {
"value": null,
"n": 8,
"maturing": 3,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 1,
"workerCost": 1,
"hours": 0.9,
"pipelineArr": 2393,
"wonArr": 8688,
"projectedArr": 1216,
"paybackDays": 1
}
}Outside benchmark: 3.2 % of Subscriptions on a plan without single sign-on move to one with it in their fourth month (a subscription-analytics firm’s billing data, 2026-09-30).
Before it · After it. Before it: signal-expansion hands it a team that reaches 20 active members, and trust-pack hands it questionnaire items on open Deals. After it: written-references hears the Customers it upgraded, and annual-prepay already holds them on the annual plan; keep-first holds both while a Customer is at risk.
Example
Leaseline ran it from 2026-07-20 to 2026-10-19 (91 days): 11 asks and setups on 10 Customers and 1 Deal, 8 of them matured past their 60-day window. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Upgraded | Booked (credited, not all caused by this Play) |
|---|---|---|---|
| Answer with the plan · Set it up before they pay | 6 · 3 | 3 · 3, with 3 test sign-ins passed | $8,688 |
| To the AE · Note the plan · Not now | 1 · 1 · 1 | 1 Quote open · 0 · 0 | $2,393 in an open Quote |
| At 2 a month (the Use it when volume) | about 6 in 91 days | before-after, not proof | Other Startups’ results: +21 per 100, ■■■□ Likely, n 1,140 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_088 Campaign.created | the three steps; dry run fails approved-pages | 10 min |
| 0 | event_091 Site.published | the pricing Page row for the $2,400 plan | 10 min |
| 9 | event_203 Subscription.switched | the first upgrade paid: Juniper Homes, Team to the annual plan, +$1,448 ARR | — |
| 16 | event_301 Role.updated | promoted: answers send after a 2-minute hold | — |
| 44 | event_655 Campaign.paused | answer-time: an ask waited 1h 25m; you answered it and resumed | 10 min |
| 58 | event_902 Action.refused | price refused the Quarry Lane draft; rewritten once and sent | 5 min |
| 1–91 | event_097 Approval.created, first of 5 | you approved 5 answers; weekly reviews, from the POST /{namespace}/tasks/next log | 20 min · total 55 min measured, 1 h asked |
Leaseline → Pinecrest’s admin, Oct 19, 10:29 · Single sign-on comes with the $2,400-a-year plan, which also adds directory sync.¹ Switching today costs $2,366.87, after the $33.13 left on Team this month.² Test sign-in with your own accounts first; nothing is charged until you press Switch.³ *Signed with the Role’s disclosure line.*⁴
Pinecrest, Oct 19, 11:52 · test sign-in passed, then pressed Switch.
Subscription.switched, +$1,448 ARR.
- We can turn on SSO for you on Team at no extra cost for the first 3 months.
+ Single sign-on with your Google accounts comes with the $2,400-a-year plan; you can test sign-in before you pay. Northgate Rentals, 2026-10-16 15:05 · questionnaire item 14: “SAML single sign-on required.” · Leaseline, 15:06 · *Thanks. Priya, your account lead, replies by 16:05 with the answer and the trust page.*⁵ The Brief went to Priya (
task_506); she answered at 15:41.
¹ Only what the pricing Page lists for the plan. ² The live Price and today’s charge, after the Team credit. ³ The test sign-in before any charge. ⁴ The fixed signature line, compiled from the Role’s disclosure Setting. ⁵ The routed line, compiled from the Role’s Settings.
Your settings
---
holdout: 0 # 4 asks a month is too few to hold any back; it reads before-after
---
Answer every single sign-on ask within the hour with the $2,400 plan. At 50 seats, a questionnaire or a Quote, bring in the AE.
Let the admin test sign-in before any charge.$ npx startup-builder show plays/sso-rung
holdout 0 · AE line 50 seats · test before charge your file plays/sso-rung.mdx:2,4,5 (Ask 2026-07-20)
family expansion · worker role:success-manager, owns never · chooses 5 (2 rule, 3 read) · sequences sso-ask-follow-up, sso-proactive-note, sso-go-live · checks owned-by-a-person, keep-first, customer-ask-cap, reconcile, price · stops 12 · placements gmail, outlook catalog play:sso-rung@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record sso-rung 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.