URL: /revenue/onboarding · Id: `page:/revenue/onboarding`

# 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](https://startupbuilder.dev/business/nouns/customer) reaches a first outcome by day 14, or the CSM sees them first.

```text title="Ask"
Linden Court just paid. Get them to a first outcome by day 14. Don’t send.
```

```ts title="SDK"
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' })
```

```json title="Response · sample"
{
  "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
    }
  ]
}
```

`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 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 <Op verb="Customer.activate" />. | $0.04 per note from your Domain (Worker cost); setup calls and the day-14 read cost nothing | [Activation rate](/revenue/activation-rate), [Month 3 retention](/revenue/month-3-retention) | [Onboarding](/capabilities/how-your-agents-act#onboarding) | every call live |

## Set it up
| Check (dry run on a 0-Customer Startup, gaps #8) | Fix | Then | Your time | Wait |
| --- | --- | --- | --- | --- |
| [`billing-connected`](/code/refusals#check-billing-connected) (Not live yet, gaps #8) · fail | Connect Stripe so every charge and Meter reading is live. | <Op verb="Integration.connect" /> | 5 min | the first sync, about 10 min |
| [`role-unstaffed`](/code/refusals#check-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. | <Op verb="Role.staff" /> | 0 min | none |
| [`baseline`](/code/refusals#check-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. | <Op verb="Metric.query" /> | 0 min | none |

## The records
```json title="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
| Call | Here | Emits | Status |
| --- | --- | --- | --- |
| <Op verb="Event.list" /> | Linden Court paid $29 on Oct 17 | — | live |
| <Op verb="Process.enable" /> | onboard-customer: the day-1 welcome, the day-7 check-in, the day-14 read | `Process.enabled` | live |
| <Op verb="Message.schedule" /> | the day-7 check-in, drafted by your Onboarding agent | `Message.scheduled` | live |
| <Op verb="Message.schedule" /> | a review ask on day 4, from review-requests | `Message.scheduled` | live |
| <Op verb="Customer.activate" /> | what day 14 reads: 40 units imported marks them activated | `Customer.activated` | live |
| <Op verb="Metric.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 <Op verb="Task.next" />, the Customer marked at risk |

## Refuses when

```json title="The 422 · sample"
{
  "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"
    }
  ]
}
```

| Check | Refuses | Fix | Then |
| --- | --- | --- | --- |
| [`customer-ask-cap`](/code/refusals#check-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; <Op verb="Decision.list" /> names the Play that holds them. | <Op verb="Decision.list" /> |
| [`keep-first`](/code/refusals#check-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. | <Op verb="Task.next" /> |

## Plays that use it
| Play | What it does | Use it when |
| --- | --- | --- |
| [Run it beside the old tool](/plays/run-beside) | 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](https://startupbuilder.dev/workflows/processes/onboarding) | `process:onboarding` |
| [Onboard a Customer](https://startupbuilder.dev/workflows/processes/onboarding/onboard-customer) | `workflow:onboard-customer` |

## Example
```text title="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
```