Tool Hooks API
Tool hooks are synchronous webhooks invoked when a model requests a tool. They let you block, modify, or execute tools on your own infrastructure.
Quick Reference
GET /api/v1/projects/:id/tool-hooks List tool hooks
POST /api/v1/projects/:id/tool-hooks Create tool hook
GET /api/v1/projects/:id/tool-hooks/:hook_id Get tool hook
PUT /api/v1/projects/:id/tool-hooks/:hook_id Update tool hook
DELETE /api/v1/projects/:id/tool-hooks/:hook_id Delete tool hook
GET /api/v1/projects/:id/tool-hooks/:hook_id/events List delivery events
Authentication
Tool hook management endpoints require a session bearer token (dashboard authentication). These endpoints are project-scoped and accessed via the dashboard.
Hook Types
| Hook | When it fires | Can modify? |
|---|---|---|
pre_tool_use |
Before tool execution | Yes - block or modify arguments |
post_tool_use |
After tool execution | Yes - modify result (requires allow_mutation) |
tool_execute |
Instead of built-in execution | Yes - provide result from your server |
Fail Behavior
fail_closed(default forpre_tool_useandtool_execute) stops the request when the hook fails.fail_open(default forpost_tool_use) skips hook errors and continues.
Webhook Payload
ModelRelay sends a JSON payload to your endpoint and signs the raw body.
{
"hook": "pre_tool_use",
"request_id": "req_abc123",
"project_id": "550e8400-e29b-41d4-a716-446655440001",
"end_user_id": "550e8400-e29b-41d4-a716-446655440009",
"tool_call": {
"id": "call_789",
"name": "search_inventory",
"arguments": {"query": "red shoes", "limit": 10}
},
"timestamp": "2025-01-15T10:30:00Z"
}
post_tool_use includes a tool_result field with the tool output JSON.
Webhook Response
{
"action": "allow",
"tool_call": {
"id": "call_789",
"name": "search_inventory",
"arguments": {"query": "red shoes", "limit": 5}
},
"result": {"ok": true},
"error": "reason"
}
Action rules:
allow: continue with the original tool call.block: stop tool usage witherror.modify: replace the tool call (pre/tool_execute) or result (post).result: fortool_execute, return the tool result payload immediately.
Signing
Every tool hook request includes:
X-ModelRelay-Timestamp(RFC3339)X-ModelRelay-Signature(sha256=+ hex HMAC)
Signature string: timestamp + "." + raw_body (HMAC SHA-256 with your signing secret).
List Tool Hooks
GET /api/v1/projects/:id/tool-hooks
Response
{
"hooks": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"project_id": "550e8400-e29b-41d4-a716-446655440001",
"hook_type": "pre_tool_use",
"endpoint_url": "https://api.example.com/hooks/pre-tool",
"enabled": true,
"timeout_ms": 5000,
"fail_behavior": "fail_closed",
"tools_allowlist": ["search_inventory"],
"allow_mutation": false,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
]
}
Create Tool Hook
POST /api/v1/projects/:id/tool-hooks
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
hook_type |
string | Yes | pre_tool_use, post_tool_use, tool_execute |
endpoint_url |
string | Yes | HTTPS URL to receive hook requests |
enabled |
boolean | No | Whether the hook is active (default: true) |
timeout_ms |
integer | No | Timeout in milliseconds (default: 5000) |
fail_behavior |
string | No | fail_closed or fail_open |
tools_allowlist |
array | No | Required for tool_execute hooks |
allow_mutation |
boolean | No | Only valid for post_tool_use |
Example
curl -X POST https://api.modelrelay.ai/api/v1/projects/550e8400-e29b-41d4-a716-446655440001/tool-hooks \
-H "Authorization: Bearer <session_token>" \
-H "Content-Type: application/json" \
-d '{
"hook_type": "tool_execute",
"endpoint_url": "https://api.example.com/hooks/execute",
"tools_allowlist": ["search_inventory"],
"timeout_ms": 5000,
"fail_behavior": "fail_closed"
}'
Response
{
"hook": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"project_id": "550e8400-e29b-41d4-a716-446655440001",
"hook_type": "tool_execute",
"endpoint_url": "https://api.example.com/hooks/execute",
"enabled": true,
"timeout_ms": 5000,
"fail_behavior": "fail_closed",
"tools_allowlist": ["search_inventory"],
"allow_mutation": false,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"signing_secret": "thsec_abc123def456..."
}
Get Tool Hook
GET /api/v1/projects/:id/tool-hooks/:hook_id
Returns a single tool hook configuration.
Update Tool Hook
PUT /api/v1/projects/:id/tool-hooks/:hook_id
Use rotate_secret to generate a new signing secret. The response includes signing_secret only when rotation occurs.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
endpoint_url |
string | No | HTTPS URL to receive hook requests |
enabled |
boolean | No | Whether the hook is active |
timeout_ms |
integer | No | Timeout in milliseconds |
fail_behavior |
string | No | fail_closed or fail_open |
tools_allowlist |
array | No | Restrict to tool names |
allow_mutation |
boolean | No | Only valid for post_tool_use |
rotate_secret |
boolean | No | Issue a new signing secret |
Delete Tool Hook
DELETE /api/v1/projects/:id/tool-hooks/:hook_id
Deletes the tool hook configuration.
Test Tool Hook
POST /api/v1/projects/:id/tool-hooks/:hook_id/test
Sends a test payload to the hook endpoint and records the delivery result.
Response
{
"status": "success",
"response_status": 200,
"response_body": "{\"action\":\"allow\"}",
"latency_ms": 120,
"error": null
}
List Tool Hook Events
GET /api/v1/projects/:id/tool-hooks/:hook_id/events?limit=100
Response
{
"events": [
{
"id": "550e8400-e29b-41d4-a716-446655440100",
"hook_config_id": "550e8400-e29b-41d4-a716-446655440000",
"request_id": "req_abc123",
"tool_call_id": "call_789",
"status": "success",
"response_status": 200,
"response_body": "{\"action\":\"allow\"}",
"latency_ms": 120,
"error": null,
"created_at": "2024-01-15T10:30:01Z"
}
]
}
Error Responses
400 Bad Request
Returned when the request body is invalid.
{
"error": "endpoint_url must use https"
}
Common validation errors:
hook_type required- missing or invalid hook typeendpoint_url required- missing endpoint URLendpoint_url must be a valid URL- malformed URLendpoint_url must use https- HTTP not allowedtools_allowlist required for tool_execute hooks- tool_execute requires allowlistallow_mutation is only valid for post_tool_use hooks- wrong hook type for mutation
401 Unauthorized
Returned when authentication fails.
{
"error": "unauthorized"
}
404 Not Found
Returned when the project or hook doesn’t exist.
{
"error": "tool hook not found"
}
500 Internal Server Error
Returned when an unexpected error occurs.
{
"error": "internal server error"
}
Execution Order
When multiple hooks of the same type are configured, they execute in order of created_at (oldest first). If any hook returns block, subsequent hooks of the same type are skipped.
Replay Attack Protection
Important: Validate the X-ModelRelay-Timestamp header to prevent replay attacks. Reject requests where the timestamp differs from the current time by more than 5 minutes. See the Tool Hooks Guide for implementation examples