# startup.ts

URL: /code/startup-ts · Id: `page:code/startup-ts`

> The root file marks a Startup and holds its name, domain, the Startup Template it extends, and its own values, in TypeScript, MDX or JSON.

`startup.ts` marks a [Startup](/business/nouns/startup) and holds its name, its [Domain](/business/nouns/domain), the [Startup Template](/business/nouns/startup-template) it extends, and its own values. It is the [business record](/business/startup) as code.

```ts
import { Startup } from 'startup-builder'

export default Startup({
  name: 'Leaseline',
  domain: 'leaseline.app',
  extends: 'solo-saas',
})
```

## Reference
One `Startup()` call with literal values. The file is parsed, never run, so it holds data only. Spreads of [Templates](/business/nouns/template) are allowed; a loop, a computed value or a call into your own code fails the parse check and names the line.

The Startup's own fields are [`name`](#name), [`domain`](#domain), [`extends`](#extends), [`idea`](#idea), [`hypothesis`](#hypothesis) (the Founding Hypothesis), [`msc`](#msc), [`offers`](#offers) and [`routes`](#routes). Any [Setting](/business/nouns/setting), such as [`signup`](#signup) or [`trial`](#trial), takes its own value as well ([Settings](/code/file-conventions/settings)). [Every key](#every-key) gives each one's type and default.

[Role](/business/nouns/role) seats keyed by function, such as `support: { agent: 'Rae' }`, are shorthand. The full seat lives in [Roles](/code/file-conventions/roles).

### Every key
Each key the root file takes, with its type, its default and the [Builder](/business/nouns/builder) that reads it. The [Startup root file](/code/project-structure/startup-root) reference adds the errors a push fails with.

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| <a id="name"></a>`name` | `string` | Required | The Startup’s name, as buyers see it. Example: `'Closewise'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="domain"></a>`domain` | `url` | None. | Its home Domain; its Sites, API and docs serve there. Example: `'closewise.com'`. Read by [SiteBuilder](/code/builders/site). |
| <a id="extends"></a>`extends` | `startup-template` | None. | The Startup Template it extends; everything it does not set is inherited from it. Example: `'agent-run-services'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="idea"></a>`idea` | `text` | None. | The Idea in one sentence. Example: `'Monthly books for small agencies, reconciled and reviewed.'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="hypothesis"></a>`hypothesis` | `object` | None. | The Founding Hypothesis, one key per slot. Read by [StartupBuilder](/code/builders/startup). |
| <a id="hypothesis-customer"></a>`hypothesis.customer` | `text` | None. | Who it is for. Example: `'Agencies with 5 to 50 staff and no in-house bookkeeper'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="hypothesis-problem"></a>`hypothesis.problem` | `text` | None. | What they struggle with. Example: `'Month-end takes three weeks and still misses entries'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="hypothesis-approach"></a>`hypothesis.approach` | `text` | None. | How the Startup solves it. Example: `'Agents reconcile every entry, and a controller reviews each month'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="hypothesis-switch"></a>`hypothesis.switch` | `text` | None. | What they use today and would leave. Example: `'A part-time bookkeeper and a spreadsheet'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="hypothesis-differentiation"></a>`hypothesis.differentiation` | `text` | None. | Why they would switch. Example: `'Books done within three business days of month end'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="msc"></a>`msc` | `object` | None. | The Minimum Success Criteria: the Metric, the value and the date that make the Startup worth keeping. Read by [StartupBuilder](/code/builders/startup). |
| <a id="msc-metric"></a>`msc.metric` | `metric` | None. | The Metric it is judged on. Example: `'outside-revenue'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="msc-value"></a>`msc.value` | `number` | None. | The value the Metric must reach. Example: `5000`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="msc-by"></a>`msc.by` | `date` | None. | The date it must reach it by. Example: `'2027-06-30'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="reserve"></a>`reserve` | `object` | None. | The reserve page’s two values nothing else supplies: the ship date and the threshold. Read by [SalesBuilder](/code/builders/sales). |
| <a id="reserve-ships"></a>`reserve.ships` | `date` | None. | The date reservers are told the product ships. Example: `'2027-01-15'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="reserve-threshold"></a>`reserve.threshold` | `object` | None. | The bar the reserve test must clear, fixed before the page goes live. Read by [SalesBuilder](/code/builders/sales). |
| <a id="reserve-threshold-deposits"></a>`reserve.threshold.deposits` | `number` | None. | How many outside deposits pass the test. Example: `8`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="reserve-threshold-reached"></a>`reserve.threshold.reached` | `number` | None. | How many people the page must reach. Example: `40`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="reserve-threshold-by"></a>`reserve.threshold.by` | `date` | None. | The date the deposits must arrive by. Example: `'2026-11-05'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="offers"></a>`offers` | `map` | None. | Its own Offers, keyed by id; a larger Offer lives in `offers/`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="offers-price"></a>`offers.*.price` | `money` | None. | The amount and currency it charges each interval. Example: `{ amount: 499, currency: 'USD' }`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="offers-interval"></a>`offers.*.interval` | `string` | None. | How often it bills: `once`, `day`, `week`, `month` or `year`. Example: `'month'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="offers-terms"></a>`offers.*.terms` | `text` | None. | What the buyer gets, in one sentence. Example: `'Books done within three business days of month end.'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="routes"></a>`routes` | `map` | None. | Routes to a Custom Implementation, keyed by path; every other route is generated. Read by [SoftwareBuilder](/code/builders/software). |
| <a id="routes-to"></a>`routes.*.to` | `string` | None. | The program in `code/` that serves the route. Example: `'code/legacy-webhook'`. Read by [SoftwareBuilder](/code/builders/software). |
| <a id="routes-reason"></a>`routes.*.reason` | `text` | Required | Why no Verb, saved query or MCP tool could serve it. Example: `'A partner posts form-encoded webhooks that no Verb accepts.'`. Read by [SoftwareBuilder](/code/builders/software). |
| <a id="locale"></a>`locale` | `string` | `'en-US'` | The language and region its Pages and Messages are written for. Example: `'en-GB'`. Read by [SiteBuilder](/code/builders/site). |
| <a id="signup"></a>`signup` | `string` | `'email'` | How a buyer signs up: `email`, `workEmail`, `magicLink`, `keyless`, `apiKey`, `oauth` or `agentIdentity`. Example: `'magicLink'`. Read by [SoftwareBuilder](/code/builders/software). |
| <a id="double-opt-in"></a>`doubleOptIn` | `boolean` | `false` | Whether a Waitlist sign-up confirms by email before it counts. Example: `true`. Read by [SiteBuilder](/code/builders/site). |
| <a id="price-unit"></a>`priceUnit` | `string` | `'seat'` | The unit its Prices count by default. Example: `'month'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="trial"></a>`trial` | `string` | `'14d'` | How long a trial runs before the first charge. Example: `'30d'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="agreement"></a>`agreement` | `string` | `'clickwrap'` | How a buyer accepts the terms: `clickwrap` or `msa`. Example: `'msa'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="terms-template"></a>`termsTemplate` | `string` | `'standard'` | Which terms Template its `/terms` Page is built from: `standard`, `developer`, `b2b`, `consumer` or `agent`. Example: `'b2b'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="tax-display"></a>`taxDisplay` | `string` | `'exclusive'` | Whether Prices show tax: `exclusive`, `inclusive` or `reverseCharge`. Example: `'inclusive'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="refund-window"></a>`refundWindow` | `string` | `'30d'` | How long after a charge a refund is granted without review. Example: `'14d'`. Read by [SalesBuilder](/code/builders/sales). |
| <a id="consent"></a>`consent` | `string` | `'strictest'` | Whose consent rules apply: the strictest everywhere, or each region’s own. Example: `'byRegion'`. Read by [SiteBuilder](/code/builders/site). |
| <a id="approval-hours"></a>`approvalHours` | `number` | `48` | How long an Approval waits before it escalates. Example: `24`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="budget"></a>`budget` | `number` | `200` | Its monthly spend budget, in USD, before an Approval. Example: `500`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="auto-upgrade"></a>`autoUpgrade` | `string` | `'onGreen'` | When a Startup Template upgrade merges: `onGreen`, `qualityGates` or `manual`. Example: `'manual'`. Read by [StartupBuilder](/code/builders/startup). |
| <a id="close-by-day"></a>`closeByDay` | `number` | `5` | The business day of the month by which the books close. Example: `3`. Read by [StartupBuilder](/code/builders/startup). |

## Examples
### Leaseline
```ts
import { Startup } from 'startup-builder'

export default Startup({
  name: 'Leaseline',
  domain: 'leaseline.com',
  extends: 'solo-saas',
  idea: 'Small property managers pay to never miss a lease renewal.',
  hypothesis: {
    customer: 'Property managers with 20 to 200 units',
    problem: 'Renewals slip because end dates live in a spreadsheet',
    approach: 'Import the rent roll and send every notice at 60 days',
    switch: 'A spreadsheet and a calendar reminder',
    differentiation: 'Set up in ten minutes from the rent roll',
  },
  signup: 'magicLink',
  trial: '30d',
})
```

### Three spellings
The same Startup in MDX and JSON parses to one fingerprint. `npm create startups` writes TypeScript, and [startups.new](/start/startups-new) writes MDX.

```mdx
---
name: Leaseline
domain: leaseline.com
extends: solo-saas
---
Leaseline tracks lease renewals for small property managers, so no renewal slips past its date.
```

```json
{ "name": "Leaseline", "domain": "leaseline.com", "extends": "solo-saas" }
```

## What it builds
The [StartupBuilder](/code/builders/startup) compiles the file and directs the other four [Builders](/business/nouns/builder).

- the `Startup`, created with `Startup.create` and extended with `Template.extend` on the first write
- its Settings, and the [Interfaces](/business/nouns/interface) its Startup Template declares: `/api`, `/app`, `/docs` and MCP
- the [Events](/business/nouns/event) `Template.extended`, then `Startup.built` when the first build finishes

## Routing
The Startup's namespace is its domain: `https://api.sb/leaseline.com` serves its API, and `leaseline.com/api` serves the same on its own Domain. A route to custom code needs a reason:

```ts
routes: { '/webhooks/partner': { to: 'code/partner-webhook', reason: 'The partner posts form-encoded webhooks that no Verb accepts.' } }
```

## Good to know
- Two root files in one folder fail. Pick `startup.ts`, `startup.mdx` or `startup.json`.
- A key set in both `startup.ts` and `settings.mdx` fails, so every Setting has one home.
- `npx startup-builder show /` prints the whole Startup, own and inherited values.