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 for pre_tool_use and tool_execute) stops the request when the hook fails.
  • fail_open (default for post_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 with error.
  • modify: replace the tool call (pre/tool_execute) or result (post).
  • result: for tool_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 type
  • endpoint_url required - missing endpoint URL
  • endpoint_url must be a valid URL - malformed URL
  • endpoint_url must use https - HTTP not allowed
  • tools_allowlist required for tool_execute hooks - tool_execute requires allowlist
  • allow_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