Activated customers
New customers who reach the week-1 event your offer declares within 14 days of signing up, billed per customer who does.
- Kind
- Service
- Price
- $40 per activated customer
- Your time
- 20 minutes
- Approval
- Goes out on its own
- Deepens
- Onboarding
- Default limits
- What waits for you
More factsFewer facts
Get this month’s new customers to their first reconciled ledger within 14 days, $40 each, and show me the plan first.
curl -X POST "https: //api.sb/ leaseline.app/ activations/ deliver? mode= try" \
-H "Authorization: Bearer $SB_TOKEN" \
-H "Content-Type: application/ json" \
-d '{"goal": "Get this month’s new customers to their first reconciled ledger within 14 days, $40 each, and show me the plan first.", "budget": {"amount": 720, "currency": "USD"}}'
npx startup-builder do Activation.deliver --try --data '{"goal": "Get this month’s new customers to their first reconciled ledger within 14 days, $40 each, and show me the plan first.", "budget": {"amount": 720, "currency": "USD"}}'
{
"name": "do",
"arguments": {
"mode": "try",
"code": "return await $.Activation.deliver({ goal: 'Get this month’s new customers to their first reconciled ledger within 14 days, $40 each, and show me the plan first.', budget: { amount: 720, currency: 'USD' } })"
}
}
import { $ } from 'startup-builder'
const result = await $.try.Activation.deliver({ goal: 'Get this month’s new customers to their first reconciled ledger within 14 days, $40 each, and show me the plan first.', budget: { amount: 720, currency: 'USD' } })
{
"mode": "try",
"stored": false,
"estimate": "About 16¢ per 10 new customers",
"bills": "$40 an activated customer",
"sample": {
"customer": "Kestrel Lane Homes",
"signed": "January 6",
"event": "first reconciled ledger",
"on day": "4",
"state": "activated, accepted"
}
}
What you get
- 10 new customers, as Customer records
activated[]· Each customer who reached the event: the day it fired, counted from signup, and the note that came before it.stalled[]· Each customer past day 14 without it, with the step they stopped at; none is billed.bill· Accepted activations times the price.
Connect once: Stripe, Gmail. How long: 14 days from each signup.
Trigger
It runs when you call it, or on any Trigger you set.
await $.Workflow.create({
verb: 'Activation.deliver',
trigger: { schedule: 'weekly' }
})Steps
Your agent does these steps, one row per step; each step’s check is part of its row and its price.
| Step | Verb | Returns | Price | Approval |
|---|---|---|---|---|
| 1. Read the offer’s week-1 event | Collection.query | The activation Event the offer declares; none refuses with activation-event | Free | Runs on its own |
| 2. Score each new customer every day | Customer.score | Each new customer’s usage against the step before the event, flagged when it stalls | Free | Runs on its own |
| 3. Write the day-1, day-3 and day-7 notes | Content.draft | A note that names the one step between them and the event, with their own numbers | About 12¢ | Runs on its own |
| 4. Send each note | Message.schedule | Each note sent; the notes stop the day the customer reaches the event | About 1.5¢ | Goes out on its own |
| 5. Save anyone stuck at day 10 | Customer.save | One note with the offer your Policy allows, such as a 20-minute setup session | About 2.1¢ | Runs on its own |
| 6. Read the event as it fires | Metric.query | Each customer activated on the day the event fires, inside 14 days of signup | Free | Runs on its own |
Calls: Collection.query, then Customer.score, then Content.draft, then Message.schedule, then Customer.save, then Metric.query.
About 16¢ per 10 new customers, each time it runs, capped at $1.00. Its own steps cost 14¢; the compositions it orders add 2.1¢.
| How it runs | What it says |
|---|---|
| Count the event your offer declares, never a login | A login or an opened email is not activation. The event is the first thing a paying customer does, declared on the offer, read from your own product’s Events. |
| Price it against what a customer is worth | A customer at $149 a month is worth the $795 CAC that plan can afford. $40 is 5% of that, billed only for the customers who reach the event. |
| Stop writing the day it fires | The notes stop the moment the event fires, so an activated customer never gets a nudge for a step they took. |
Example: give it a goal
Get this month’s new customers to their first reconciled ledger within 14 days, $40 each, and show me the plan first.
The plan it shows runs 6 steps, priced before it spends anything; Run it above shows the result it returns.
When something fails
Each failure, and what happens next
| When | Then |
|---|---|
| The offer declares no activation Event | It refuses with activation-event before anything runs; declare the event on the offer, then order again. |
| A customer has an open support conversation | The notes pause and the customer is handed to a person with the context; the 14 days keep running. |
| A customer activates, then refunds within 30 days | The activation is credited and the refund reason is written to the customer. |
Each step retries three times, then falls through to the next route; one item's failure lands in skipped with its reason, never failing the call. Before a step would cross maxCost it stops and returns what it has, with a resume link. Each step's idempotency key is the call's key plus the step and the item: leaseline-activation-deliver-1-<step>-<item>.
What it promises
| Term | This Service |
|---|---|
| Done | A new customer reaches the activation Event your offer declares within 14 days of signing up. |
| Counted by | Activation.delivered |
| Billed | $40 an activated customer, on acceptance |
| Target | Every new customer ordered in the month. |
| Accepted when | The event firing accepts it. A customer who refunds within 30 days of activating is credited. |
| Credited | A customer who refunds within 30 days of activating. |
| Remedy | A customer stuck at day 10 gets a save note under your Policy at no charge; one who never reaches the event is never billed. |
| Evaluator | Code reads the offer’s activation Event from your product’s own Events, with its time against the signup. |
| Window | 14 days from each signup; the refund check runs 30 days past the event. |
| Assurance | measured |
| Oversight | none: agents and code do every step |
You pay $40 for each activated customer you accept. Behind it, the agents spend about 16¢ in calls for 10 new customers, never more than $1, shown beside your bill. That spend is inside the $40: you are billed for accepted units only, never for the calls.
January: 18 new Leaseline customers, every one ordered.
| Count | What happened |
|---|---|
| 18 | Ordered |
| 18 | Signed up and ordered. |
| 3 | Stuck at day 10, so each got a save note offering a setup session; 2 then activated. |
| 13 | Reached their first reconciled ledger within 14 days; the median was day 4. |
| 5 | Not activated by day 14: never billed, each with the step they stopped at. |
| 1 | Refunded within 30 days of activating: credited. |
| 12 | Accepted and billed: 12 × $40 = $480 |
Change it
| Ask | Compiles to |
|---|---|
| Count the second reconciled ledger instead of the first. | Activation.deliver |
| Offer a setup call at day 5 instead of day 10. | Customer.save |
| Show me where the stalled ones stopped. | Metric.query |
import { $, Service } from 'startup-builder'
export default Service({
name: 'activation-deliver',
verb: 'Activation.deliver',
input: {
offer: 'string',
within: 'string',
customers: "'new' | string[]",
policy: 'string'
},
maxCost: 1,
// each one's cost rolls up into this call
orders: ['Customer.score', 'Customer.save'],
oversight: { posture: 'none' },
contract: {
done: 'Activation.delivered', accept: {
by: 'event',
within: '14d'
}, assurance: 'measured',
bills: { usd: 40, per: 'activated customer' }, credits: ['refund-within-30d'], remedy: 'save-note-at-day-10',
},
execute: async (ctx, { offer, within = '14d', policy }) => {
const event = await ctx.step(
'event',
() => $.Collection.query({
from: 'offer',
id: offer,
fields: ['activationEvent']
})
)
if (!event.activationEvent) return ctx.refuse('activation-event')
on.Customer.created(async (customer, $) => {
for (const day of [1, 3, 7]) await ctx.at(
customer,
`${day}d`,
() => $.Content.draft({
kind: 'onboarding-note',
customer,
step: event.next,
maxCost: 0.005
})
)
await ctx.at(
customer,
'10d',
() => $.Customer.save({ customer: customer.$id, policy }),
{ unless: event.activationEvent }
)
})
},
})Extend it with extends: and base(), or compose your own from these steps.
Works with
Plays that order it: Run it beside the old tool.
| Orders | Kind | Runs, each at its own price | Rolls up |
|---|---|---|---|
| Silence watch | Workflow | 14 × Free | Free |
| Save and win back | Agent task | 3 × About 0.7¢ a customer | About 2.1¢ |
It serves Keep and grow customers. It deepens Onboarding.
For agents
For agents: the guide, its approvals, retries and lookups
| Fact | Value |
|---|---|
| Guide | Activation.deliver |
| Guide approval | None. |
| Goal | Get this month’s new customers to their first reconciled ledger within 14 days, $40 each, and show me the plan first. It may change counts, the order of steps, soft filters and the route a read takes, and it stops early when the goal is met. It never relaxes your words, raises its own budget, answers its own approval, calls a Play or acts outside your standing approval. |
| Retry | Three times with backoff, then the next route; the same idempotency key never charges, sends or posts twice |
| Idempotency key | leaseline-activation-deliver-1 |
| Lookups | A find: input asks unless exactly one record fits |
Step 4 reaches people outside your records and goes out on its own within your limits.
Who does each step, and how it is checked
| Step | Function | Doer | Checker | Assurance | Inputs |
|---|---|---|---|---|---|
| 1. Read the offer’s week-1 event | code | Code | Code reads the Event name from the offer’s declared fields | measured | $0.offer |
| 2. Score each new customer every day, by Silence watch | code | Code | Code scores usage by the declared rule and reads each flag back | measured | $0.customers |
| 3. Write the day-1, day-3 and day-7 notes | agentic | The Onboarding agent | Adversarial review by a second model: Pass, or held: every number from their usage, every step one the product has | graded | $1.event, |
| 4. Send each note | code | Code | Code reads the result back from where it landed | measured | $3.passed |
| 5. Save anyone stuck at day 10, by Save and win back | agentic | The CSM agent | A second model checks each note against the customer’s record and your Policy | graded | $2.stalled, |
| 6. Read the event as it fires | code | Code | Code reads the activation Event from your product’s own Events, timed against the signup | measured | $1.event, |
Code does steps 1, 2, 4 and 6; The Onboarding agent does step 3; and the CSM agent does step 5. A second model checks the 2 graded steps, never the one that wrote it, so the whole call is graded.
Under the hood
Under the hood: the Systems, Nouns and Events it touches
| Kind | What it touches |
|---|---|
| Systems | Analytics and experiments, Mailboxes, sites and content |
| Nouns | Collection, Customer, Content, Action, Message, Metric |
| Events | Collection.queried, Content.drafted, Action.evaluated, Message.scheduled, Metric.queried |
Reference
Inputs, outputs, its Event and its errors
| Name | Type | Default | Meaning |
|---|---|---|---|
offer | Offer | Required | The offer whose declared activation Event counts, such as Leaseline’s first reconciled rent ledger. |
within | string | '14d' | Days from signup in which the event must fire to count. |
customers | 'new' | Customer[] | 'new' | Who is ordered: every new customer this month, or the ones you name. |
policy | Policy | your retention Policy | What a day-10 save note may offer without asking: a setup session, a pause, or a credit up to its amount. |
Emits one Event named for its Verb. Refuses with max-cost before it spends, and with the Data calls and Accounts groups (refusals).