> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getunbound.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Tool Policy Hooks (Inbound `/v1/hooks/pretool`)

> Enforce tool policies on agent tool calls before execution. Inbound endpoint — your agent calls the gateway, not the other way around.

## Overview

The Tool Policy Hooks endpoint lets you enforce your organization's tool policies on agent tool calls. Before your agent executes a tool — whether it's a terminal command, an MCP tool, or any other action — your agent sends an **inbound** request to this endpoint and the gateway returns a decision. This is a request the agent makes to Unbound; Unbound does not call out to your agent.

Any agent framework or custom application can integrate with it.

Policies are configured at [gateway.getunbound.ai/policies/tool-policies](https://gateway.getunbound.ai/policies/tool-policies).

## Endpoint

```http theme={null}
POST /v1/hooks/pretool
```

## Authentication

Include your API key in the Authorization header:

```
Authorization: Bearer YOUR_API_KEY
```

## Request Body

| Parameter           | Type   | Required | Description                                                                                |
| ------------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
| `conversation_id`   | string | Yes      | Unique identifier for the conversation or session                                          |
| `model`             | string | Yes      | The model being used                                                                       |
| `event_name`        | string | Yes      | `pre_tool_use` for tool policy checks, `user_prompt` for prompt guardrails                 |
| `unbound_app_label` | string | Yes      | Your application identifier (e.g., `openclaw`, `claude-code`, `cursor`, or a custom label) |
| `pre_tool_use_data` | object | Yes      | Details about the tool being invoked (see below)                                           |
| `messages`          | array  | No       | Conversation messages for context                                                          |

### pre\_tool\_use\_data Object

| Parameter   | Type   | Required    | Description                                                                                                                                 |
| ----------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `tool_name` | string | Yes         | Name of the tool. Use `Bash`, `Shell`, or `exec` for terminal commands. For MCP tools, use the full name (e.g., `mcp__slack__send_message`) |
| `command`   | string | Conditional | The shell command string. Required when `tool_name` is `Bash`, `Shell`, or `exec`                                                           |
| `metadata`  | object | No          | Additional metadata. For MCP tools, include `mcp_server` and `mcp_tool`                                                                     |

## Response

| Field                         | Type   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ----------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `decision`                    | string | `allow`, `deny`, or `ask`                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `reason`                      | string | Present when `decision` is `deny` or `ask`. Human-readable explanation                                                                                                                                                                                                                                                                                                                                                                                                               |
| `policy_check_failure_action` | string | Present on every authenticated response — `allow`, `deny`, and `ask` decisions all carry it. Values are `allow` (fail-open) or `block` (fail-closed); carries the action your organization has configured for the case where the policy check itself fails. Honor this when the client cannot reach the gateway. **Cache only the value from authenticated, policy-evaluated responses** — see [Error responses](#error-responses) for why the error-shape value is unsafe to cache. |
| `additionalContext`           | string | Present on `deny` and `ask` responses when the matching policy supplies extra guidance for the client — a human-readable remediation hint or context string to surface alongside the approval prompt. Optional — absent when the policy has no extra context to add.                                                                                                                                                                                                                 |

### Decision Values

| Decision | Meaning                              | Recommended Action                                                                                                                   |
| -------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| `allow`  | Tool call is permitted               | Proceed with execution                                                                                                               |
| `deny`   | Tool call is blocked by policy       | Do not execute. Show the `reason` to the user                                                                                        |
| `ask`    | Tool call requires user confirmation | Prompt the user for approval before executing. If your agent has no confirmation UI, treat as `allow` based on your security posture |

## How It Works

The endpoint handles two types of tools differently:

**Terminal commands** (`Bash`, `Shell`, `exec`): The command is automatically classified and matched against your configured terminal command policies.

**MCP tools**: The `mcp_server` and `mcp_tool` from metadata are matched against your MCP tool policies.

**Other tools**: Tools that don't match a terminal command or MCP tool pattern return `allow`.

## Examples

### Terminal Command (Blocked)

```bash theme={null}
curl -X POST 'https://api.getunbound.ai/v1/hooks/pretool' \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "session-123",
    "model": "claude-sonnet-4-20250514",
    "event_name": "pre_tool_use",
    "unbound_app_label": "my-agent",
    "pre_tool_use_data": {
      "tool_name": "Bash",
      "command": "rm -rf /tmp/data",
      "metadata": {}
    },
    "messages": [
      {"role": "user", "content": "clean up temp files"}
    ]
  }'
```

**Response:**

```json theme={null}
{
  "decision": "deny",
  "reason": "This command is blocked by your organization's policy.",
  "policy_check_failure_action": "block"
}
```

### Terminal Command (Allowed)

```bash theme={null}
curl -X POST 'https://api.getunbound.ai/v1/hooks/pretool' \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "session-123",
    "model": "claude-sonnet-4-20250514",
    "event_name": "pre_tool_use",
    "unbound_app_label": "my-agent",
    "pre_tool_use_data": {
      "tool_name": "Bash",
      "command": "ls -la /tmp",
      "metadata": {}
    },
    "messages": []
  }'
```

**Response:**

```json theme={null}
{
  "decision": "allow",
  "policy_check_failure_action": "allow"
}
```

### MCP Tool

```bash theme={null}
curl -X POST 'https://api.getunbound.ai/v1/hooks/pretool' \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "session-123",
    "model": "claude-sonnet-4-20250514",
    "event_name": "pre_tool_use",
    "unbound_app_label": "my-agent",
    "pre_tool_use_data": {
      "tool_name": "mcp__slack__send_message",
      "command": "",
      "metadata": {
        "mcp_server": "slack",
        "mcp_tool": "send_message"
      }
    },
    "messages": []
  }'
```

**Response** (depends on your configured policies):

```json theme={null}
{
  "decision": "deny",
  "reason": "This MCP tool call is blocked by your organization's policy.",
  "policy_check_failure_action": "block"
}
```

## Error responses

The gateway currently returns `200 OK` with `decision: "allow"` for requests that are malformed or unauthenticated — a fail-open posture. There is no structured error envelope today.

```json theme={null}
{
  "decision": "allow",
  "policy_check_failure_action": "allow"
}
```

If your client needs fail-closed behavior, gate it locally before calling the endpoint (validate the request body, confirm the API key is present) rather than relying on the gateway to reject.

<Warning>
  **Only cache `policy_check_failure_action` from authenticated, policy-evaluated responses** — those reflect your organization's real config. The `policy_check_failure_action: "allow"` returned in the error response above is a hardcoded fail-open value emitted *because* the gateway couldn't evaluate the org's policies; it does not represent the org's configured posture. A client that caches the value from an error response (for example, right after an API-key rotation) will silently apply fail-open behavior even on a fail-closed org. Treat the last-known value from a successful authenticated response as authoritative, and refuse to update the cached value from an error-shape response.
</Warning>

<Note>
  This is the current behavior, not an aspirational contract. If you need a structured error response shape, file a request with Unbound support.
</Note>

## Integration Guide

To integrate tool policies into your agent framework:

1. **Before each tool execution**, send a `POST` request to `/v1/hooks/pretool` with the tool details
2. **Check the `decision`** in the response:
   * `allow` — execute the tool normally
   * `deny` — block execution and surface the `reason` to the user
   * `ask` — prompt the user for confirmation, or treat as `allow` if your agent has no interactive UI
3. **Handle errors gracefully** — if the endpoint is unreachable, decide whether to fail open (allow) or fail closed (deny) based on your security requirements
4. **Configure policies** at [gateway.getunbound.ai/policies/tool-policies](https://gateway.getunbound.ai/policies/tool-policies)
