# Approval policies tools

> MCP tools for Approval policies: approval_policies_get, approval_policies_overrides_delete, approval_policies_overrides_set, approval_policies_update.

- `approval_policies_get`: Get the approval policy
- `approval_policies_overrides_delete`: Delete an approval policy override
- `approval_policies_overrides_set`: Set an approval policy override
- `approval_policies_update`: Update the approval policy

## `approval_policies_get`

**Get the approval policy.** Operation [`approval_policies.get`](https://ownrecord.io/docs/reference/approval-policies-get.md) · Organization level · permission `approvals:read` · risk tier `read` · since M2

Returns the organization's approval policy:

- `tiers`: what agents, apps and MCP clients may do per risk tier (`allow`, `require_approval` or `deny`).
  Until the policy is saved: write and financial `allow`, compliance and security `require_approval`.
- `twoPersonFor`: the operations that need a second person's approval, whoever calls.
- `amountLimits`: for operations that move money, the amount per currency at or below which a call runs at
  once (micros as a string).
- `overrides`: stricter rules for single entities, agents and apps. The strictest applicable rule wins.

Without a saved policy `id` is null and `version` 0. `availableOperations` lists every operation a policy
can name. The policy applies in both modes.

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

This tool takes no arguments.

- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't see the approval policy here.

### Examples

**Brand changes need a second person; one agent may not move money**

Arguments:

```json
{}
```

Result `output`:

```json
{
  "object": "approval_policy",
  "id": "apol_01m4ttwd3veh9apbewxheq5xh9",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "tiers": {
    "write": "allow",
    "financial": "allow",
    "compliance": "require_approval",
    "security": "require_approval"
  },
  "twoPersonFor": ["brands.update"],
  "amountLimits": [],
  "version": 2,
  "updatedAt": "2026-10-13T14:30:00.000Z",
  "overrides": [
    {
      "id": "apol_01m4ttwd3veh9apbewxheq5xhb",
      "object": "approval_policy_override",
      "entityId": null,
      "agentId": "agt_01m4ttwd3veh9apbewxheq5xhc",
      "clientId": null,
      "tiers": {
        "write": null,
        "financial": "deny",
        "compliance": null,
        "security": null
      },
      "twoPersonFor": [],
      "amountLimits": [],
      "version": 1,
      "updatedAt": "2026-10-13T14:30:00.000Z"
    }
  ],
  "availableOperations": [
    {
      "id": "brands.update",
      "summary": "Update a brand",
      "riskTier": "write",
      "scope": "brand",
      "amounts": false
    },
    {
      "id": "members.remove",
      "summary": "Remove a member",
      "riskTier": "security",
      "scope": "org",
      "amounts": false
    }
  ]
}
```

**No policy saved yet**

Arguments:

```json
{}
```

Result `output`:

```json
{
  "object": "approval_policy",
  "id": null,
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "tiers": {
    "write": "allow",
    "financial": "allow",
    "compliance": "require_approval",
    "security": "require_approval"
  },
  "twoPersonFor": [],
  "amountLimits": [],
  "version": 0,
  "updatedAt": null,
  "overrides": [],
  "availableOperations": [
    {
      "id": "brands.update",
      "summary": "Update a brand",
      "riskTier": "write",
      "scope": "brand",
      "amounts": false
    },
    {
      "id": "members.remove",
      "summary": "Remove a member",
      "riskTier": "security",
      "scope": "org",
      "amounts": false
    }
  ]
}
```

## `approval_policies_overrides_delete`

**Delete an approval policy override.** Operation [`approval_policies.overrides.delete`](https://ownrecord.io/docs/reference/approval-policies-overrides-delete.md) · Organization level · permission `approvals:admin` · risk tier `security` · since M10

Deletes one approval policy override (`apol_…`, from `overrides` in `approval_policies.get`). Calls at its
entity, or by its agent or app, follow the organization's policy (and any other override that applies)
again. Send the override's `version` to avoid deleting a change you haven't seen. The organization's own
policy can't be deleted; change it with `approval_policies.update`. Returns the whole approval policy.
Owners and admins only, with a sign-in in the last 15 minutes.

Annotations: `readOnlyHint: false` · `destructiveHint: true` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument          | Type          | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`apol_…`) | yes      | –                                                                                                                                                                                                        |
| `version`         | integer       | no       | (1–9007199254740991)                                                                                                                                                                                     |
| `idempotency_key` | string        | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean       | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No override with this ID exists in the organization (the organization's own policy isn't one).
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The override changed since you read it (`version`); read it again.
- [`fresh_auth_required`](https://ownrecord.io/docs/reference/errors.md#fresh_auth_required): You last signed in more than 15 minutes ago.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): Only owners and admins change the approval policy.

### Example

**Remove an agent's override**

Arguments:

```json
{
  "id": "apol_01m4ttwd3veh9apbewxheq5xhb",
  "version": 1,
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "approval_policy",
  "id": "apol_01m4ttwd3veh9apbewxheq5xh9",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "tiers": {
    "write": "allow",
    "financial": "allow",
    "compliance": "require_approval",
    "security": "require_approval"
  },
  "twoPersonFor": ["brands.update"],
  "amountLimits": [],
  "version": 2,
  "updatedAt": "2026-10-13T14:30:00.000Z",
  "overrides": [],
  "availableOperations": [
    {
      "id": "brands.update",
      "summary": "Update a brand",
      "riskTier": "write",
      "scope": "brand",
      "amounts": false
    },
    {
      "id": "members.remove",
      "summary": "Remove a member",
      "riskTier": "security",
      "scope": "org",
      "amounts": false
    }
  ]
}
```

## `approval_policies_overrides_set`

**Set an approval policy override.** Operation [`approval_policies.overrides.set`](https://ownrecord.io/docs/reference/approval-policies-overrides-set.md) · Organization level · permission `approvals:admin` · risk tier `security` · since M10

Creates or changes the approval policy override for one legal entity (`entityId`), one agent (`agentId`)
or one app (`clientId`, its OAuth client). Send exactly one of them.

An override has the same parts as the organization's policy: `tiers` (each tier you send replaces the
current one; null removes it), `twoPersonFor` and `amountLimits` (each list you send replaces the current
one). The **strictest applicable rule wins**: a call is checked against the organization's policy and every
override for its entity, its agent and its app, so an override can only tighten what the organization
allows, never loosen it.

Agents and apps are referenced by ID; the entity must belong to the organization. Returns the whole
approval policy. Owners and admins only, with a sign-in in the last 15 minutes.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument          | Type            | Required | Description                                                                                                                                                                                              |
| ----------------- | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entityId`        | ID (`ent_…`)    | no       | –                                                                                                                                                                                                        |
| `agentId`         | ID (`agt_…`)    | no       | –                                                                                                                                                                                                        |
| `clientId`        | ID (`ocl_…`)    | no       | –                                                                                                                                                                                                        |
| `tiers`           | object          | no       | –                                                                                                                                                                                                        |
| `twoPersonFor`    | array of string | no       | (at most 50 items)                                                                                                                                                                                       |
| `amountLimits`    | array of object | no       | (at most 100 items)                                                                                                                                                                                      |
| `version`         | integer         | no       | (0–9007199254740991)                                                                                                                                                                                     |
| `idempotency_key` | string          | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean         | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): The override names no subject or several, an unknown or ineligible operation, compliance or security set to allow, or amount limits that don't fit (`details.issues`).
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No legal entity with this ID exists in the organization.
- [`approval_policy_override_limit_reached`](https://ownrecord.io/docs/reference/errors.md#approval_policy_override_limit_reached): The organization already has 100 overrides.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The override changed since you read it (`version`); read it again.
- [`fresh_auth_required`](https://ownrecord.io/docs/reference/errors.md#fresh_auth_required): You last signed in more than 15 minutes ago.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): Only owners and admins change the approval policy.

### Examples

**One agent may not move money**

Arguments:

```json
{
  "agentId": "agt_01m4ttwd3veh9apbewxheq5xhc",
  "tiers": {
    "financial": "deny"
  },
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "approval_policy",
  "id": "apol_01m4ttwd3veh9apbewxheq5xh9",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "tiers": {
    "write": "allow",
    "financial": "allow",
    "compliance": "require_approval",
    "security": "require_approval"
  },
  "twoPersonFor": ["brands.update"],
  "amountLimits": [],
  "version": 2,
  "updatedAt": "2026-10-13T14:30:00.000Z",
  "overrides": [
    {
      "id": "apol_01m4ttwd3veh9apbewxheq5xhb",
      "object": "approval_policy_override",
      "entityId": null,
      "agentId": "agt_01m4ttwd3veh9apbewxheq5xhc",
      "clientId": null,
      "tiers": {
        "write": null,
        "financial": "deny",
        "compliance": null,
        "security": null
      },
      "twoPersonFor": [],
      "amountLimits": [],
      "version": 1,
      "updatedAt": "2026-10-13T14:30:00.000Z"
    }
  ],
  "availableOperations": [
    {
      "id": "brands.update",
      "summary": "Update a brand",
      "riskTier": "write",
      "scope": "brand",
      "amounts": false
    },
    {
      "id": "members.remove",
      "summary": "Remove a member",
      "riskTier": "security",
      "scope": "org",
      "amounts": false
    }
  ]
}
```

**Refunds at one legal entity need a person above EUR 200**

Arguments:

```json
{
  "entityId": "ent_01m4ttwd3veh9apbewxheq5xh4",
  "amountLimits": [
    {
      "operationId": "refunds.create",
      "perCall": {
        "amount": "200000000",
        "currency": "EUR"
      }
    }
  ],
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "approval_policy",
  "id": "apol_01m4ttwd3veh9apbewxheq5xh9",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "tiers": {
    "write": "allow",
    "financial": "allow",
    "compliance": "require_approval",
    "security": "require_approval"
  },
  "twoPersonFor": ["brands.update"],
  "amountLimits": [],
  "version": 2,
  "updatedAt": "2026-10-13T14:30:00.000Z",
  "overrides": [
    {
      "id": "apol_01m4ttwd3veh9apbewxheq5xhb",
      "object": "approval_policy_override",
      "entityId": "ent_01m4ttwd3veh9apbewxheq5xh4",
      "agentId": null,
      "clientId": null,
      "tiers": {
        "write": null,
        "financial": null,
        "compliance": null,
        "security": null
      },
      "twoPersonFor": [],
      "amountLimits": [
        {
          "operationId": "refunds.create",
          "perCall": {
            "amount": "200000000",
            "currency": "EUR"
          }
        }
      ],
      "version": 1,
      "updatedAt": "2026-10-13T14:30:00.000Z"
    }
  ],
  "availableOperations": [
    {
      "id": "brands.update",
      "summary": "Update a brand",
      "riskTier": "write",
      "scope": "brand",
      "amounts": false
    },
    {
      "id": "members.remove",
      "summary": "Remove a member",
      "riskTier": "security",
      "scope": "org",
      "amounts": false
    }
  ]
}
```

## `approval_policies_update`

**Update the approval policy.** Operation [`approval_policies.update`](https://ownrecord.io/docs/reference/approval-policies-update.md) · Organization level · permission `approvals:admin` · risk tier `security` · since M2

Changes the organization's approval policy. Each part you send replaces the current one; leave one out to
keep it.

- `tiers`: what agents, apps and MCP clients may do per risk tier: `allow`, `require_approval` or `deny`
  (a denied call fails with `approval_policy_denied`). Compliance and security are `require_approval` or
  `deny`, never `allow`: those calls always need a person.
- `twoPersonFor`: operations that need a second person's approval, whoever calls. For a call by an agent or
  app, two people approve.
- `amountLimits`: for operations that carry an amount, the amount per currency at or below which a call runs
  at once (micros as a string). Above it, in a currency without a limit, or without an amount, an agent's or
  app's call needs approval; for people the limits apply to the operations in `twoPersonFor`.

Only changes inside the organization that support dry runs can be named (`availableOperations` in
`approval_policies.get`), never the approvals operations themselves. Overrides for single entities, agents
and apps are set with `approval_policies.overrides.set`. Requests already waiting for approval keep their
requirement. Owners and admins only, with a sign-in in the last 15 minutes.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument          | Type            | Required | Description                                                                                                                                                                                              |
| ----------------- | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tiers`           | object          | no       | –                                                                                                                                                                                                        |
| `twoPersonFor`    | array of string | no       | (at most 50 items)                                                                                                                                                                                       |
| `amountLimits`    | array of object | no       | (at most 100 items)                                                                                                                                                                                      |
| `version`         | integer         | no       | (0–9007199254740991)                                                                                                                                                                                     |
| `idempotency_key` | string          | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean         | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): The policy names an unknown or ineligible operation, sets compliance or security to allow, or its amount limits don't fit (`details.issues`).
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The policy changed since you read it (`version`); read it again.
- [`fresh_auth_required`](https://ownrecord.io/docs/reference/errors.md#fresh_auth_required): You last signed in more than 15 minutes ago.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): Only owners and admins change the approval policy.

### Examples

**Require a second person for brand changes**

Arguments:

```json
{
  "twoPersonFor": ["brands.update"],
  "version": 1,
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "approval_policy",
  "id": "apol_01m4ttwd3veh9apbewxheq5xh9",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "tiers": {
    "write": "allow",
    "financial": "allow",
    "compliance": "require_approval",
    "security": "require_approval"
  },
  "twoPersonFor": ["brands.update"],
  "amountLimits": [],
  "version": 2,
  "updatedAt": "2026-10-13T14:30:00.000Z",
  "overrides": [],
  "availableOperations": [
    {
      "id": "brands.update",
      "summary": "Update a brand",
      "riskTier": "write",
      "scope": "brand",
      "amounts": false
    },
    {
      "id": "members.remove",
      "summary": "Remove a member",
      "riskTier": "security",
      "scope": "org",
      "amounts": false
    }
  ]
}
```

**Agents and apps may not change anything without approval**

Arguments:

```json
{
  "tiers": {
    "write": "require_approval",
    "financial": "require_approval"
  },
  "version": 2,
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "approval_policy",
  "id": "apol_01m4ttwd3veh9apbewxheq5xh9",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "tiers": {
    "write": "require_approval",
    "financial": "require_approval",
    "compliance": "require_approval",
    "security": "require_approval"
  },
  "twoPersonFor": ["brands.update"],
  "amountLimits": [],
  "version": 3,
  "updatedAt": "2026-10-13T14:30:00.000Z",
  "overrides": [],
  "availableOperations": [
    {
      "id": "brands.update",
      "summary": "Update a brand",
      "riskTier": "write",
      "scope": "brand",
      "amounts": false
    },
    {
      "id": "members.remove",
      "summary": "Remove a member",
      "riskTier": "security",
      "scope": "org",
      "amounts": false
    }
  ]
}
```

**Turn the two-person rule off**

Arguments:

```json
{
  "twoPersonFor": [],
  "amountLimits": [],
  "version": 2,
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "approval_policy",
  "id": "apol_01m4ttwd3veh9apbewxheq5xh9",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "tiers": {
    "write": "allow",
    "financial": "allow",
    "compliance": "require_approval",
    "security": "require_approval"
  },
  "twoPersonFor": [],
  "amountLimits": [],
  "version": 3,
  "updatedAt": "2026-10-13T14:30:00.000Z",
  "overrides": [],
  "availableOperations": [
    {
      "id": "brands.update",
      "summary": "Update a brand",
      "riskTier": "write",
      "scope": "brand",
      "amounts": false
    },
    {
      "id": "members.remove",
      "summary": "Remove a member",
      "riskTier": "security",
      "scope": "org",
      "amounts": false
    }
  ]
}
```
