# Products

URL: /products · Id: `page:products`

> What a Startup sells: an App, an API, a Site, a Service, an agent sold as a service, or data, each sold through Offers.

A [Product](/business/nouns/product) is what a [Startup](/business/nouns/startup) sells: an [App](/business/nouns/app), an API, a [Site](/business/nouns/site), a [Service](/business/nouns/service), an agent or data, each sold through an [Offer](/business/nouns/offer). [How products work](/products/how-products-work) maps each onto its kind.

| Product | What it is | Kind | Build it in code |
| --- | --- | --- | --- |
| [App](/products/app) | The signed-in product your customers use | [Software](/business/nouns/software) | [`apps/[app]/`](/code/file-conventions/apps) · [reference](/code/api/reference#app) |
| [API](/products/api) | Your [Verbs](/business/nouns/verb), sold to developers and agents | Software | [`products/[product].mdx`](/code/file-conventions/products) · [API](/code/api) |
| [Site](/products/site) | Public [Pages](/business/nouns/page), storefront, [Portal](/business/nouns/portal) and [Domains](/business/nouns/domain) | Every kind gets one | [`sites/[site]/`](/code/file-conventions/sites) · [reference](/code/api/reference#site) |
| [Service](/products/service) | Work agents deliver, priced per outcome, hour or month | Service | [`products/[product].mdx`](/code/file-conventions/products) · [reference](/code/api/reference#product) |
| [An agent sold as a service](/products/agent) | One agent doing one job for your customers | [Agent](/business/nouns/agent) | [`products/[product].mdx`](/code/file-conventions/products) · [reference](/code/api/reference#agent) |
| [A data product](/products/data) | A [Dataset](/business/nouns/dataset), queried or downloaded | Data | [`products/[product].mdx`](/code/file-conventions/products) · [reference](/code/api/reference#dataset) |
| [Offers](/products/offers) | A Product at a [Price](/business/nouns/price), on terms | Any | [`offers/[offer].mdx`](/code/file-conventions/offers) · [reference](/code/api/reference#offer) |
| [Pricing](/products/pricing) | Flat, per seat, metered or per outcome | Any | [`offers/[offer].mdx`](/code/file-conventions/offers) · [reference](/code/api/reference#offer) |

**For agents**

- Guide: `guide:build-my-app`, status `beta`. Page: [/products/app/build-my-app.md](/products/app/build-my-app.md).
- Approval: ask the founder first. Show the run, then wait for their Approval; a refusal ends it.
- Leaves the chat: never.
- Needs first: [Startup](/business/nouns/startup).
- Run: call the steps in order, each through the API, SDK, CLI or MCP tab below; a later step passes the `$id` an earlier one returns. Each value marked example is the sample business’s: pass the founder’s own.

| Step | Verb | Inputs (type, required, this guide’s value) | Returns |
| --- | --- | --- | --- |
| 1 | [`Software.create`](/business/nouns/software/create) (`verb:Software.create`) | `name` string, required: example `"Leaseline"`; `promise` text, required: example `"Every lease renewal date in one place, with a reminder 90 days out."` | `software` Software |
| 2 | [`App.publish`](/business/nouns/app/publish) (`verb:App.publish`) | `app` App (an id), required: the `$id` of the first Interface `Interface.list` returns for `where: kind = app` | `app` App |

Returns: the last call answers with `app` and its `action`, whose `status` is `done`, `pending` (waiting on an Approval or a Worker), `failed`, `canceled` or `refused`:

```json
{
  "api": "https://api.sb/leaseline.app",
  "app": {
    "$id": "https://api.sb/leaseline.app/apps/interface_1",
    "$type": "App"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/action_1",
    "operation": "App.publish",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/action_1"
  }
}
```

Next: offer “Add an owner view that shows every property at once”, or “Hide rent amounts from the maintenance Persona”.

Calls: `Software.create` → `App.publish`

Ask:

```text
Build the app my property managers sign in to.
Give each customer a dashboard of their leases and renewal dates.
Make an app where a manager sees which renewals are due this month.
```

API:

```bash
# 1. Software.create
curl -X POST https://api.sb/leaseline.app/software \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Leaseline","promise":"Every lease renewal date in one place, with a reminder 90 days out."}'

# Look up the Interface: Interface.list
APP=$(curl "https://api.sb/leaseline.app/interfaces?where=kind%20%3D%20app&limit=1" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" | jq -r '.interfaces[0]["$id"] | split("/") | last')

# 2. App.publish
curl -X POST https://api.sb/leaseline.app/apps/$APP/publish \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
```

SDK:

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

await $.Software.create({ name: 'Leaseline', promise: 'Every lease renewal date in one place, with a reminder 90 days out.' })
const [app] = await $.Interface.list({ where: 'kind = app', limit: 1 })
await $.App.publish({ app: app.$id })
```

CLI:

```bash
npx startup-builder do Software.create --json '{"name":"Leaseline","promise":"Every lease renewal date in one place, with a reminder 90 days out."}'
APP=$(npx startup-builder do Interface.list --json '{"where":"kind = app","limit":1}' | jq -r '.interfaces[0]["$id"] | split("/") | last')
npx startup-builder do App.publish --json '{"app":"'"$APP"'"}'
```

MCP:

```json
{
  "name": "do",
  "arguments": {
    "code": "await $.Software.create({ name: 'Leaseline', promise: 'Every lease renewal date in one place, with a reminder 90 days out.' })\nconst [app] = await $.Interface.list({ where: 'kind = app', limit: 1 })\nreturn await $.App.publish({ app: app.$id })"
  }
}
```

**Guides.** What a founder says to their agent, and the guide that does it.

| You say | Guide | Calls | Status |
| --- | --- | --- | --- |
| `Give every new Pro customer 14 days free` | [Add a free trial to a plan](/products/offers/add-a-free-trial-to-a-plan) | [Offer.update](/business/nouns/offer/update) | `live` |
| `Add a yearly plan at $290` | [Add a yearly plan](/products/offers/add-a-yearly-plan) | [Offer.create](/business/nouns/offer/create), [Offer.publish](/business/nouns/offer/publish) | `live` |
| `Build the app my property managers sign in to` | [Build my app](/products/app/build-my-app) | [Software.create](/business/nouns/software/create), [App.publish](/business/nouns/app/publish) | `beta` |
| `Buy leaseline.app` | [Buy a domain](/products/site/domains/buy-a-domain) | [Domain.search](/business/nouns/domain/search), [Domain.register](/business/nouns/domain/register), [Domain.connect](/business/nouns/domain/connect) | `live` |
| `Give Starter 10 exports a day, then ask them to upgrade` | [Cap usage on a plan](/products/offers/cap-usage-on-a-plan) | [Limit.create](/business/nouns/limit/create), [Offer.grant](/business/nouns/offer/grant), [Offer.update](/business/nouns/offer/update) | `live` |
| `Charge $15 a month for each person on the team` | [Charge per seat](/products/app/charge-per-seat) | [Offer.create](/business/nouns/offer/create), [Offer.publish](/business/nouns/offer/publish) | `live` |
| `Connect leaseline.com. I bought it somewhere else` | [Connect my domain](/products/site/domains/connect-my-domain) | [Domain.connect](/business/nouns/domain/connect) | `live` |
| `Give me dana@leaseline.app` | [Get email at my domain](/products/site/domains/get-email-at-my-domain) | [Domain.authenticate](/business/nouns/domain/authenticate), [Mailbox.create](/business/nouns/mailbox/create) | `beta` |
| `Give Riverside Property a 14-day free trial` | [Give a customer a free trial](/products/offers/give-a-free-trial) | [Offer.trial](/business/nouns/offer/trial) | `live` |
| `Give the first 100 customers 20% off for three months` | [Give a launch discount](/products/offers/give-a-launch-discount) | [Coupon.create](/business/nouns/coupon/create) | `live` |
| `Let my customers sign in` | [Let customers sign in](/products/app/let-customers-sign-in) | [Tenant.provision](/business/nouns/tenant/provision), [Tenant.invite](/business/nouns/tenant/invite) | `live` |
| `Lock export to Pro` | [Lock a feature to a plan](/products/offers/lock-a-feature-to-a-plan) | [Offer.grant](/business/nouns/offer/grant) | `live` |
| `Sell renewal outreach as a service at $199 a month` | [Sell a service](/products/service/sell-a-service) | [Service.create](/business/nouns/service/create), [Offer.create](/business/nouns/offer/create), [Offer.publish](/business/nouns/offer/publish) | `beta` |
| `Sell renewal dates by county as data` | [Sell my data](/products/data/sell-my-data) | [Dataset.create](/business/nouns/dataset/create), [Offer.create](/business/nouns/offer/create), [Offer.publish](/business/nouns/offer/publish) | `beta` |
| `Sell renewal dates as an API, a cent per call` | [Ship an API](/products/api/ship-an-api) | [Interface.create](/business/nouns/interface/create), [Offer.publish](/business/nouns/offer/publish) | `beta` |
| `Keep each customer's leases, units and tenants` | [Store my customers' data](/products/app/store-my-customers-data) | [Collection.create](/business/nouns/collection/create), [Tenant.provision](/business/nouns/tenant/provision) | `beta` |
| `Make Harbor Residential a custom plan at $24,000 a year` | [Make a custom plan for one customer](/products/offers/make-a-custom-plan) | [Offer.create](/business/nouns/offer/create), [Quote.create](/business/nouns/quote/create), [Quote.send](/business/nouns/quote/send) | `live` |
| `Sell in the UK` | [Sell outside the US](/products/offers/sell-outside-the-us) | [Market.enter](/business/nouns/market/enter) | `beta` |
| `Set up SSO with Okta for Harbor Properties` | [Set up SSO for a customer](/products/app/set-up-sso-for-a-customer) | [Tenant.requestSetup](/business/nouns/tenant/request-setup), [SSOConnection.activate](/business/nouns/sso-connection/activate) | `beta` |
| `Cancel a customer’s subscription` | [Cancel a customer’s subscription](/products/offers/cancel-a-subscription) | [Subscription.unsubscribe](/business/nouns/subscription/unsubscribe) | `live` |
| `Can Riverside Property export right now` | [Check what a customer can do](/products/offers/check-what-a-customer-can-do) | [Entitlement.check](/business/nouns/entitlement/check) | `live` |
| `My domain is not working` | [Fix my domain](/products/site/domains/fix-my-domain) | [Domain.verify](/business/nouns/domain/verify) | `live` |
| `License the full renewal dataset for $12,000 a year` | [License my data](/products/data/license-my-data) | [Offer.create](/business/nouns/offer/create), [Offer.publish](/business/nouns/offer/publish) | `beta` |
| `Promise 99.9% uptime on Scale` | [Promise uptime on a plan](/products/api/promise-uptime) | [Offer.update](/business/nouns/offer/update) | `live` |
| `Raise Pro to $39 for new customers` | [Raise my price](/products/offers/raise-my-price) | [Offer.create](/business/nouns/offer/create), [Offer.publish](/business/nouns/offer/publish), [Offer.withdraw](/business/nouns/offer/withdraw) | `live` |
| `A customer posted their API key in public, replace it` | [Replace a leaked key](/products/api/replace-a-leaked-key) | [APIKey.roll](/business/nouns/api-key/roll) | `live` |
| `List renewal dates on AWS Marketplace` | [Sell on AWS Marketplace](/products/offers/sell-on-aws-marketplace) | [Integration.connect](/business/nouns/integration/connect), [Integration.sync](/business/nouns/integration/sync) | `beta` |