Update the approval policy
The approval_policies.update operation: PATCH /api/v1/approval_policy in the REST API and the approval_policies_update tool in the MCP server.
/api/v1/approval_policyChanges 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_approvalordeny(a denied call fails withapproval_policy_denied). Compliance and security arerequire_approvalordeny, neverallow: 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 intwoPersonFor.
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.
At a glance
- REST:
PATCH /api/v1/approval_policy - MCP tool:
approval_policies_update - Operation ID:
approval_policies.update - Scope: Organization
- Permission:
approvals:admin - Risk tier:
security - Dry run: Supported (send
Ownrecord-Dry-Run: true) - Idempotency:
Idempotency-Keyoptional - Modes: Test and live
- Authentication: API key with the
approvals:adminscope - Fresh sign-in: In the console, a sign-in within the last 15 minutes
- Since: M2
Request
Body
A JSON object (Content-Type: application/json):
| Field | Type | Required | Description |
|---|---|---|---|
tiers | object | No | |
tiers.write | one of allow, require_approval, deny | No | |
tiers.financial | one of allow, require_approval, deny | No | |
tiers.compliance | one of allow, require_approval, deny | No | |
tiers.security | one of allow, require_approval, deny | 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
Require a second person for brand changes
PATCH /api/v1/approval_policy
Authorization: Bearer or_test_…
Content-Type: application/json
{
"twoPersonFor": [
"brands.update"
],
"version": 1
}
Response (200):
{
"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
PATCH /api/v1/approval_policy
Authorization: Bearer or_test_…
Content-Type: application/json
{
"tiers": {
"write": "require_approval",
"financial": "require_approval"
},
"version": 2
}
Response (200):
{
"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
PATCH /api/v1/approval_policy
Authorization: Bearer or_test_…
Content-Type: application/json
{
"twoPersonFor": [],
"amountLimits": [],
"version": 2
}
Response (200):
{
"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
}
]
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
validation_failed | 400 | The policy names an unknown or ineligible operation, sets compliance or security to allow, or its amount limits don't fit (details.issues). | Fix the fields listed in details.issues and send the request again. |
version_conflict | 409 | The policy changed since you read it (version); read it again. | Fetch the object again and retry the change. |
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 | 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: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, resource_not_found, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.