# Approval

URL: /business/nouns/approval · Id: `noun:approval`

> An Approval is a Task to allow or refuse one pending Action that exceeds a Limit or a Mandate.

An Approval is a [Task](/business/nouns/task) to allow or refuse one pending [Action](/business/nouns/action) that exceeds a [Limit](/business/nouns/limit) or a [Mandate](/business/nouns/mandate).

## Properties
| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `verdict` | `string` | No | One of `allowed` or `refused`. |
| `deadline` | `datetime` | No | When an unanswered Approval cancels the Action. |

<details>
<summary>Inherited from [Task](/business/nouns/task): 3 properties</summary>

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `due` | `datetime` | No | When the Task is due. |
| `priority` | `integer` | No | Its rank in the inbox, highest first. |
| `recurrence` | `string` | No | The schedule a recurring duty repeats on. |

</details>

<details>
<summary>Inherited from [Action](/business/nouns/action): 11 properties</summary>

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | `string` | Yes | One of `pending`, `done`, `failed`, `canceled`, or `refused`. |
| `reason` | `string` | No | Why a pending Action waits: `queued`, `running`, `retrying`, `awaitingWorker`, `awaitingInput`, `awaitingSource`, `awaitingAction`, or `awaitingTime`. |
| `mode` | `string` | Yes | How the caller invoked it: `try`, `send`, or `do`. |
| `by` | [Worker](/business/nouns/worker) | No | The Worker that performed it. |
| `for` | [Party](/business/nouns/party) | No | The Party it was done on behalf of. |
| `via` | `string` | No | The Interface or request it arrived through. |
| `on` | `string` | No | The Action or Event that caused it, such as the failed attempt a retry follows. |
| `thing` | `string` | No | The record, at the Version the Action was decided against. |
| `input` | `json` | No | The input it was called with. |
| `createdAt` | `datetime` | No | When it was called. |
| `reserved` | `money` | No | The most this Action may cost, held against its Limits from the check until it settles, billed misses included. |

</details>

## Object
```json
{
  "$id": "https://api.sb/shiftnote.app/approvals/approval_1",
  "$type": "Approval",
  "status": "pending",
  "reason": "queued",
  "mode": "try",
  "by": "worker_1",
  "for": "party_1",
  "via": "API",
  "on": "Invoice.overdue",
  "thing": "invoice_1@v3",
  "input": {},
  "createdAt": "2026-10-22T12:00:00Z",
  "reserved": {
    "amount": 79,
    "currency": "USD"
  },
  "due": "2026-10-22T12:00:00Z",
  "priority": 1,
  "recurrence": "Weekly on Friday",
  "verdict": "allowed",
  "deadline": "2026-10-22T12:00:00Z"
}
```

## Relationships
- <a id="rel-gates"></a>An Approval **gates** one [Action](/business/nouns/action): an Approval holds one pending [Action](/business/nouns/action) that exceeds a [Limit](/business/nouns/limit) or [Mandate](/business/nouns/mandate) until someone allows or refuses it. `gates`, inverse [`approvals`](/business/nouns/action#rel-approvals).

## Lifecycle

| State | Meaning | Moves to |
| --- | --- | --- |
| `pending` (first) | An Action waits on the answer. | `approved` by [Approval.approve](/business/nouns/approval/approve); `refused` by [Approval.refuse](/business/nouns/approval/refuse); `expired` on [`Approval.expired`](/business/nouns/approval#approvalexpired) when nobody answered by its `deadline` |
| `approved` | The Action it held runs. | None: it ends here. |
| `refused` | The Action it held ends `refused`, with the reason given. | None: it ends here. |
| `expired` | Nobody answered by the deadline, so the Action it held ends `canceled`. | None: it ends here. |

## Verbs
| Verb | Description | Subject | Event | Class |
| --- | --- | --- | --- | --- |
| [Approval.approve](/business/nouns/approval/approve) | Approve allows the pending Action an Approval holds, and that Action runs. | [Founder](/agents/founding/founder) | [`Approval.approved`](/business/events/Approval.approved) | None. |
| [Approval.refuse](/business/nouns/approval/refuse) | Refuse declines an Approval, which sets the Action it holds to `refused` with the reason given. | [Founder](/agents/founding/founder) | [`Approval.refused`](/business/events/Approval.refused) | None. |
| <a id="create"></a>[Approval.create](/business/nouns/approval/create) | Creates an Approval. Inherited from [Noun](/business/nouns/noun). | None. | `Approval.created` | Two-way: `try`, `send`, `do` |
| <a id="get"></a>[Approval.get](/business/nouns/approval/get) | Returns one Approval by id. Inherited from [Noun](/business/nouns/noun). | None. | None. | Read: `try`, `do` |
| <a id="list"></a>[Approval.list](/business/nouns/approval/list) | Returns Approvals, newest first, one page at a time. Inherited from [Noun](/business/nouns/noun). | None. | None. | Read: `try`, `do` |
| <a id="update"></a>[Approval.update](/business/nouns/approval/update) | Changes the given properties of an Approval. Inherited from [Noun](/business/nouns/noun). | None. | `Approval.updated` | Two-way: `try`, `send`, `do` |
| <a id="delete"></a>[Approval.delete](/business/nouns/approval/delete) | Deletes an Approval; its history is kept. Inherited from [Noun](/business/nouns/noun). | None. | `Approval.deleted` | One-way: `send`, `do` |

## Events
Events no Verb emits. Each Verb’s Event is in the Verbs table above; every Event is delivered in the same shape.

### Approval.expired
Nobody answered an Approval by its `deadline`, so the Action it held ends. Raised by a clock.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | `string` | Yes | `Approval.expired`. |
| `at` | `datetime` | Yes | When it happened. |
| `seq` | `integer` | No | Its position in the namespace, one more than the Event before; any seq is a cursor into the history. |
| `data` | `json` | Yes | The Thing as the Action left it. |
| `data.approval` | [Approval](/business/nouns/approval) | Yes | The Approval as the change left it. |
| `data.approval.status` | `string` | Yes | One of `pending`, `done`, `failed`, `canceled`, or `refused`. |
| `data.approval.reason` | `string` | No | Why a pending Action waits: `queued`, `running`, `retrying`, `awaitingWorker`, `awaitingInput`, `awaitingSource`, `awaitingAction`, or `awaitingTime`. |
| `data.approval.mode` | `string` | Yes | How the caller invoked it: `try`, `send`, or `do`. |
| `data.approval.by` | [Worker](/business/nouns/worker) | No | The Worker that performed it. |
| `data.approval.for` | [Party](/business/nouns/party) | No | The Party it was done on behalf of. |
| `data.approval.via` | `string` | No | The Interface or request it arrived through. |
| `data.approval.on` | `string` | No | The Action or Event that caused it, such as the failed attempt a retry follows. |
| `data.approval.thing` | `string` | No | The record, at the Version the Action was decided against. |
| `data.approval.input` | `json` | No | The input it was called with. |
| `data.approval.createdAt` | `datetime` | No | When it was called. |
| `data.approval.reserved` | `money` | No | The most this Action may cost, held against its Limits from the check until it settles, billed misses included. |
| `data.approval.due` | `datetime` | No | When the Task is due. |
| `data.approval.priority` | `integer` | No | Its rank in the inbox, highest first. |
| `data.approval.recurrence` | `string` | No | The schedule a recurring duty repeats on. |
| `data.approval.verdict` | `string` | No | One of `allowed` or `refused`. |
| `data.approval.deadline` | `datetime` | No | When an unanswered Approval cancels the Action. |

```json
{
  "$id": "https://api.sb/shiftnote.app/events/event_1",
  "$type": "Event",
  "name": "Approval.expired",
  "at": "2026-10-22T12:00:00Z",
  "data": {
    "approval": {
      "$id": "https://api.sb/shiftnote.app/approvals/approval_1",
      "$type": "Approval",
      "status": "pending",
      "reason": "queued",
      "mode": "try",
      "by": "worker_1",
      "for": "party_1",
      "via": "API",
      "on": "Invoice.overdue",
      "thing": "invoice_1@v3",
      "input": {},
      "createdAt": "2026-10-22T12:00:00Z",
      "reserved": {
        "amount": 79,
        "currency": "USD"
      },
      "due": "2026-10-22T12:00:00Z",
      "priority": 1,
      "recurrence": "Weekly on Friday",
      "verdict": "allowed",
      "deadline": "2026-10-22T12:00:00Z"
    }
  },
  "seq": 1
}
```

## Permissions
Which Access level may call each Verb. One-way Verbs wait their delay window.

| Operation | `owner` | `admin` | `member` | `viewer` |
| --- | --- | --- | --- | --- |
| `Approval.create` | Yes | Yes | Yes | No |
| `Approval.get` | Yes | Yes | Yes | Yes |
| `Approval.list` | Yes | Yes | Yes | Yes |
| `Approval.update` | Yes | Yes | Yes | No |
| `Approval.delete` | Yes | Yes | Yes | No |
| `Approval.approve` | Yes | Yes | Yes | No |
| `Approval.refuse` | Yes | Yes | Yes | No |

## Call it

**Ask**

```text
Approve the latest approval.
```

**API**

```bash
curl -X POST https://api.sb/kilnbakery.com/approvals/approval_1/approve \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
```

```json
{
  "api": "https://api.sb/kilnbakery.com",
  "approval": {
    "$id": "https://api.sb/kilnbakery.com/approvals/approval_1",
    "$type": "Approval",
    "status": "pending",
    "mode": "try"
  },
  "action": {
    "$id": "https://api.sb/kilnbakery.com/actions/action_1",
    "operation": "Approval.approve",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/kilnbakery.com/actions/action_1"
  }
}
```

**SDK**

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

const approval = await $.Approval.approve({ approval: 'approval_1' })
```

**CLI**

```bash
npx startup-builder do Approval.approve --json '{"approval":"approval_1"}'
```

**MCP**

```json
{
  "name": "do",
  "arguments": {
    "code": "return await $.Approval.approve({ approval: 'approval_1' })"
  }
}
```

## Example
The [Sales Lead](/agents/sales/sales-lead) offers a 30% discount when its [Limit](/business/nouns/limit) is 20%. An Approval lands in the [Founder](/agents/founding/founder)'s inbox, and the [Quote](/business/nouns/quote) goes out once approved.