curl --request POST \
--url https://api.waterr.ai/v1/custom-functions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"name": "lookup_account",
"description": "Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.",
"parameters_schema": {
"type": "object",
"properties": {
"account_id": {
"type": "string",
"description": "The participant's account ID (e.g. cus_XXXX)."
}
},
"required": [
"account_id"
]
},
"execution_mode": "webhook",
"webhook_url": "https://your-app.com/waterr/tools/lookup_account",
"webhook_secret": "whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c",
"timeout_ms": 8000
}
EOFimport requests
url = "https://api.waterr.ai/v1/custom-functions"
payload = {
"name": "lookup_account",
"description": "Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.",
"parameters_schema": {
"type": "object",
"properties": { "account_id": {
"type": "string",
"description": "The participant's account ID (e.g. cus_XXXX)."
} },
"required": ["account_id"]
},
"execution_mode": "webhook",
"webhook_url": "https://your-app.com/waterr/tools/lookup_account",
"webhook_secret": "whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c",
"timeout_ms": 8000
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'lookup_account',
description: 'Fetch the participant\'s CRM record so you can reference their plan, MRR, and last contact date.',
parameters_schema: {
type: 'object',
properties: {
account_id: {type: 'string', description: 'The participant\'s account ID (e.g. cus_XXXX).'}
},
required: ['account_id']
},
execution_mode: 'webhook',
webhook_url: 'https://your-app.com/waterr/tools/lookup_account',
webhook_secret: 'whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c',
timeout_ms: 8000
})
};
fetch('https://api.waterr.ai/v1/custom-functions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.waterr.ai/v1/custom-functions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'lookup_account',
'description' => 'Fetch the participant\'s CRM record so you can reference their plan, MRR, and last contact date.',
'parameters_schema' => [
'type' => 'object',
'properties' => [
'account_id' => [
'type' => 'string',
'description' => 'The participant\'s account ID (e.g. cus_XXXX).'
]
],
'required' => [
'account_id'
]
],
'execution_mode' => 'webhook',
'webhook_url' => 'https://your-app.com/waterr/tools/lookup_account',
'webhook_secret' => 'whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c',
'timeout_ms' => 8000
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.waterr.ai/v1/custom-functions"
payload := strings.NewReader("{\n \"name\": \"lookup_account\",\n \"description\": \"Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.\",\n \"parameters_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"account_id\": {\n \"type\": \"string\",\n \"description\": \"The participant's account ID (e.g. cus_XXXX).\"\n }\n },\n \"required\": [\n \"account_id\"\n ]\n },\n \"execution_mode\": \"webhook\",\n \"webhook_url\": \"https://your-app.com/waterr/tools/lookup_account\",\n \"webhook_secret\": \"whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c\",\n \"timeout_ms\": 8000\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.waterr.ai/v1/custom-functions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"lookup_account\",\n \"description\": \"Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.\",\n \"parameters_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"account_id\": {\n \"type\": \"string\",\n \"description\": \"The participant's account ID (e.g. cus_XXXX).\"\n }\n },\n \"required\": [\n \"account_id\"\n ]\n },\n \"execution_mode\": \"webhook\",\n \"webhook_url\": \"https://your-app.com/waterr/tools/lookup_account\",\n \"webhook_secret\": \"whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c\",\n \"timeout_ms\": 8000\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.waterr.ai/v1/custom-functions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"lookup_account\",\n \"description\": \"Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.\",\n \"parameters_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"account_id\": {\n \"type\": \"string\",\n \"description\": \"The participant's account ID (e.g. cus_XXXX).\"\n }\n },\n \"required\": [\n \"account_id\"\n ]\n },\n \"execution_mode\": \"webhook\",\n \"webhook_url\": \"https://your-app.com/waterr/tools/lookup_account\",\n \"webhook_secret\": \"whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c\",\n \"timeout_ms\": 8000\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "4f8a6c50-9d3b-4c1f-9c0a-7a3b6e2d1f10",
"membership_id": "a1b2c3d4-e5f6-7890-abcd-ef0123456789",
"name": "lookup_account",
"description": "Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.",
"parameters_schema": {
"type": "object",
"properties": {
"account_id": {
"type": "string"
}
},
"required": [
"account_id"
]
},
"execution_mode": "webhook",
"webhook_url": "https://your-app.com/waterr/tools/lookup_account",
"has_webhook_secret": true,
"timeout_ms": 8000,
"tool_spec": {
"type": "function",
"function": {
"name": "lookup_account",
"description": "Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.",
"parameters": {
"type": "object",
"properties": {
"account_id": {
"type": "string"
}
},
"required": [
"account_id"
]
}
}
},
"created_at": "2026-06-18T12:34:56.000Z",
"updated_at": "2026-06-18T12:34:56.000Z"
}
}{
"message": "Invalid payload",
"errors": [
"name must be a string matching ^[a-zA-Z0-9_-]{1,64}$ (OpenAI tool-name rule)",
"webhook_url is required when execution_mode='webhook' (the default)"
]
}{
"message": "A custom function with that name already exists on this account"
}Create a tool definition
Register a tool on your account. Define once, then attach to any number of scenarios with Attach a tool to a scenario. Editing the definition later (Update a tool) propagates to every attached scenario instantly.
curl --request POST \
--url https://api.waterr.ai/v1/custom-functions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"name": "lookup_account",
"description": "Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.",
"parameters_schema": {
"type": "object",
"properties": {
"account_id": {
"type": "string",
"description": "The participant's account ID (e.g. cus_XXXX)."
}
},
"required": [
"account_id"
]
},
"execution_mode": "webhook",
"webhook_url": "https://your-app.com/waterr/tools/lookup_account",
"webhook_secret": "whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c",
"timeout_ms": 8000
}
EOFimport requests
url = "https://api.waterr.ai/v1/custom-functions"
payload = {
"name": "lookup_account",
"description": "Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.",
"parameters_schema": {
"type": "object",
"properties": { "account_id": {
"type": "string",
"description": "The participant's account ID (e.g. cus_XXXX)."
} },
"required": ["account_id"]
},
"execution_mode": "webhook",
"webhook_url": "https://your-app.com/waterr/tools/lookup_account",
"webhook_secret": "whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c",
"timeout_ms": 8000
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'lookup_account',
description: 'Fetch the participant\'s CRM record so you can reference their plan, MRR, and last contact date.',
parameters_schema: {
type: 'object',
properties: {
account_id: {type: 'string', description: 'The participant\'s account ID (e.g. cus_XXXX).'}
},
required: ['account_id']
},
execution_mode: 'webhook',
webhook_url: 'https://your-app.com/waterr/tools/lookup_account',
webhook_secret: 'whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c',
timeout_ms: 8000
})
};
fetch('https://api.waterr.ai/v1/custom-functions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.waterr.ai/v1/custom-functions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'lookup_account',
'description' => 'Fetch the participant\'s CRM record so you can reference their plan, MRR, and last contact date.',
'parameters_schema' => [
'type' => 'object',
'properties' => [
'account_id' => [
'type' => 'string',
'description' => 'The participant\'s account ID (e.g. cus_XXXX).'
]
],
'required' => [
'account_id'
]
],
'execution_mode' => 'webhook',
'webhook_url' => 'https://your-app.com/waterr/tools/lookup_account',
'webhook_secret' => 'whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c',
'timeout_ms' => 8000
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.waterr.ai/v1/custom-functions"
payload := strings.NewReader("{\n \"name\": \"lookup_account\",\n \"description\": \"Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.\",\n \"parameters_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"account_id\": {\n \"type\": \"string\",\n \"description\": \"The participant's account ID (e.g. cus_XXXX).\"\n }\n },\n \"required\": [\n \"account_id\"\n ]\n },\n \"execution_mode\": \"webhook\",\n \"webhook_url\": \"https://your-app.com/waterr/tools/lookup_account\",\n \"webhook_secret\": \"whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c\",\n \"timeout_ms\": 8000\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.waterr.ai/v1/custom-functions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"lookup_account\",\n \"description\": \"Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.\",\n \"parameters_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"account_id\": {\n \"type\": \"string\",\n \"description\": \"The participant's account ID (e.g. cus_XXXX).\"\n }\n },\n \"required\": [\n \"account_id\"\n ]\n },\n \"execution_mode\": \"webhook\",\n \"webhook_url\": \"https://your-app.com/waterr/tools/lookup_account\",\n \"webhook_secret\": \"whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c\",\n \"timeout_ms\": 8000\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.waterr.ai/v1/custom-functions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"lookup_account\",\n \"description\": \"Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.\",\n \"parameters_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"account_id\": {\n \"type\": \"string\",\n \"description\": \"The participant's account ID (e.g. cus_XXXX).\"\n }\n },\n \"required\": [\n \"account_id\"\n ]\n },\n \"execution_mode\": \"webhook\",\n \"webhook_url\": \"https://your-app.com/waterr/tools/lookup_account\",\n \"webhook_secret\": \"whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c\",\n \"timeout_ms\": 8000\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "4f8a6c50-9d3b-4c1f-9c0a-7a3b6e2d1f10",
"membership_id": "a1b2c3d4-e5f6-7890-abcd-ef0123456789",
"name": "lookup_account",
"description": "Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.",
"parameters_schema": {
"type": "object",
"properties": {
"account_id": {
"type": "string"
}
},
"required": [
"account_id"
]
},
"execution_mode": "webhook",
"webhook_url": "https://your-app.com/waterr/tools/lookup_account",
"has_webhook_secret": true,
"timeout_ms": 8000,
"tool_spec": {
"type": "function",
"function": {
"name": "lookup_account",
"description": "Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date.",
"parameters": {
"type": "object",
"properties": {
"account_id": {
"type": "string"
}
},
"required": [
"account_id"
]
}
}
},
"created_at": "2026-06-18T12:34:56.000Z",
"updated_at": "2026-06-18T12:34:56.000Z"
}
}{
"message": "Invalid payload",
"errors": [
"name must be a string matching ^[a-zA-Z0-9_-]{1,64}$ (OpenAI tool-name rule)",
"webhook_url is required when execution_mode='webhook' (the default)"
]
}{
"message": "A custom function with that name already exists on this account"
}Authorizations
API key from waterr.ai/settings?tab=api-keys. Send as Authorization: Bearer wai_<your_key>.
Body
Function name the LLM calls. Letters, digits, _, -. Max 64. Unique per account.
64^[a-zA-Z0-9_-]{1,64}$"lookup_account"
One-sentence prompt the LLM reads to decide when to call this tool.
"Fetch the participant's CRM record so you can reference their plan, MRR, and last contact date."
JSON Schema for the arguments. Top-level type must be "object".
{
"type": "object",
"properties": {
"account_id": {
"type": "string",
"description": "The participant's account ID (e.g. cus_XXXX)."
}
},
"required": ["account_id"]
}
webhook — we POST the call to webhook_url. client — your frontend handles it.
webhook, client "webhook"
HTTP(S) endpoint for tool calls. Required when execution_mode = "webhook".
"https://your-app.com/waterr/tools/lookup_account"
HMAC-SHA256 secret. Signs every webhook request as X-Waterr-Signature: sha256=<hex>. Never returned after creation.
"whsec_8f2c9e7b5d4a3e1c2f5d8b6e9a4c7f1e3b6d8a2c5e7f9b1d4a6c8e2f5b7d9a3c"
Webhook response timeout in ms. Range 1000–30000.
1000 <= x <= 300008000
What the persona does while the tool runs. See Conversational modes.
generate_filler, static_filler, silent, passthrough "static_filler"
Phrase to speak during the tool call. Required when on_call = "static_filler", forbidden otherwise.
"Sure, let me grab that for you."
What to do with the result after the tool returns.
generate_response, response_in_result, add_to_context, fire_and_forget "generate_response"
Response
Tool created.
A tool the LLM can call mid-meeting. Defined once on your account, attached to one or more scenarios.
Show child attributes
Show child attributes

