# Refuse an approval

URL: /agents/refuse-an-approval · Id: `guide:refuse-an-approval`

> Refuse one Approval you name, with your reason: the Action it holds ends refused and nothing it would do runs.

Name the [Approval](/business/nouns/approval) you mean, and your agent reads it back before it records your no and your reason. The [Action](/business/nouns/action) it holds ends `refused`, the agent that asked reads why, and to say yes instead you [answer an approval](/agents/answer-an-approval).

**Before it runs**

- Asks you first: You do it yourself: only a person answers an [Approval](/business/nouns/approval), never an agent.
- You leave the chat: Never.

## What you get
- 1 the Approval you named, read back to you before anything is answered (Approval)
- 1 refusal recorded with your reason, so the agent reads why (Approval)
- 1 held Action ended `refused`: nothing it would have done runs (Action)

## Your agent does
**For agents**

- Guide: `guide:refuse-an-approval`. Page: [/agents/refuse-an-approval.md](/agents/refuse-an-approval.md).
- Approval: ask the founder first. Show the run, then wait for their Approval; a refusal ends it.
- Leaves the chat: never.
- Run: call the steps in order, each through the API, CLI, MCP or SDK 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.
- Retry: each write sends the Idempotency-Key `refuse-an-approval-<the Startup's domain>-<run>-<step>` (`refuse-an-approval-leaseline.app-$RUN-1` for step 1 of the worked example), in the API and CLI as a header or flag and in the SDK as `{ idempotencyKey }`. Mint `run` once per founder request (`RUN=$(uuidgen)`, `crypto.randomUUID()`): the same ask made again later is a new request with a new run, so it runs again. After a timeout, rerun with the same run: api.sb returns each finished step's first Action and runs nothing twice.
- Retry in MCP: the `do` call carries `idempotencyKey: "refuse-an-approval-<the Startup's domain>-<run>"`, and each write inside sends it plus `-<n>`, its call number. Rerun the same code with the same key after a timeout: finished calls return their first Action, and only the rest run.

| Step | Verb | Inputs (type, required, this guide’s value) | Returns |
| --- | --- | --- | --- |
| 1 | [`Approval.get`](/business/nouns/approval/get) (`verb:Approval.get`) | `id` string, required: example `"approval_o2PM4EUAdC"` | `approval` Approval |
| 2 | [`Approval.refuse`](/business/nouns/approval/refuse) (`verb:Approval.refuse`) | `approval` Approval (an id), required: example `"approval_o2PM4EUAdC"`; `reason` text, required: example `"The March budget is spent."` | `approval` Approval |

Returns: the last call answers with `approval` 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",
  "approval": {
    "$id": "https://api.sb/leaseline.app/approvals/approval_o2PM4EUAdC",
    "$type": "Approval",
    "status": "refused"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/act_br07HsG8MG",
    "operation": "Approval.refuse",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/act_br07HsG8MG"
  }
}
```

Next: offer “Tell the agent to try again next month”, or “Refuse every ad spend over $500 this month”.

Calls: `Approval.get` → `Approval.refuse`

Ask:

```text
Refuse that request and tell the agent why.
No to the $740 ad spend.
Turn down the pending request.
```

API:

```bash
# 1. Approval.get
RUN=$(uuidgen)  # once per request; reuse it only to retry this request
curl https://api.sb/leaseline.app/approvals/approval_o2PM4EUAdC \
  -H "Authorization: Bearer $SB_TOKEN"

# 2. Approval.refuse
curl -X POST https://api.sb/leaseline.app/approvals/approval_o2PM4EUAdC/refuse \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Idempotency-Key: refuse-an-approval-leaseline.app-$RUN-2" \
  -H "Content-Type: application/json" \
  -d '{"reason":"The March budget is spent."}'
```

CLI:

```bash
RUN=$(uuidgen)  # once per request; reuse it only to retry this request
npx startup-builder do Approval.get --data '{"id":"approval_o2PM4EUAdC"}'
npx startup-builder do Approval.refuse --data '{"approval":"approval_o2PM4EUAdC","reason":"The March budget is spent."}' --idempotency-key refuse-an-approval-leaseline.app-$RUN-2
```

MCP:

```json
{
  "name": "do",
  "arguments": {
    "code": "await $.Approval.get({ id: 'approval_o2PM4EUAdC' })\nreturn await $.Approval.refuse({ approval: 'approval_o2PM4EUAdC', reason: 'The March budget is spent.' })",
    "idempotencyKey": "refuse-an-approval-leaseline.app-<run>"
  }
}
```

SDK:

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

const run = crypto.randomUUID() // once per request; reuse it only to retry this request
await $.Approval.get({ id: 'approval_o2PM4EUAdC' })
await $.Approval.refuse({ approval: 'approval_o2PM4EUAdC', reason: 'The March budget is spent.' }, { idempotencyKey: `refuse-an-approval-leaseline.app-${run}-2` })
```

## Change it
- Tell the agent to try again next month.
- Refuse every ad spend over $500 this month.
- Show me what is still waiting.

## Under the hood
- Systems: [Work queue](/agents/work-queue)
- Nouns: [Approval](/business/nouns/approval), [Action](/business/nouns/action)
- Events: [`Approval.refused`](/business/events/Approval.refused)