Appearance
Agent Tool Overrides & Permissions API
These endpoints manage per-agent tool permission levels (three-tier model) and per-user "approve always" overrides that skip the HITL approval prompt for subsequent tool invocations. All paths sit under the /ai prefix.
Authentication
All endpoints require:
- A valid
Authorization: Bearer <jwt>token (decorated with@Auth()) - Without a valid token the API returns
401 Unauthorized
The JWT's userId and agencyId claims are used to scope overrides to the authenticated user.
PUT /ai/agents/:agentId/tools
Upserts the full tool-permission list for an agent. Replaces the previous enabledTools model with a three-tier permission status per tool. (REQ-INTERNAL-TOOLS-1)
Breaking change from v1: the legacy
{ enabledTools: string[] }request body is rejected with400. Use the newtoolsarray shape.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
agentId | UUID v7 | The AI agent's identifier |
Request Body
json
{
"tools": [
{
"toolName": "create_task",
"permissionStatus": "needs_approval",
"providerKey": "operations"
},
{
"toolName": "list_tasks",
"permissionStatus": "always_allow",
"providerKey": "operations"
},
{
"toolName": "delete_task",
"permissionStatus": "blocked",
"providerKey": "operations"
}
]
}| Field | Type | Constraints | Description |
|---|---|---|---|
tools | ToolPermissionInput[] | min 0 items | Full desired permission set for the agent |
tools[].toolName | string | min length 1 | Tool name from the static catalog |
tools[].permissionStatus | 'always_allow' | 'needs_approval' | 'blocked' | required | Three-tier permission level |
tools[].providerKey | string | min length 1 | Provider that owns the tool (e.g. "operations", "mcp__github") |
Permission levels:
| Value | Runtime behaviour |
|---|---|
always_allow | Tool is included in the LLM tools map and executes immediately — no user prompt |
needs_approval | Tool is included but the Vercel AI SDK pauses with state='approval-requested' before execution. A user override bypasses this. |
blocked | Tool is excluded from the tools map entirely — the LLM never sees its schema |
Response — 200 OK
json
{
"agentId": "01927f3e-0000-7000-8000-000000000001",
"toolCount": 3
}Errors
| Status | Code | When |
|---|---|---|
| 400 | Zod validation error | Body is invalid — includes sending the legacy { enabledTools } shape |
| 401 | — | Missing or invalid JWT |
| 404 | AI.AGENT_NOT_FOUND | The agent does not exist |
Example — set three-tier permissions
bash
curl -X PUT \
"https://api.daramex.app/ai/agents/01927f3e-0000-7000-8000-000000000001/tools" \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"tools": [
{ "toolName": "create_task", "permissionStatus": "needs_approval", "providerKey": "operations" },
{ "toolName": "list_tasks", "permissionStatus": "always_allow", "providerKey": "operations" },
{ "toolName": "delete_task", "permissionStatus": "blocked", "providerKey": "operations" }
]
}'Example — legacy body rejected (400)
bash
# This shape is no longer accepted
curl -X PUT \
"https://api.daramex.app/ai/agents/01927f3e-0000-7000-8000-000000000001/tools" \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{ "enabledTools": ["create_task"] }'
# Response 400
{
"statusCode": 400,
"message": "Validation failed",
"errors": [{ "path": ["tools"], "message": "Required" }]
}POST /ai/agents/:agentId/tool-overrides
Creates an "approve always" override for the authenticated user on a specific tool. After an override exists, the needsApproval closure returns false for that user+agent+tool combination — no approval prompt is shown on subsequent invocations.
This endpoint is idempotent: re-posting the same (userId, agentId, toolName) returns 200 with the existing row instead of a 409. (REQ-OVER-1)
Path Parameters
| Parameter | Type | Description |
|---|---|---|
agentId | UUID v7 | The AI agent's identifier |
Request Body
json
{ "toolName": "create_task" }| Field | Type | Constraints | Description |
|---|---|---|---|
toolName | string | min length 1 | The tool name to add an override for |
Response — 200 OK
Returns 200 for both new inserts and idempotent repeats (no 201 split — documented simplification, W4 deviation).
json
{
"toolName": "create_task",
"createdAt": "2026-04-13T15:30:00.000Z"
}Errors
| Status | Code | When |
|---|---|---|
| 400 | TOOL_APPROVAL_UNKNOWN_ID | An addToolApprovalResponse id does not match any pending approval in the stream (chat flow, not this endpoint directly) |
| 400 | TOOL_APPROVAL_REASON_TOO_LONG | Denial reason exceeds 2000 characters (chat flow, not this endpoint directly) |
| 401 | — | Missing or invalid JWT |
| 404 | AI.AGENT_NOT_FOUND | The agent does not exist |
Note:
TOOL_APPROVAL_UNKNOWN_IDandTOOL_APPROVAL_REASON_TOO_LONGare surfaced by the/chatstream endpoint, not by this overrides endpoint. They are documented here for discoverability since they belong to the same approval flow.
Example — approve always for create_task
bash
curl -X POST \
"https://api.daramex.app/ai/agents/01927f3e-0000-7000-8000-000000000001/tool-overrides" \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{ "toolName": "create_task" }'DELETE /ai/agents/:agentId/tool-overrides/:toolName
Removes the authenticated user's "approve always" override for a specific tool. After deletion, subsequent invocations of a needs_approval tool will prompt again.
This endpoint is idempotent: deleting a non-existent override returns 204 without error. (REQ-OVER-2)
Path Parameters
| Parameter | Type | Description |
|---|---|---|
agentId | UUID v7 | The AI agent's identifier |
toolName | string | The tool name whose override should be removed |
Response — 204 No Content
No body. 204 is returned whether the override existed or not.
Errors
| Status | Code | When |
|---|---|---|
| 401 | — | Missing or invalid JWT |
Example
bash
curl -X DELETE \
"https://api.daramex.app/ai/agents/01927f3e-0000-7000-8000-000000000001/tool-overrides/create_task" \
-H "Authorization: Bearer <jwt>"GET /ai/agents/:agentId/tool-overrides
Returns the authenticated user's "approve always" overrides for a specific agent. Only the caller's overrides are returned — cross-user isolation is enforced server-side. (REQ-OVER-3)
Path Parameters
| Parameter | Type | Description |
|---|---|---|
agentId | UUID v7 | The AI agent's identifier |
Response — 200 OK
json
{
"overrides": [
{ "toolName": "create_task", "createdAt": "2026-04-13T15:30:00.000Z" },
{ "toolName": "update_event", "createdAt": "2026-04-13T16:00:00.000Z" }
]
}Returns { "overrides": [] } when no overrides exist for the agent.
Errors
| Status | Code | When |
|---|---|---|
| 401 | — | Missing or invalid JWT |
| 404 | AI.AGENT_NOT_FOUND | The agent does not exist |
Example
bash
curl -X GET \
"https://api.daramex.app/ai/agents/01927f3e-0000-7000-8000-000000000001/tool-overrides" \
-H "Authorization: Bearer <jwt>"Spec References
| Endpoint | Spec requirement |
|---|---|
PUT /tools | REQ-INTERNAL-TOOLS-1 |
POST /tool-overrides | REQ-OVER-1 |
DELETE /tool-overrides/:toolName | REQ-OVER-2 |
GET /tool-overrides | REQ-OVER-3 |
| Agent deletion cascade | REQ-OVER-4 |