Onboarding: the first outcome by day 14
Onboarding: the welcome, the check-in and the day-14 read that marks a new Customer activated.
Every paying Customer reaches a first outcome by day 14, or the CSM sees them first.
You, to your agent
Linden Court just paid. Get them to a first outcome by day 14. Don’t send.
curl "https://api.sb/leaseline.app/events?where=name%20%3D%20%22Order.paid%22&limit=1" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
curl -X POST "https://api.sb/leaseline.app/processes/onboarding/enable?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
curl -X POST "https://api.sb/leaseline.app/messages/message_122/schedule?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"at":"2026-10-24T14:00:00Z"}'
curl -X POST "https://api.sb/leaseline.app/messages/message_123/schedule?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"at":"2026-10-21T14:00:00Z"}'
curl -X POST "https://api.sb/leaseline.app/customers/customer_23/activate?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"offer":"offer_1"}'
curl -X POST https://api.sb/leaseline.app/metrics/query \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"metric":"activation-rate","shape":"trend","window":"28d"}'import { $ } from 'startup-builder'
const { events: [paid] } = await $.Event.list({ where: 'name = "Order.paid"', limit: 1 }) // Linden Court paid $29 on Oct 17
await $.Process.enable({ process: 'onboarding' }, { mode: 'try' }) // onboard-customer: the day-1 welcome, the day-7 check-in, the day-14 read
await $.Message.schedule({ message: 'message_122', at: '2026-10-24T14: 00: 00Z' }, { mode: 'try' }) // the day-7 check-in, drafted by your Onboarding agent
await $.Message.schedule({ message: 'message_123', at: '2026-10-21T14: 00: 00Z' }, { mode: 'try' }) // a review ask on day 4, from review-requests
// 422 · The review ask to Linden Court did not send: their day-7 check-in is the open ask.
// customer-ask-cap: Wait for the open ask to close; Decision.list names the Play that holds them. · then Decision.list
await $.Customer.activate({ customer: 'customer_23', offer: 'offer_1' }, { mode: 'try' }) // what day 14 reads: 40 units imported marks them activated
return await $.Metric.query({ metric: 'activation-rate', shape: 'trend', window: '28d' })
npx startup-builder do Event.list --json '{"where":"name = \"Order.paid\"","limit":1}'
npx startup-builder do Process.enable --json '{"process":"onboarding"}' --try
npx startup-builder do Message.schedule --json '{"message":"message_122","at":"2026-10-24T14:00:00Z"}' --try
npx startup-builder do Message.schedule --json '{"message":"message_123","at":"2026-10-21T14:00:00Z"}' --try
npx startup-builder do Customer.activate --json '{"customer":"customer_23","offer":"offer_1"}' --try
npx startup-builder do Metric.query --json '{"metric":"activation-rate","shape":"trend","window":"28d"}'{
"name": "do",
"arguments": {
"code": "const { events: [paid] } = await $.Event.list({ where: 'name = \"Order.paid\"', limit: 1 }) // Linden Court paid $29 on Oct 17\nawait $.Process.enable({ process: 'onboarding' }, { mode: 'try' }) // onboard-customer: the day-1 welcome, the day-7 check-in, the day-14 read\nawait $.Message.schedule({ message: 'message_122', at: '2026-10-24T14:00:00Z' }, { mode: 'try' }) // the day-7 check-in, drafted by your Onboarding agent\nawait $.Message.schedule({ message: 'message_123', at: '2026-10-21T14:00:00Z' }, { mode: 'try' }) // a review ask on day 4, from review-requests\n// 422 · The review ask to Linden Court did not send: their day-7 check-in is the open ask.\n// customer-ask-cap: Wait for the open ask to close; Decision.list names the Play that holds them. · then Decision.list\nawait $.Customer.activate({ customer: 'customer_23', offer: 'offer_1' }, { mode: 'try' }) // what day 14 reads: 40 units imported marks them activated\nreturn await $.Metric.query({ metric: 'activation-rate', shape: 'trend', window: '28d' })",
"mode": "try"
}
}Response200
application/json{
"metric": {
"$id": "https: //api.sb/ leaseline.app/ metrics/ activation-rate",
"$type": "Metric",
"name": "Activation rate"
},
"rows": [
{
"week": "2026-10-12",
"value": 0.71,
"activated": 12,
"customers": 17
}
]
}
samplePreview12 of 17 new Customers activated by day 14 · 71 % · ■■□□ Early sign · n 17
Metric.query({"metric": · sample · leaseline.app at 2026-10-19
What it does
| What it does | Price per unit | Moves | Who does it | Today |
|---|---|---|---|---|
Order.paid starts the onboard-customer Workflow: a day-1 welcome, a day-7 check-in and the day-14 read of POST /{namespace}/customers/{customer}/activate. | $0.04 per note from your Domain (Worker cost); setup calls and the day-14 read cost nothing | Activation rate, Month 3 retention | Onboarding | every call live |
Set it up
| Check (dry run on a 0-Customer Startup, gaps #8) | Fix | Then | Your time | Wait |
|---|---|---|---|---|
billing-connected (Not live yet, gaps #8) · fail | Connect Stripe so every charge and Meter reading is live. | POST /{namespace}/integrations/connect | 5 min | the first sync, about 10 min |
role-unstaffed (Not live yet, gaps #8) · warn: Onboarding has no person: its drafts come to you | Staff Onboarding, or leave it: its Tasks come to you. | POST /{namespace}/roles/{role}/staff | 0 min | none |
baseline (Not live yet, gaps #8) · warn: 12 of 17 activated by day 14 in 90 days | n 17: it reads before-after, not proof, until volume allows a held-back half. | POST /{namespace}/metrics/query | 0 min | none |
The records
{
"$id": "https://api.sb/leaseline.app/customers/customer_23" ,
"$type": "Customer",
"since": "2026-10-17",
"outside": true,
"status": "active"
}Calls
| Call | Here | Emits | Status |
|---|---|---|---|
GET /{namespace}/events | Linden Court paid $29 on Oct 17 | — | live |
POST /{namespace}/processes/{process}/enable | onboard-customer: the day-1 welcome, the day-7 check-in, the day-14 read | Process.enabled | live |
POST /{namespace}/messages/{message}/schedule | the day-7 check-in, drafted by your Onboarding agent | Message.scheduled | live |
POST /{namespace}/messages/{message}/schedule | a review ask on day 4, from review-requests | Message.scheduled | live |
POST /{namespace}/customers/{customer}/activate | what day 14 reads: 40 units imported marks them activated | Customer.activated | live |
POST /{namespace}/metrics/query | Metric.queried | live |
Events
| Event | When it fires | What hears it |
|---|---|---|
Order.paid | a first Order clears | starts onboard-customer |
Customer.activated | the declared activation Event reaches its count, here 40 units imported | ends onboarding; the Customer goes to the CSM |
Task.offered | day 10 with no activation | the CSM’s POST /{namespace}/tasks/next, the Customer marked at risk |
Refuses when
| Check | Fix | Then |
|---|---|---|
customer-ask-cap fail · Not live yet, gaps #3 | Wait for the open ask to close; Decision.list names the Play that holds them. | GET /{namespace}/decisions |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The review ask to Linden Court did not send: their day-7 check-in is the open ask.",
"checks": [
{
"check": "customer-ask-cap",
"status": "fail",
"doc": "/code/refusals#check-customer-ask-cap",
"fix": "Wait for the open ask to close; Decision.list names the Play that holds them.",
"then": "Decision.list"
}
]
}It says no, says why, and names the fix.
| Check | Refuses | Fix | Then |
|---|---|---|---|
customer-ask-cap (Not live yet, gaps #3) | a second open ask to one Customer in a window, from any Play | Wait for the open ask to close; GET /{namespace}/decisions names the Play that holds them. | GET /{namespace}/decisions |
keep-first (Not live yet, gaps #8) | an upgrade, referral, review or reference 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 |
Plays that use it
| Play | What it does | Use it when |
|---|---|---|
| Run it beside the old tool | Runs a new Customer’s work beside their old tool every day, fixes each difference you caused, and books the switch when the report reads zero. | 4 or more switching Customers a month, with 20 or more checkable items a day each |
first-outcome-onboarding (Not live yet, gaps #4) | The Play that gets each new Customer to a first outcome by day 14. | today: The hub Workflow onboard-customer, started by Order.paid. |
Hub guides it deepens
| On startupbuilder.dev | Id |
|---|---|
| Onboarding | process: |
| Onboard a Customer | workflow: |
Example
Linden Court · paid $29 on Oct 17 · day 1: welcome sent · day 2: 0 units imported, setup call offered for Oct 21 · day 4: review ask refused (customer-ask-cap) · day 7: check-in · activated at 40 units · sample 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.