Skip to content

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.

Onboard a new CustomerMode try
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"
  }
}
Response200application/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
    }
  ]
}
samplePreview

12 of 17 new Customers activated by day 14 · 71 % · ■■□□ Early sign · n 17

Metric.query({"metric":"activation-rate","shape":"trend","window":"28d"}) · sample · leaseline.app at 2026-10-19

What it does

What it doesPrice per unitMovesWho does itToday
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 nothingActivation rate, Month 3 retentionOnboardingevery call live

Set it up

Check (dry run on a 0-Customer Startup, gaps #8)FixThenYour timeWait
billing-connected (Not live yet, gaps #8) · failConnect Stripe so every charge and Meter reading is live.POST /{namespace}/integrations/connect5 minthe first sync, about 10 min
role-unstaffed (Not live yet, gaps #8) · warn: Onboarding has no person: its drafts come to youStaff Onboarding, or leave it: its Tasks come to you.POST /{namespace}/roles/{role}/staff0 minnone
baseline (Not live yet, gaps #8) · warn: 12 of 17 activated by day 14 in 90 daysn 17: it reads before-after, not proof, until volume allows a held-back half.POST /{namespace}/metrics/query0 minnone

The records

Linden Court, the day it paid
{
  "$id": "https://api.sb/leaseline.app/customers/customer_23",
  "$type": "Customer",
  "since": "2026-10-17",
  "outside": true,
  "status": "active"
}

Calls

CallHereEmitsStatus
GET /{namespace}/eventsLinden Court paid $29 on Oct 17—live
POST /{namespace}/processes/{process}/enableonboard-customer: the day-1 welcome, the day-7 check-in, the day-14 readProcess.enabledlive
POST /{namespace}/messages/{message}/schedulethe day-7 check-in, drafted by your Onboarding agentMessage.scheduledlive
POST /{namespace}/messages/{message}/schedulea review ask on day 4, from review-requestsMessage.scheduledlive
POST /{namespace}/customers/{customer}/activatewhat day 14 reads: 40 units imported marks them activatedCustomer.activatedlive
POST /{namespace}/metrics/queryMetric.queriedlive

Events

EventWhen it firesWhat hears it
Order.paida first Order clearsstarts onboard-customer
Customer.activatedthe declared activation Event reaches its count, here 40 units importedends onboarding; the Customer goes to the CSM
Task.offeredday 10 with no activationthe CSM’s POST /{namespace}/tasks/next, the Customer marked at risk

Refuses when

422RefusedThe review ask to Linden Court did not send: their day-7 check-in is the open ask.
CheckFixThen
customer-ask-cap fail · Not live yet, gaps #3Wait 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.

CheckRefusesFixThen
customer-ask-cap (Not live yet, gaps #3)a second open ask to one Customer in a window, from any PlayWait 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 leavingLet their CSM reach them first, then ask again once they are healthy.POST /{namespace}/tasks/next

Plays that use it

PlayWhat it doesUse it when
Run it beside the old toolRuns 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.devId
Onboardingprocess:onboarding
Onboard a Customerworkflow:onboard-customer

Example

Leaseline, as the fixture ran it
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.

Contents