# Cap usage on a plan

URL: /products/offers/cap-usage-on-a-plan · Id: `guide:cap-usage-on-a-plan`

> Say "give the starter plan 10 exports a day" and get a Limit on the plan, a usage meter in the Portal, and an upgrade offer at the cap.

A [Limit](/business/nouns/limit) bounds an [Entitlement](/business/nouns/entitlement), and the [Offer](/business/nouns/offer)'s `atBound` says what happens past it: stop, bill the overage, or offer the next plan.

Needs: [Charge monthly](/systems/finance/charge-monthly) · [Open a bank account](/systems/finance/open-a-bank-account)

**Before it runs**

- You leave the chat: Never: it all happens in the chat.

## What you get
- 1 Limit of 10 exports per rolling day (Limit)
- 1 Entitlement on the Starter Offer, bounded by that Limit (Entitlement)
- 1 usage meter in each customer’s Portal, with the reset time (Portal)
- 1 upgrade offer at the cap, to the next plan up (Offer)

## Your agent does
**For agents**

- Guide: `guide:cap-usage-on-a-plan`, status `live`. Page: [/products/offers/cap-usage-on-a-plan.md](/products/offers/cap-usage-on-a-plan.md).
- Approval: none. Run it when the founder asks.
- Leaves the chat: never.
- Needs first: [Charge monthly](/systems/finance/charge-monthly), [Open a bank account](/systems/finance/open-a-bank-account).
- 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 | [`Limit.create`](/business/nouns/limit/create) (`verb:Limit.create`) | `amount` money: example `{"amount":29,"currency":"USD"}`; `count` integer: example `10`; `period` string: example `"day"`; `resets` string: example `"rolling"` | `limit` Limit |
| 2 | [`Offer.grant`](/business/nouns/offer/grant) (`verb:Offer.grant`) | `offer` Offer (an id), required: example `"offer_starter_monthly"`; `verb` Verb (an id), required: example `"Collection.export"`; `limit` Limit (an id): the `$id` step 1 returns | `entitlement` Entitlement, `offer` Offer |
| 3 | [`Offer.update`](/business/nouns/offer/update) (`verb:Offer.update`) | `id` string, required: example `"offer_starter_monthly"`; `price` money: example `{"amount":29,"currency":"USD"}`; `atBound` string: example `"upgrade"` | `offer` Offer |

Returns: the last call answers with `offer` 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",
  "offer": {
    "$id": "https://api.sb/leaseline.app/offers/offer_starter_monthly",
    "$type": "Offer",
    "atBound": "upgrade"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/action_1",
    "operation": "Offer.update",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/action_1"
  }
}
```

Next: offer “Bill a cent per export past the cap instead”, or “Reset the cap on the first of the month”.

Calls: `Limit.create` → `Offer.grant` → `Offer.update`

Ask:

```text
Give Starter 10 exports a day, then ask them to upgrade.
Cap the free plan at 100 calls a month.
Limit how much each plan can use.
```

API:

```bash
# 1. Limit.create
LIMIT=$(curl -X POST https://api.sb/leaseline.app/limits \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":{"amount":29,"currency":"USD"},"count":10,"period":"day","resets":"rolling"}' | jq -r '.limit["$id"] | split("/") | last')

# 2. Offer.grant
curl -X POST https://api.sb/leaseline.app/offers/offer_starter_monthly/grant \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"verb":"Collection.export","limit":"'"$LIMIT"'"}'

# 3. Offer.update
curl -X PATCH https://api.sb/leaseline.app/offers/offer_starter_monthly \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"price":{"amount":29,"currency":"USD"},"atBound":"upgrade"}'
```

SDK:

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

const limit = await $.Limit.create({ amount: { amount: 29, currency: 'USD' }, count: 10, period: 'day', resets: 'rolling' })
await $.Offer.grant({ offer: 'offer_starter_monthly', verb: 'Collection.export', limit: limit.$id })
await $.Offer.update({ id: 'offer_starter_monthly', price: { amount: 29, currency: 'USD' }, atBound: 'upgrade' })
```

CLI:

```bash
LIMIT=$(npx startup-builder do Limit.create --json '{"amount":{"amount":29,"currency":"USD"},"count":10,"period":"day","resets":"rolling"}' | jq -r '.limit["$id"] | split("/") | last')
npx startup-builder do Offer.grant --json '{"offer":"offer_starter_monthly","verb":"Collection.export","limit":"'"$LIMIT"'"}'
npx startup-builder do Offer.update --json '{"id":"offer_starter_monthly","price":{"amount":29,"currency":"USD"},"atBound":"upgrade"}'
```

MCP:

```json
{
  "name": "do",
  "arguments": {
    "code": "const limit = await $.Limit.create({ amount: { amount: 29, currency: 'USD' }, count: 10, period: 'day', resets: 'rolling' })\nawait $.Offer.grant({ offer: 'offer_starter_monthly', verb: 'Collection.export', limit: limit.$id })\nreturn await $.Offer.update({ id: 'offer_starter_monthly', price: { amount: 29, currency: 'USD' }, atBound: 'upgrade' })"
  }
}
```

## Change it
- Bill a cent per export past the cap instead.
- Reset the cap on the first of the month.
- Raise the cap for Riverside Property only.

## Under the hood
- Systems: [Billing](/systems/billing), [Work queue](/agents/work-queue), [Matchmaking](/systems/matching)
- Nouns: [Limit](/business/nouns/limit), [Entitlement](/business/nouns/entitlement), [Offer](/business/nouns/offer)
- Events: `Limit.created`, [`Offer.granted`](/business/events/Offer.granted), `Offer.updated`