TriLuna Try it free

webhook_tools

Webhook Tools Development Guide

This document covers creating and registering webhook tools for ElevenLabs integration.

Overview

CRITICAL: When creating new webhook tools, you must register them in BOTH:

  1. Database - Enables toggle in our UI (webhook_tools, agent_webhook_config)
  2. ElevenLabs - Makes tool available to agents during conversations

Common Mistake: Toggling a tool ON in our UI does NOT automatically add it to ElevenLabs. The agent won’t be able to use the tool until it’s registered in ElevenLabs workspace.


Two-Step Process

Step 1: Add Tool to Database

IMPORTANT: Always include elevenlabs_tool_id and organization_id so we know which ElevenLabs account the tool belongs to.

INSERT INTO webhook_tools (tool_name, elevenlabs_tool_id, organization_id, display_name, description, webhook_url, is_system_tool)
VALUES ('my_tool', 'tool_xxxxx', 2, 'My Tool', 'Description of what it does...', 'https://api.triluna.app/api/my-tool/webhook', 1);
ColumnDescription
elevenlabs_tool_idThe tool_xxx ID from ElevenLabs workspace (visible at https://elevenlabs.io/app/agents/tools)
organization_idOur org ID — determines which ElevenLabs API key to use (e.g., 7 = MyJava, 2 = TriLuna platform)

Step 2: Create ElevenLabs Registration Script

Check existing scripts for reference:

ls webapp/server/scripts/create-*-tool.js

Reference Scripts:

  • create-realtor-listings-tool.js - Pattern example
  • create-google-sheets-tool.js - Multi-tenant tool
  • create-email-tool.js - Email integration

Script Template

const axios = require('axios');
require('dotenv').config({ path: require('path').join(__dirname, '../.env') });

const ELEVENLABS_API_KEY = process.env.ELEVENLABS_API_KEY;

async function createMyTool() {
  const toolPayload = {
    tool_config: {
      type: "webhook",
      name: "my_tool_name",
      description: "What this tool does...",
      response_timeout_secs: 20,
      disable_interruptions: false,
      force_pre_tool_speech: false,
      assignments: [],
      api_schema: {
        url: "https://api.triluna.app/api/my-tool/webhook",
        method: "POST",
        path_params_schema: {},
        query_params_schema: null,
        request_body_schema: {
          type: "object",
          required: ["agent_id", "action"],
          properties: {
            agent_id: {
              type: "string",
              enum: null,
              dynamic_variable: "system__agent_id",
              constant_value: ""
            },
            conversation_id: {
              type: "string",
              enum: null,
              dynamic_variable: "system__conversation_id",
              constant_value: ""
            },
            action: {
              type: "string",
              description: "Action to perform",
              enum: ["action1", "action2"],
              dynamic_variable: "",
              constant_value: ""
            }
            // Add more parameters as needed
          }
        },
        request_headers: {
          "Content-Type": "application/json"
        },
        auth_connection: null
      },
      dynamic_variables: {
        dynamic_variable_placeholders: {}
      }
    }
  };

  try {
    const response = await axios.post(
      'https://api.elevenlabs.io/v1/convai/tools',
      toolPayload,
      {
        headers: {
          'xi-api-key': ELEVENLABS_API_KEY,
          'Content-Type': 'application/json'
        }
      }
    );
    console.log('Tool created:', response.data);
    return response.data;
  } catch (error) {
    if (error.response?.status === 409) {
      console.log('Tool already exists, fetching existing...');
      // Handle 409 conflict - tool already exists
    }
    throw error;
  }
}

createMyTool().catch(console.error);

Step 3: Run Script and Add to Agent

cd webapp/server/scripts
node create-my-tool.js

# Tool is now available at: https://elevenlabs.io/app/agents/tools
# Add it to specific agents through ElevenLabs UI

Schema Requirements

RequirementDetails
Wrap in tool_configRoot object must be { tool_config: { ... } }
Dynamic variablesProperties with dynamic_variable cannot have description
System variablesUse system__agent_id and system__conversation_id
force_pre_tool_speechMust be boolean (not “auto”)
Handle 409Tool may already exist - fetch existing tool info

Critical Database Schema

IMPORTANT: When querying elevenlabs_agents for user/owner information:

// WRONG - These columns DO NOT EXIST
SELECT user_id, owner_user_id FROM elevenlabs_agents WHERE agent_id = ?

// CORRECT - Use primary_owner_id
SELECT primary_owner_id FROM elevenlabs_agents WHERE agent_id = ?
const userId = agents[0].primary_owner_id;

Common Pattern for Webhook Tools:

// Get agent owner
const [agents] = await database.query(
  'SELECT agent_id, primary_owner_id FROM elevenlabs_agents WHERE agent_id = ?',
  [params.agent_id]
);

if (agents.length === 0) {
  return res.status(404).json({ error: 'Agent not found' });
}

const userId = agents[0].primary_owner_id;

// Now use userId for user-specific queries
const credentials = await getCredentials(userId, params.agent_id);

Debugging Webhook Tools

Agent can’t use the tool during conversation:

  1. Check if tool exists in ElevenLabs: https://elevenlabs.io/app/agents/tools
  2. Check if tool is added to the specific agent
  3. Check webhook logs table for errors:
SELECT id, agent_id, email_action, status, error_message, created_at
FROM webhook_logs
WHERE agent_id = 'agent_xxx'
ORDER BY created_at DESC
LIMIT 10;

Common Issues:

IssueCauseSolution
Agent can’t access toolTool toggled ON in UI but not registered in ElevenLabsRun registration script
Tool not availableTool registered but not added to agentAdd via ElevenLabs UI
404 errorsRoute not definedCheck server routes, restart server
”Unknown column” errorsUsing wrong column nameUse primary_owner_id not user_id

Last Updated: 2026-01-14