Approvals and AgentHub
Propose sensitive changes; a signed-in person decides in the AgentHub; approval policies.
Start with: approvals_submit, approvals_list, approvals_decide, approvals_get.
9 operations. Discover them from an agent with agentdb_capabilities {"category": "approvals_hub"}.
#approval_policies_create
Owners/admins: require approval for writes. Keys: name, operations (domain names: records.update, records.*, *), objects (object scope, e.g. ["deal"]), fields (e.g. ["amount"]), condition {field, op: gt|gte|lt|lte|eq|neq, value} (amount thresholds), applies_to (default ["agent"] = agent keys and OAuth connectors; ["agent", "key"] also covers account-key agents such as Claude Code), approvers {min_role (default admin), members, kinds}, quorum, expires_in_seconds, confirm (high-risk), human_only (default true: a signed-in person decides in the AgentHub), distinct_approver (four-eyes), enabled. Example: {"name": "Large deals need an admin", "operations": ["records.update"], "objects": ["deal"], "fields": ["amount"], "condition": {"field": "amount", "op": "gt", "value": 10000}, "applies_to": ["agent", "key"]}. agentdb_capabilities {operation: "approval_policies_create"} shows a full example.
- MCP tool
approval_policies_create- REST
POST /v1/workspaces/{ws}/approval-policiesscope schema:write
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
name | string | yes | Policy name shown to approvers, e.g. "Large deals need an admin". (min length 1, max length 100) |
operations | string[] | yes | Domain operation names that need approval: "records.update", a prefix "records.*" or "*". Use domain names (records.update), not tool names (records_update). (max 50 items) |
objects | string[] | Object scope: only writes to these object types, e.g. ["deal"]. Omit for every object. (max 50 items) | |
fields | string[] | Field scope: only writes that touch one of these fields, e.g. ["amount", "stage"]. Deletes touch every field. Omit for any field. (max 50 items) | |
condition | object | Only when a proposed value meets this condition, e.g. {"field": "amount", "op": "gt", "value": 1000}. Omit for every matching write. | |
applies_to | "agent" | "user" | "key" | "form"[] | Callers the policy covers. Default ["agent"] (agent keys and OAuth MCP connectors). Add "key" to also cover account and workspace API keys used by agents such as Claude Code: ["agent", "key"]. "user" = people, "form" = public form submissions. (max 4 items, default ["agent"]) | |
approvers | object | Who may decide: {min_role, members, kinds}. Default {min_role: "admin", members: [], kinds: ["user", "key"]}. (default {"min_role":"admin","members":[],"kinds":["user","key"]}) | |
quorum | integer | Distinct approvals needed (1-5, default 1). (min 1, max 5, default 1) | |
expires_in_seconds | integer | Proposals expire after this many seconds (60 to 2592000, default 604800 = 7 days). (min 60, max 2592000, default 604800) | |
confirm | boolean | High-risk: the approver repeats the approval id as confirm. Default false. (default false) | |
enabled | boolean | Default true. false keeps the policy but stops it applying. (default true) | |
human_only | boolean | Default true: only a signed-in person in the AgentHub (/app/hub) can decide; no API key, OAuth token or agent can. false: any principal the approvers rule allows. (default true) | |
distinct_approver | boolean | Four-eyes. Default false. true: whoever submitted a proposal can never decide it. (default false) | |
idempotency_key | string | Optional retry key ([A-Za-z0-9._:-], max 255). Repeating a call with the same key and arguments returns the original result without writing again. | |
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approval_policies_create",
"arguments": {
"name": "Large deals need an admin",
"operations": [
"records.update",
"records.create"
],
"objects": [
"deal"
],
"fields": [
"amount",
"stage"
],
"condition": {
"field": "amount",
"op": "gt",
"value": 10000
},
"applies_to": [
"agent",
"key"
],
"approvers": {
"min_role": "admin",
"members": [],
"kinds": [
"user"
]
},
"quorum": 1,
"expires_in_seconds": 604800,
"human_only": true,
"distinct_approver": false,
"enabled": true
}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approval_policies_create",
"arguments": {
"name": "Large deals need an admin",
"operations": [
"records.update",
"records.create"
],
"objects": [
"deal"
],
"fields": [
"amount",
"stage"
],
"condition": {
"field": "amount",
"op": "gt",
"value": 10000
},
"applies_to": [
"agent",
"key"
],
"approvers": {
"min_role": "admin",
"members": [],
"kinds": [
"user"
]
},
"quorum": 1,
"expires_in_seconds": 604800,
"human_only": true,
"distinct_approver": false,
"enabled": true
}
}
}curl -s -X POST "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approval-policies" \
-H "Authorization: Bearer $AGENTDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Large deals need an admin","operations":["records.update","records.create"],"objects":["deal"],"fields":["amount","stage"],"condition":{"field":"amount","op":"gt","value":10000},"applies_to":["agent","key"],"approvers":{"min_role":"admin","members":[],"kinds":["user"]},"quorum":1,"expires_in_seconds":604800,"human_only":true,"distinct_approver":false,"enabled":true}'#approval_policies_delete
Delete an approval policy. Pending proposals keep the requirements they were submitted with.
- MCP tool
approval_policies_delete- REST
DELETE /v1/workspaces/{ws}/approval-policies/{policy}scope schema:write
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
policy_id | string | yes | Policy id (apl_...) |
idempotency_key | string | Optional retry key ([A-Za-z0-9._:-], max 255). Repeating a call with the same key and arguments returns the original result without writing again. | |
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approval_policies_delete",
"arguments": {
"policy_id": "apl_example"
}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approval_policies_delete",
"arguments": {
"policy_id": "apl_example"
}
}
}curl -s -X DELETE "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approval-policies/apl_example" \
-H "Authorization: Bearer $AGENTDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'#approval_policies_list
Approval policies and the operations that can be proposed.
- MCP tool
approval_policies_list- REST
GET /v1/workspaces/{ws}/approval-policiesscope schema:read
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approval_policies_list",
"arguments": {}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approval_policies_list",
"arguments": {}
}
}curl -s "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approval-policies" \
-H "Authorization: Bearer $AGENTDB_TOKEN"#approval_policies_update
Change an approval policy (send its current version; null removes objects, fields or condition). Same keys as approval_policies_create, each optional.
- MCP tool
approval_policies_update- REST
PATCH /v1/workspaces/{ws}/approval-policies/{policy}scope schema:write
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
version | integer | yes | The current version of the item. The call fails with VERSION_CONFLICT if it changed. |
name | string | Policy name shown to approvers, e.g. "Large deals need an admin". (min length 1, max length 100) | |
operations | string[] | Domain operation names that need approval: "records.update", a prefix "records.*" or "*". Use domain names (records.update), not tool names (records_update). (max 50 items) | |
objects | string[] | null | string[] | null | |
fields | string[] | null | string[] | null | |
condition | object | null | object | null | |
applies_to | "agent" | "user" | "key" | "form"[] | Callers the policy covers. Default ["agent"] (agent keys and OAuth MCP connectors). Add "key" to also cover account and workspace API keys used by agents such as Claude Code: ["agent", "key"]. "user" = people, "form" = public form submissions. (max 4 items) | |
approvers | object | Who may decide: {min_role, members, kinds}. Default {min_role: "admin", members: [], kinds: ["user", "key"]}. | |
quorum | integer | Distinct approvals needed (1-5, default 1). (min 1, max 5) | |
expires_in_seconds | integer | Proposals expire after this many seconds (60 to 2592000, default 604800 = 7 days). (min 60, max 2592000) | |
confirm | boolean | High-risk: the approver repeats the approval id as confirm. Default false. | |
enabled | boolean | Default true. false keeps the policy but stops it applying. | |
human_only | boolean | Default true: only a signed-in person in the AgentHub (/app/hub) can decide; no API key, OAuth token or agent can. false: any principal the approvers rule allows. | |
distinct_approver | boolean | Four-eyes. Default false. true: whoever submitted a proposal can never decide it. | |
policy_id | string | yes | Policy id (apl_...) |
idempotency_key | string | Optional retry key ([A-Za-z0-9._:-], max 255). Repeating a call with the same key and arguments returns the original result without writing again. | |
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approval_policies_update",
"arguments": {
"policy_id": "apl_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"version": 1,
"objects": [
"deal",
"quote"
],
"condition": null
}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approval_policies_update",
"arguments": {
"policy_id": "apl_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"version": 1,
"objects": [
"deal",
"quote"
],
"condition": null
}
}
}curl -s -X PATCH "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approval-policies/apl_aaaaaaaaaaaaaaaaaaaaaaaaaa" \
-H "Authorization: Bearer $AGENTDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"version":1,"objects":["deal","quote"],"condition":null}'#approvals_cancel
Withdraw a pending proposal (the proposer, or an admin).
- MCP tool
approvals_cancel- REST
POST /v1/workspaces/{ws}/approvals/{approval}/cancelscope records:read- CLI
agentdb approvals cancel
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
comment | string | string, up to 2000 characters | |
approval_id | string | yes | Approval id (apr_...) to withdraw. The key is approval_id, not id. |
idempotency_key | string | Optional retry key ([A-Za-z0-9._:-], max 255). Repeating a call with the same key and arguments returns the original result without writing again. | |
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approvals_cancel",
"arguments": {
"approval_id": "apr_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"comment": "Superseded by a corrected proposal."
}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approvals_cancel",
"arguments": {
"approval_id": "apr_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"comment": "Superseded by a corrected proposal."
}
}
}curl -s -X POST "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approvals/apr_aaaaaaaaaaaaaaaaaaaaaaaaaa/cancel" \
-H "Authorization: Bearer $AGENTDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"comment":"Superseded by a corrected proposal."}'agentdb approvals cancel [options] <approval_id>#approvals_decide
Approve, reject or request changes on someone else's proposal (you can't decide your own). Arguments: {"approval_id": "apr_...", "decision": "approve" | "reject" | "request_changes", "comment"?, "action_hash"?, "confirm"?}. Needs the role the policy names and the rights to make the change yourself. action_hash: the proposal's action_hash from approvals_get; a mismatch is refused (ACTION_CHANGED). The approval that reaches the quorum runs the change once. High-risk policies need confirm = the approval id. Human-only proposals (the default) can't be decided here: only a signed-in person in the AgentHub can (FORBIDDEN, reason human_session_required, with decide_in). Policies with human_only: false accept keys with the role.
- MCP tool
approvals_decide- REST
POST /v1/workspaces/{ws}/approvals/{approval}/decidescope records:read
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
decision | "approve" | "reject" | "request_changes" | yes | Your decision. |
comment | string | string, up to 2000 characters | |
confirm | string | string, up to 64 characters | |
action_hash | string | string | |
approval_id | string | yes | Approval id (apr_...) to decide. The key is approval_id, not id. |
idempotency_key | string | Optional retry key ([A-Za-z0-9._:-], max 255). Repeating a call with the same key and arguments returns the original result without writing again. | |
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approvals_decide",
"arguments": {
"approval_id": "apr_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"decision": "approve",
"comment": "Checked the signed order form."
}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approvals_decide",
"arguments": {
"approval_id": "apr_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"decision": "approve",
"comment": "Checked the signed order form."
}
}
}curl -s -X POST "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approvals/apr_aaaaaaaaaaaaaaaaaaaaaaaaaa/decide" \
-H "Authorization: Bearer $AGENTDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"decision":"approve","comment":"Checked the signed order form."}'#approvals_get
One proposal: operation, input, preview/diff, requirements, human_only, action_hash, decisions with comments, result or error. can_decide is false for every API key on human-only proposals.
- MCP tool
approvals_get- REST
GET /v1/workspaces/{ws}/approvals/{approval}scope records:read- CLI
agentdb approvals get
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
approval_id | string | yes | Approval id (apr_...), e.g. from approvals_submit or approvals_list. The key is approval_id, not id. |
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approvals_get",
"arguments": {
"approval_id": "apr_aaaaaaaaaaaaaaaaaaaaaaaaaa"
}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approvals_get",
"arguments": {
"approval_id": "apr_aaaaaaaaaaaaaaaaaaaaaaaaaa"
}
}
}curl -s "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approvals/apr_aaaaaaaaaaaaaaaaaaaaaaaaaa" \
-H "Authorization: Bearer $AGENTDB_TOKEN"agentdb approvals get [options] <approval_id>#approvals_list
Proposals, newest first. Filter by status; mine=true for yours; decidable=true for those you may decide now.
- MCP tool
approvals_list- REST
GET /v1/workspaces/{ws}/approvalsscope records:read- CLI
agentdb approvals list
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
status | "pending" | "executed" | "failed" | "rejected" | "changes_requested" | "expired" | "cancelled" | string, one of: pending, executed, failed, rejected, changes_requested, expired, cancelled | |
mine | boolean | "0" | "1" | "true" | "false" | boolean | "0" | "1" | "true" | "false" | |
decidable | boolean | "0" | "1" | "true" | "false" | boolean | "0" | "1" | "true" | "false" | |
limit | integer | integer, 1–100, default 50 | |
cursor | string | string, up to 200 characters | |
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approvals_list",
"arguments": {
"status": "pending",
"decidable": true
}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approvals_list",
"arguments": {
"status": "pending",
"decidable": true
}
}
}curl -s "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approvals" \
-H "Authorization: Bearer $AGENTDB_TOKEN"agentdb approvals list [options]#approvals_submit
Propose a write for human approval instead of running it. MCP form: operation = a write tool name with that tool's own arguments in arguments: {"operation": "records_update", "arguments": {"record_id": "rec_...", "version": 3, "data": {"amount": 25000}}, "justification": "..."}. Or a domain name with params + input (the REST form, POST /v1/workspaces/{ws}/approvals): {"operation": "records.update", "params": {"record": "rec_..."}, "input": {"version": 3, "data": {...}}}. Never mix arguments with params/input. Give a justification and evidence. Use it when a write fails with APPROVAL_REQUIRED, or for sensitive changes. The change runs once, as you, when approved (same idempotency_key). Check the outcome with approvals_get: pending, executed (with result), failed (e.g. VERSION_CONFLICT: re-read and propose again), rejected, changes_requested, expired, cancelled. Human-only proposals (human_only: true, the default) are decided by a signed-in person in the AgentHub (decide_in); tell the person, then poll. For uncertain import rules, propose imports.normalize_uncertain and run imports_run with approval_id once approved.
- MCP tool
approvals_submit- REST
POST /v1/workspaces/{ws}/approvalsscope records:read- CLI
agentdb approvals submit
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
operation | string | yes | The operation to propose, e.g. records.update. (min length 1, max length 64) |
params | object | object, default {} | |
input | any | any | |
justification | string | string, up to 4000 characters | |
evidence | any | any | |
expires_in_seconds | integer | integer, 60–2592000 | |
supersedes | string | string, up to 64 characters | |
arguments | object | With a write tool name as operation: that tool's arguments (e.g. {record_id, version, data} for records_update). Replaces params and input. | |
idempotency_key | string | Optional retry key ([A-Za-z0-9._:-], max 255). Repeating a call with the same key and arguments returns the original result without writing again. | |
workspace | string | Workspace id (preferred), slug or exact name. Omit for the default workspace. Resolve names once with workspace_select. |
Example
{
"tool": "approvals_submit",
"arguments": {
"operation": "records_update",
"arguments": {
"record_id": "rec_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"version": 3,
"data": {
"amount": 25000,
"stage": "won"
}
},
"justification": "The customer signed the order form for 25,000 EUR.",
"evidence": {
"source": "signed order form",
"url": "https://example.test/orders/1042"
},
"idempotency_key": "propose-deal-1042-won"
}
}{
"tool": "agentdb_execute",
"arguments": {
"operation": "approvals_submit",
"arguments": {
"operation": "records_update",
"arguments": {
"record_id": "rec_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"version": 3,
"data": {
"amount": 25000,
"stage": "won"
}
},
"justification": "The customer signed the order form for 25,000 EUR.",
"evidence": {
"source": "signed order form",
"url": "https://example.test/orders/1042"
},
"idempotency_key": "propose-deal-1042-won"
}
}
}curl -s -X POST "https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/approvals" \
-H "Authorization: Bearer $AGENTDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"operation":"records_update","arguments":{"record_id":"rec_aaaaaaaaaaaaaaaaaaaaaaaaaa","version":3,"data":{"amount":25000,"stage":"won"}},"justification":"The customer signed the order form for 25,000 EUR.","evidence":{"source":"signed order form","url":"https://example.test/orders/1042"}}'agentdb approvals submit [options]