---
url: https://saas.dev/docs/run-it
md: https://saas.dev/docs/run-it.md
---

# Run it

Once Leaseclock takes payments, its team runs the business from the admin at `leaseclock.com/admin`. Customers, payments, plans and emails are records there, like leases, and every change has a preview, an undo and a line in its history. The same Verbs run from the API, from `npx leaseclock` and from your team's agent.

Your team signs in to the admin with its own Leaseclock accounts. Scripts use a key created in the admin under **Settings → API keys**, read from `LEASECLOCK_TOKEN`, and pick a customer with the `Workspace` header or `--workspace`.

## Customers

[Leaseclock's admin, Customers in Live: Northgate Rentals and four others, with Harbor Point Homes past due and Linden Row Lettings canceled](https://leaseclock.com/admin/customers)

Every workspace is a customer, with its plan and where its billing stands. Past due and Canceled have tabs of their own, so the customers who need a look are one click away.

**API**

```bash title="Terminal"
curl "https://leaseclock.com/api/subscriptions?status=past_due" \
  -H "Authorization: Bearer $LEASECLOCK_TOKEN"
```

**CLI**

```bash title="Terminal"
npx leaseclock show subscriptions --status past_due
```

## A card fails

[Leaseclock's Billing screen in Live for October 2026: Northgate Rentals paid, Harbor Point Homes past due and retrying Oct 25, Linden Row Lettings refunded](https://leaseclock.com/admin/billing)

When a renewal payment fails, Stripe retries the card over the next two weeks, and Leaseclock emails the workspace's owner a link to update it, from Leaseclock's own address. The payment reads Past due, with the date of the next retry. The workspace keeps working while Stripe retries, and its owner sees a Past due banner in the app with the same link. If the last retry fails, the plan ends and the workspace turns read-only, with every record kept, until someone pays.

Once Harbor Point Homes updates its card, retry it now instead of waiting for Stripe's next attempt:

**API**

```bash title="Terminal"
curl -X POST https://leaseclock.com/api/subscriptions/harbor-point-homes/retry \
  -H "Authorization: Bearer $LEASECLOCK_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
```

**CLI**

```bash title="Terminal"
npx leaseclock do Subscription.retry harbor-point-homes
```

## Refund a payment

[A $29.00 payment from Linden Row Lettings in Leaseclock's admin, with Refund's preview open](https://leaseclock.com/admin/billing/payments/lc-0042)

Refund opens its preview first: the amount, the card it goes back to and the status the payment is left in. Confirm it, and Stripe returns the money, the payment reads Refunded, and the owner gets a receipt for the refund. Pass an amount to refund part of a payment.

**API**

```bash title="Terminal"
curl -X POST https://leaseclock.com/api/payments/linden-row-lettings-2026-10-09/refund \
  -H "Authorization: Bearer $LEASECLOCK_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
```

**CLI**

```bash title="Terminal"
npx leaseclock do Payment.refund linden-row-lettings-2026-10-09
```

A GET on the same URL returns the preview and moves nothing. [Stripe](https://saas.dev/docs/stripe.md#refunds) covers refunds from the customer's side.

## Change a customer's plan

With a second Offer, a customer moves between plans from its billing portal, and your team moves it from its page in the admin. Here Leaseclock adds a Team plan for larger property managers:

```mdx title="Offer/team.mdx"
---
name: Leaseclock Team
price: { amount: 79, currency: USD, unit: month }
limits: { Unit: 1000 }
personas: Property manager, Leasing coordinator
status: Live
---
```

[Northgate Rentals in Leaseclock's admin, with Change plan's preview open: Leaseclock Pro to Leaseclock Team, prorated](https://leaseclock.com/admin/customers/northgate-rentals)

The preview names both plans, the new price and what Stripe prorates, and the next invoice carries the difference.

**API**

```bash title="Terminal"
curl -X POST https://leaseclock.com/api/subscriptions/northgate-rentals/changePlan \
  -H "Authorization: Bearer $LEASECLOCK_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "offer": "team" }'
```

**CLI**

```bash title="Terminal"
npx leaseclock do Subscription.changePlan northgate-rentals --offer team
```

## Answer a support request

[Northgate Rentals' Leases list as Leaseclock's team sees it, under the band: Viewing Northgate Rentals as Leaseclock team, changes are recorded under your name](https://leaseclock.com/admin/customers/northgate-rentals/view)

Priya writes in: a lease she renewed shows the wrong date. **View as customer** on Northgate Rentals' page opens its app with its records, under a band that says whose screen it is. Anything your team changes there lands in the record's history under your team member's name, so Priya sees who changed what.

**API**

```bash title="Terminal"
curl https://leaseclock.com/api/leases/4b/history \
  -H "Authorization: Bearer $LEASECLOCK_TOKEN" \
  -H "Workspace: northgate-rentals"
```

**CLI**

```bash title="Terminal"
npx leaseclock history leases 4b --workspace northgate-rentals
```

The history shows every renewal of 4B with who ran it and from where, and Undo on the newest puts the date back.

## Emails your product sends

[Leaseclock's admin, Emails: every message the product sends from hello@leaseclock.com, and what sends it](https://leaseclock.com/admin/emails)

Leaseclock sends every email from its own domain, `hello@leaseclock.com`, in its theme. Sign-in links, invitations, receipts, failed-card notices and refund receipts come with every product. A Verb with `emails:` adds its own, like Lease's 60-day reminder in [Verbs](https://saas.dev/docs/verbs.md#on-a-date). [`npx saas.dev domain add`](https://saas.dev/docs/saas-dev-cli.md) publishes the domain's SPF and DKIM records with its DNS record, so the mail lands in inboxes. Rewrite an email's words, or turn one off, from the Emails screen.

Each email sent is a record, so a question about a missing message has an answer:

**API**

```bash title="Terminal"
curl "https://leaseclock.com/api/emails?to=dana.whitfield@example.com" \
  -H "Authorization: Bearer $LEASECLOCK_TOKEN" \
  -H "Workspace: northgate-rentals"
```

**CLI**

```bash title="Terminal"
npx leaseclock show emails --to dana.whitfield@example.com --workspace northgate-rentals
```

## Close a customer

[Northgate Rentals in Leaseclock's admin, with Cancel plan's preview open: Active to Canceled on Nov 21, 2026, records kept](https://leaseclock.com/admin/customers/northgate-rentals)

Cancel plan shows what changes before anything changes: the plan ends on its renewal date, nothing more is charged, and the workspace stays readable with every record. The owner exports everything in one call, and reopening the plan brings the workspace back as it was.

**API**

```bash title="Terminal"
curl -X POST https://leaseclock.com/api/subscriptions/northgate-rentals/cancel \
  -H "Authorization: Bearer $LEASECLOCK_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
```

**CLI**

```bash title="Terminal"
npx leaseclock do Subscription.cancel northgate-rentals
```

## What the admin holds

Beside your own Nouns, every product has these, with the same lists, pages, API, CLI and MCP tools:

| Noun | What it is | Verbs |
| --- | --- | --- |
| Workspace | One customer, with its people and records | |
| Member | A person in a workspace, with a role | |
| Subscription | A workspace's plan in Stripe | `retry`, `changePlan`, `cancel` |
| Payment | One charge in Stripe | `refund` |
| Invoice | What Stripe billed, with its PDF | |
| Email | One message the product sent or has scheduled | |
| Changelog entry | What changed in a push customers can see | |

## Your team's agent

Your team's agent connects to the same [MCP server](https://saas.dev/docs/mcp.md#your-teams-agent) and runs the same Verbs, with the same previews. A morning's work is one sentence:

```text title="Ask your agent"
Find every past-due subscription and draft a note to each owner.
```
