The offers/ folder: one file and what it compiles to
What one offers/ file holds, what each key compiles to, and the checks that read it.
One offers/ file is one Offer: its Price, its trial, its checkout and how it is sold. SalesBuilder compiles it, and show traces every key.
---
price: { amount: 29, currency: USD, per: month }
limit: { units: 200 }
trial: 14d
checkout: self-serve
sale: self-serve
---
Renewal tracking for up to 200 units.$ npx startup-builder show offers/pro.mdx
price { amount: 29, currency: USD, per: month } offers/pro.mdx:2
limit { units: 200 } offers/pro.mdx:3
trial 14d offers/pro.mdx:4
checkout self-serve offers/pro.mdx:5
sale self-serve offers/pro.mdx:6
owner SalesBuilderleaseline.app/
├── plays/
│ ├── cold-email.mdx
│ ├── warm-intros.mdx
│ ├── signup-interviews.mdx
│ ├── lead-reactivation.mdx
│ └── events-and-webinars.mdx
├── audiences/
│ ├── small-property-managers.mdx
│ ├── lapsed-leads.mdx
│ └── renewal-season.mdx
├── sequences/
│ └── cold-email-thread-founder.mdx
├── funnels/
│ └── signup.mdx
├── workflows/
│ └── outbound.mdx
├── agents/
│ ├── sales/prospector.mdx
│ └── marketing/content-lead.mdx
├── systems/
│ └── sequences.mdx
├── domains/
│ └── leaseline.app.mdx
├── offers/ ← this folder
│ ├── pro.mdx
│ └── team.mdx
├── content/
│ └── webinars/60-day-notices.mdx
├── metrics/
│ ├── q4.mdx
│ └── positive-reply-rate.mdx
└── startups.lockThe file
| Key | On the page | Compiles to | Checked by |
|---|---|---|---|
price | Price | the Offer’s Price, published by POST /{namespace}/offers/{offer}/publish | S8 |
limit | Limit | the Offer’s Limit: what an upgrade Play reads | — |
trial | Trial | POST /{namespace}/offers/{offer}/trial for the days given | — |
checkout | Checkout | where the buyer pays: self-serve ends at POST /{namespace}/orders/place | — |
sale | How it’s sold | who carries the buyer to yes: self-serve, sales-assisted (POST /{namespace}/meetings/book, POST /{namespace}/quotes/{quote}/send, POST /{namespace}/deals/{deal}/win) or enterprise | — |
Checks
| Check | It holds | What dev prints |
|---|---|---|
| S8 | An Experiment that varies an Offer’s Price assigns by market or by time. | experiments/ |
Refusals
| Code | Fix, then the call that clears it |
|---|---|
activation-event | Declare the Offer’s activation Event before the first ask, then publish it. Then POST /{namespace}/offers/{offer}/publish. |
bar-cap | Set the bar at the 15th percentile of your own first months. Then POST /{namespace}/offers/{offer}/publish. |
cluster | Offer the plain trial; the account keeps every other term. Then POST /{namespace}/offers/{offer}/trial. |
contribution-floor | Raise the Price or lower the cost until the margin clears its target, then publish again. Then POST /{namespace}/offers/{offer}/publish. |
limit-on-offer | Add a Limit to the Offer, then publish it. Then POST /{namespace}/offers/{offer}/publish. |
no-reset | Keep the close time written at the post’s publish time. Then POST /{namespace}/offers/{offer}/publish. |
outcome-event | Declare the Offer’s delivered-outcome Event, then publish it. Then POST /{namespace}/offers/{offer}/publish. |
price | Get the discount approved, or quote at the floor. Then POST /{namespace}/approvals/{approval}/approve. |
price-split-by-buyer | Assign the Price test by market or by time. Then POST /{namespace}/experiments/{experiment}/start. |
price-sync | Publish the Offer so the price file and Stripe Prices match. Then POST /{namespace}/offers/{offer}/publish. |
sheet-lock | Publish a new version; it reaches new Customers only. Then POST /{namespace}/offers/{offer}/publish. |
ship-date | Set tranche 1 to ship within 90 days of the post. Then POST /{namespace}/offers/{offer}/publish. |
Calls
You, to your agent
Publish the Pro Offer and start a trial, as a dry run.
curl -X POST "https://api.sb/leaseline.app/offers/offer_1/publish?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
curl -X POST "https://api.sb/leaseline.app/offers/offer_1/trial?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"customer":"customer_1","days":1}'import { $ } from 'startup-builder'
await $.Offer.publish({ offer: 'offer_1' }, { mode: 'try' }) // offers/ pro.mdx, $29 a month
return await $.Offer.trial({ offer: 'offer_1', customer: 'customer_1', days: 1 }, { mode: 'try' })
npx startup-builder do Offer.publish --json '{"offer":"offer_1"}' --try
npx startup-builder do Offer.trial --json '{"offer":"offer_1","customer":"customer_1","days":1}' --try{
"name": "do",
"arguments": {
"code": "await $.Offer.publish({ offer: 'offer_1' }, { mode: 'try' }) // offers/pro.mdx, $29 a month\nreturn await $.Offer.trial({ offer: 'offer_1', customer: 'customer_1', days: 1 }, { mode: 'try' })",
"mode": "try"
}
}Response200
application/json{
"subscription": {
"$id": "https: //api.sb/ leaseline.app/ subscriptions/ subscription_1",
"$type": "Subscription",
"status": "active"
},
"offer": {
"$id": "https: //api.sb/ leaseline.app/ offers/ offer_1",
"$type": "Offer",
"price": {
"amount": 29,
"currency": "USD"
}
},
"action": {
"$id": "https: //api.sb/ leaseline.app/ actions/ action_1",
"operation": "Offer.trial",
"status": "done"
}
}
sample| Call | What it does |
|---|---|
POST /{namespace}/offers/{offer}/publish | Publish makes an Offer available for parties to accept. Emits Offer.published. |
POST /{namespace}/offers/{offer}/trial | Trial starts a Customer on an Offer free for a set number of days, with or without a card, converting or ending by its terms. Emits Offer.trialed. |
POST /{namespace}/orders/place | Place commits a Customer to buy an Offer once and records the Offer Version and price at that moment. Emits Order.placed. |
POST /{namespace}/quotes/{quote}/send | Send presents a drafted Quote to its buyer and freezes its lines, total and payment terms. Emits Quote.sent. |
Compiled, not written: edit the records it reads (compile table; cap), 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.