Skip to main content

Custom Tools

Custom tools let you extend your agents with any capability your system can expose over HTTP. When the agent decides it needs to call your tool, Truedy sends a POST (or GET) request to your endpoint, your server responds with JSON, and the agent uses that data to continue the conversation. Build a custom tool when you need to:
  • Look up a customer account by phone number or email
  • Check order status, shipping information, or account balance
  • Verify identity or eligibility
  • Create a support ticket, send a notification, or trigger any internal workflow
  • Do anything not covered by the built-in integrations

Tool definition fields

Every tool is created with a name and a definition object. The definition describes your endpoint and its parameters. Top-level request body:
FieldTypeDescription
namestringHuman-readable display name (e.g. "Look Up Customer"). Used in the dashboard.
definitionobjectFull tool specification — see below.
definition fields:
FieldTypeDescription
descriptionstringPlain-English description of what the tool does and when to call it. This is what the AI reads to decide whether to invoke the tool.
http.baseUrlPatternstringYour HTTPS endpoint URL, e.g. "https://api.example.com/lookup".
http.httpMethodstringHTTP method: "POST", "GET", "PUT", "PATCH", or "DELETE". Use POST for operations that send parameters in the body.
dynamicParametersarrayParameters the AI extracts from the conversation and sends with each call.
staticParametersarrayFixed parameters always sent (e.g. an auth header). The AI never changes these.
dynamicParameters / staticParameters item shape:
FieldTypeDescription
namestringParameter name
locationstringWhere to put it: "PARAMETER_LOCATION_BODY", "PARAMETER_LOCATION_QUERY", or "PARAMETER_LOCATION_HEADER"
schemaobjectJSON Schema for the parameter (for dynamicParameters)
valuestringFixed value (for staticParameters only)
requiredbooleanWhether this parameter is required
Never embed API keys or secrets in http.baseUrlPattern as query parameters. Use a staticParameters entry with location: "PARAMETER_LOCATION_HEADER" instead, so credentials are not logged in request URLs.

Full workflow

1

Build your webhook endpoint

Create an HTTPS endpoint on your server that accepts POST requests and returns JSON. See the example implementations below.
2

Define the tool in Truedy

Create the tool in the dashboard (Tools → New Tool → Custom HTTP) or via the API. Provide the name, description, URL, method, and parameters schema.
3

Attach the tool to an agent

Go to your agent’s Tools tab and enable the custom tool, or use the PATCH /agents/{id} endpoint.
4

Test with a live call

Use the dashboard’s Test Agent panel to start a test call. Trigger the tool by speaking the scenario it is designed for, and verify your endpoint receives the request and the agent responds correctly.

Example tool definition

This tool looks up a customer’s account status by phone number:
{
  "name": "Look Up Customer",
  "definition": {
    "description": "Look up a customer's account status and last order by their phone number. Call this tool when the caller asks about their account, order history, or current status, and you have their phone number.",
    "http": {
      "baseUrlPattern": "https://your-server.com/truedy-tools/lookup",
      "httpMethod": "POST"
    },
    "dynamicParameters": [
      {
        "name": "phone_number",
        "location": "PARAMETER_LOCATION_BODY",
        "schema": {
          "type": "string",
          "description": "Customer's phone number in E.164 format, e.g. +14155551234"
        },
        "required": true
      },
      {
        "name": "lookup_type",
        "location": "PARAMETER_LOCATION_BODY",
        "schema": {
          "type": "string",
          "enum": ["account", "orders"],
          "description": "What to look up — account details or order history"
        }
      }
    ],
    "staticParameters": [
      {
        "name": "x-truedy-secret",
        "location": "PARAMETER_LOCATION_HEADER",
        "value": "your-shared-secret"
      }
    ]
  }
}

Webhook endpoint examples

const express = require('express');
const app = express();
app.use(express.json());

app.post('/truedy-tools/lookup', (req, res) => {
  // Validate the Truedy shared secret
  const secret = req.headers['x-truedy-secret'];
  if (secret !== process.env.TRUEDY_TOOL_SECRET) {
    return res.status(401).json({ success: false, error: 'Unauthorized' });
  }

  const { phone_number, lookup_type = 'account' } = req.body;

  if (!phone_number) {
    return res.status(400).json({ success: false, error: 'phone_number is required' });
  }

  // Your database or API call here
  const customer = db.findByPhone(phone_number);

  if (!customer) {
    return res.json({
      success: true,
      data: { found: false, message: 'No account found for this number' }
    });
  }

  return res.json({
    success: true,
    data: {
      found: true,
      name: customer.name,
      account_status: customer.status,
      last_order: lookup_type === 'orders' ? customer.lastOrder : undefined
    }
  });
});

app.listen(3000);

Create the tool via API

curl -X POST https://api.truedy.ai/api/public/v1/tools \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Look Up Customer",
    "definition": {
      "description": "Look up a customer account by phone number. Call when the caller asks about their account status or orders.",
      "http": {
        "baseUrlPattern": "https://your-server.com/truedy-tools/lookup",
        "httpMethod": "POST"
      },
      "dynamicParameters": [
        {
          "name": "phone_number",
          "location": "PARAMETER_LOCATION_BODY",
          "schema": { "type": "string", "description": "Caller phone number" },
          "required": true
        },
        {
          "name": "lookup_type",
          "location": "PARAMETER_LOCATION_BODY",
          "schema": { "type": "string", "enum": ["account", "orders"] }
        }
      ],
      "staticParameters": [
        {
          "name": "x-truedy-secret",
          "location": "PARAMETER_LOCATION_HEADER",
          "value": "YOUR_SHARED_SECRET"
        }
      ]
    }
  }'

Attach to an agent

Once the tool is created, attach it to an agent:
curl -X PATCH https://api.truedy.ai/api/public/v1/agents/{agent_id} \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tools": ["TOOL_ID"]
  }'
The tools array replaces the agent’s current tool list. To add a tool without removing existing ones, fetch the agent’s current tools first and include all IDs in the array.

Tool response format

Return JSON from your endpoint. The agent reads the entire response body, so structure it to be clear and self-explanatory. Recommended response structure:
{
  "success": true,
  "data": {
    "name": "Jane Smith",
    "account_status": "active",
    "outstanding_balance": 0,
    "last_order": "Order #4821 — delivered 3 days ago"
  }
}
For errors:
{
  "success": false,
  "error": "Customer not found"
}
Use human-readable strings for values the agent will speak aloud. Instead of "account_status": 2, use "account_status": "active". The agent reads what you return — make it easy to say.

Timeout handling

Tools must respond within 5 seconds. If your backend operation takes longer (e.g. a slow third-party API), use a queued pattern:
  1. Acknowledge the request immediately with a pending response
  2. Return a message the agent can relay to the caller
  3. Trigger the slow operation asynchronously
{
  "success": true,
  "data": {
    "status": "pending",
    "message": "Your request is being processed. We will send you a confirmation email within 5 minutes."
  }
}
Then instruct the agent in the prompt:
If the tool returns a status of "pending", tell the caller exactly what the
message field says and offer to answer any other questions while they wait.

Security: validating Truedy requests

Use a shared secret to verify that requests to your endpoint genuinely come from Truedy. In your tool definition, add a secret as a static header parameter:
{
  "staticParameters": [
    {
      "name": "x-truedy-secret",
      "location": "PARAMETER_LOCATION_HEADER",
      "value": "a-long-random-string-you-generate"
    }
  ]
}
In your endpoint, validate the header on every request before processing:
const secret = req.headers['x-truedy-secret'];
if (!secret || secret !== process.env.TRUEDY_TOOL_SECRET) {
  return res.status(401).json({ success: false, error: 'Unauthorized' });
}
Store the shared secret in an environment variable, never hardcoded in source code. Rotate it immediately if it is ever exposed.

Prompt engineering for custom tools

The description field is the single most important part of your tool definition. It is what the AI model reads to decide whether and when to call the tool. Poor description (too vague):
Looks up customer data.
Good description (precise and contextual):
Look up a customer's account status and most recent order by their phone number.
Call this tool when the caller mentions their account, asks about an order,
or wants to know their current balance. Only call this once per conversation
unless the caller provides a different phone number.
Rules for effective descriptions:
  • State what the tool returns, not just what it is
  • State when to call it (the trigger condition)
  • State any constraints (call once, require a phone number first, etc.)
  • Avoid ambiguity — the model takes descriptions literally

Next steps

Built-in Tools

Use Cal.com, GoHighLevel, or Calendly without writing any code

Tools Overview

Understand the full tool execution model