# Set an approval policy override

> The approval_policies.overrides.set operation: PUT /api/v1/approval_policy/overrides in the REST API and the approval_policies_overrides_set tool in the MCP server.

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.

## At a glance

- **REST:** `PUT /api/v1/approval_policy/overrides`
- **MCP tool:** `approval_policies_overrides_set`
- **Operation ID:** `approval_policies.overrides.set`
- **Scope:** Organization
- **Permission:** `approvals:admin`
- **Risk tier:** `security`
- **Dry run:** Supported (send `Ownrecord-Dry-Run: true`)
- **Idempotency:** `Idempotency-Key` optional
- **Modes:** Test and live
- **Authentication:** API key with the `approvals:admin` scope
- **Fresh sign-in:** In the console, a sign-in within the last 15 minutes
- **Since:** M10

## Request

### Body

A JSON object (`Content-Type: application/json`):

| Field                        | Type                                               | Required | Description |
| ---------------------------- | -------------------------------------------------- | -------- | ----------- |
| `entityId`                   | `ent_…` ID                                         | No       |             |
| `agentId`                    | `agt_…` ID                                         | No       |             |
| `clientId`                   | `ocl_…` ID                                         | No       |             |
| `tiers`                      | object                                             | No       |             |
| `tiers.write`                | one of `allow`, `require_approval`, `deny` or null | No       |             |
| `tiers.financial`            | one of `allow`, `require_approval`, `deny` or null | No       |             |
| `tiers.compliance`           | one of `allow`, `require_approval`, `deny` or null | No       |             |
| `tiers.security`             | one of `allow`, `require_approval`, `deny` or null | No       |             |
| `twoPersonFor`               | array of string                                    | No       |             |
| `amountLimits`               | array of object                                    | No       |             |
| `amountLimits[].operationId` | string                                             | Yes      |             |
| `amountLimits[].perCall`     | money                                              | Yes      |             |
| `version`                    | integer (at least 0)                               | No       |             |

## Response

`200 OK` with a JSON object:

| Field                                    | Type                                                  | Description |
| ---------------------------------------- | ----------------------------------------------------- | ----------- |
| `object`                                 | `"approval_policy"`                                   |             |
| `id`                                     | `apol_…` ID or null                                   |             |
| `orgId`                                  | `org_…` ID                                            |             |
| `tiers`                                  | object                                                |             |
| `tiers.write`                            | one of `allow`, `require_approval`, `deny`            |             |
| `tiers.financial`                        | one of `allow`, `require_approval`, `deny`            |             |
| `tiers.compliance`                       | one of `allow`, `require_approval`, `deny`            |             |
| `tiers.security`                         | one of `allow`, `require_approval`, `deny`            |             |
| `twoPersonFor`                           | array of string                                       |             |
| `amountLimits`                           | array of object                                       |             |
| `amountLimits[].operationId`             | string                                                |             |
| `amountLimits[].perCall`                 | money                                                 |             |
| `version`                                | integer (at least 0)                                  |             |
| `updatedAt`                              | date-time or null                                     |             |
| `overrides`                              | array of object                                       |             |
| `overrides[].id`                         | `apol_…` ID                                           |             |
| `overrides[].object`                     | `"approval_policy_override"`                          |             |
| `overrides[].entityId`                   | `ent_…` ID or null                                    |             |
| `overrides[].agentId`                    | `agt_…` ID or null                                    |             |
| `overrides[].clientId`                   | `ocl_…` ID or null                                    |             |
| `overrides[].tiers`                      | object                                                |             |
| `overrides[].tiers.write`                | one of `allow`, `require_approval`, `deny` or null    |             |
| `overrides[].tiers.financial`            | one of `allow`, `require_approval`, `deny` or null    |             |
| `overrides[].tiers.compliance`           | one of `allow`, `require_approval`, `deny` or null    |             |
| `overrides[].tiers.security`             | one of `allow`, `require_approval`, `deny` or null    |             |
| `overrides[].twoPersonFor`               | array of string                                       |             |
| `overrides[].amountLimits`               | array of object                                       |             |
| `overrides[].amountLimits[].operationId` | string                                                |             |
| `overrides[].amountLimits[].perCall`     | money                                                 |             |
| `overrides[].version`                    | integer (at least 1)                                  |             |
| `overrides[].updatedAt`                  | date-time                                             |             |
| `availableOperations`                    | array of object                                       |             |
| `availableOperations[].id`               | string                                                |             |
| `availableOperations[].summary`          | string                                                |             |
| `availableOperations[].riskTier`         | one of `write`, `financial`, `compliance`, `security` |             |
| `availableOperations[].scope`            | one of `org`, `entity`, `brand`                       |             |
| `availableOperations[].amounts`          | boolean                                               |             |

## Examples

### One agent may not move money

```http
PUT /api/v1/approval_policy/overrides
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "agentId": "agt_01m4ttwd3veh9apbewxheq5xhc",
  "tiers": {
    "financial": "deny"
  }
}
```

Response (`200`):

```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

```http
PUT /api/v1/approval_policy/overrides
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "entityId": "ent_01m4ttwd3veh9apbewxheq5xh4",
  "amountLimits": [
    {
      "operationId": "refunds.create",
      "perCall": {
        "amount": "200000000",
        "currency": "EUR"
      }
    }
  ]
}
```

Response (`200`):

```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
    }
  ]
}
```

## Errors

| Code                                                                                                                             | HTTP status | When                                                                                                                                                                   | What to do                                                                                                                    |
| -------------------------------------------------------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed)                                           | 400         | 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`). | Fix the fields listed in `details.issues` and send the request again.                                                         |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found)                                         | 404         | No legal entity with this ID exists in the organization.                                                                                                               | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.                          |
| [`approval_policy_override_limit_reached`](https://ownrecord.io/docs/reference/errors.md#approval_policy_override_limit_reached) | 409         | The organization already has 100 overrides.                                                                                                                            | Delete an override you no longer need (`details.limit` is the maximum), or set the rule in the organization's policy instead. |
| [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict)                                             | 409         | The override changed since you read it (`version`); read it again.                                                                                                     | Fetch the object again and retry the change.                                                                                  |
| [`fresh_auth_required`](https://ownrecord.io/docs/reference/errors.md#fresh_auth_required)                                       | 403         | You last signed in more than 15 minutes ago.                                                                                                                           | Sign in again, then repeat the action within 15 minutes.                                                                      |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)                                           | 403         | Only owners and admins change the approval policy.                                                                                                                     | Ask an organization owner or admin for a role or scope that allows this action.                                               |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`invalid_json`](https://ownrecord.io/docs/reference/errors.md#invalid_json), [`unsupported_media_type`](https://ownrecord.io/docs/reference/errors.md#unsupported_media_type), [`authentication_required`](https://ownrecord.io/docs/reference/errors.md#authentication_required), [`api_key_invalid`](https://ownrecord.io/docs/reference/errors.md#api_key_invalid), [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://ownrecord.io/docs/reference/errors.md#idempotency_in_progress), [`approval_required`](https://ownrecord.io/docs/reference/errors.md#approval_required), [`approval_rejected`](https://ownrecord.io/docs/reference/errors.md#approval_rejected), [`approval_expired`](https://ownrecord.io/docs/reference/errors.md#approval_expired), [`stale_approval`](https://ownrecord.io/docs/reference/errors.md#stale_approval), [`approval_policy_denied`](https://ownrecord.io/docs/reference/errors.md#approval_policy_denied), [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
