# Run payroll

URL: /systems/people/run-payroll · Id: `guide:run-payroll`

> Say "run payroll" and get a Pay Run with every employee's withholding, an approval, direct deposit on payday and the run in your books.

Pay every employee for one pay period: the agent prepares the [Pay Run](/business/nouns/pay-run), it is approved, and net pay lands on payday.

Needs: [Pay runs](/systems/people/payroll) · [Tax IDs](/systems/finance/tax-ids)

**Before real money moves**

- Who says yes: You. Your agent shows you the run and waits for your [Approval](/business/nouns/approval).
- You leave the chat: Never: it all happens in the chat.

## What you get
- 1 Pay Run with gross, withholding, deductions and net pay per employee (Pay Run)
- 1 Approval when the run is over the Payroll Specialist’s Limit (Approval)
- 1 direct deposit to each employee on the pay date (Transaction)
- 1 tax deposits and employer returns filed by the payroll provider (Pay Run)
- 4 lines in your books per run: wages, employer tax, then cash out (Entry)
- 1 pay stub emailed to each employee (Message)

## Your agent does
**For agents**

- Guide: `guide:run-payroll`, status `beta`. Page: [/systems/people/run-payroll.md](/systems/people/run-payroll.md).
- Approval: ask the founder first. Show the run, then wait for their Approval; a refusal ends it.
- Leaves the chat: never.
- Needs first: [Pay runs](/systems/people/payroll), [Tax IDs](/systems/finance/tax-ids).
- 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 | [`PayRun.prepare`](/business/nouns/pay-run/prepare) (`verb:PayRun.prepare`) | `company` Company (an id), required: example `"company_leaseline"`; `periodStart` date, required: example `"2026-11-01"`; `periodEnd` date, required: example `"2026-11-15"`; `payDate` date, required: example `"2026-11-15"` | `payRun` PayRun |
| 2 | [`PayRun.approve`](/business/nouns/pay-run/approve) (`verb:PayRun.approve`) | `payRun` PayRun (an id), required: the `$id` step 1 returns | `payRun` PayRun |

Returns: the last call answers with `payRun` 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",
  "payRun": {
    "$id": "https://api.sb/leaseline.app/pay-runs/pay_run_1",
    "$type": "PayRun",
    "company": "company_leaseline",
    "periodStart": "2026-11-01",
    "periodEnd": "2026-11-15",
    "payDate": "2026-11-15",
    "status": "approved"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/action_1",
    "operation": "PayRun.approve",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/action_1"
  }
}
```

Next: offer “Pay us twice a month instead of every two weeks”, or “Add Maya’s $2,000 bonus to the next run”.

Calls: `PayRun.prepare` → `PayRun.approve`

Ask:

```text
Run payroll this Friday.
Run payroll for the first half of November.
Run an off-cycle payroll for Maya’s bonus.
```

API:

```bash
# 1. PayRun.prepare
PAY_RUN=$(curl -X POST https://api.sb/leaseline.app/pay-runs/prepare \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"company":"company_leaseline","periodStart":"2026-11-01","periodEnd":"2026-11-15","payDate":"2026-11-15"}' | jq -r '.payRun["$id"] | split("/") | last')

# 2. PayRun.approve
curl -X POST https://api.sb/leaseline.app/pay-runs/$PAY_RUN/approve \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
```

SDK:

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

const payRun = await $.PayRun.prepare({ company: 'company_leaseline', periodStart: '2026-11-01', periodEnd: '2026-11-15', payDate: '2026-11-15' })
await $.PayRun.approve({ payRun: payRun.$id })
```

CLI:

```bash
PAY_RUN=$(npx startup-builder do PayRun.prepare --json '{"company":"company_leaseline","periodStart":"2026-11-01","periodEnd":"2026-11-15","payDate":"2026-11-15"}' | jq -r '.payRun["$id"] | split("/") | last')
npx startup-builder do PayRun.approve --json '{"payRun":"'"$PAY_RUN"'"}'
```

MCP:

```json
{
  "name": "do",
  "arguments": {
    "code": "const payRun = await $.PayRun.prepare({ company: 'company_leaseline', periodStart: '2026-11-01', periodEnd: '2026-11-15', payDate: '2026-11-15' })\nreturn await $.PayRun.approve({ payRun: payRun.$id })"
  }
}
```

## Change it
- Pay us twice a month instead of every two weeks.
- Add Maya’s $2,000 bonus to the next run.
- Approve every run under $40,000 without asking me.
- Void this run and prepare it again.

## Under the hood
- Systems: [Pay runs](/systems/payroll), [Ledger](/systems/ledger), [Treasury](/systems/treasury), [Workforce](/systems/workforce)
- Nouns: [Pay Run](/business/nouns/pay-run), [Human](/business/nouns/human), [Agreement](/business/nouns/agreement), [Entry](/business/nouns/entry), [Transaction](/business/nouns/transaction)
- Events: [`PayRun.prepared`](/business/events/PayRun.prepared), [`PayRun.approved`](/business/events/PayRun.approved), [`PayRun.paid`](/business/events/PayRun.paid)

[`PayRun.prepare`](/business/nouns/pay-run/prepare) reads each employee's rate from their employment [Agreement](/business/nouns/agreement) and withholds for the state where they work. A missing rate, tax setup or bank account opens a [Task](/business/nouns/task) before anything is approved.

[`PayRun.approve`](/business/nouns/pay-run/approve) books the cost the moment it runs, so the [Ledger](/systems/ledger) shows payroll by [Team](/business/nouns/team) the same day. [`PayRun.pay`](/business/nouns/pay-run/pay) draws on the operating account early enough to land on payday; keep the account funded before then.

A mistake in a paid run is fixed in the next one, or in an `offCycle` run the same week. Who is an employee and who is a contractor stays your call; contractors are paid through [Earnings](/systems/payouts).