POSThttps://core-api.heysadie.ai/tools
name body instruction textInstructions serverUrl success data id tenantId hasTenantInstruction createdAt updatedAt metadata timestamp version path error code message details fieldCreate tool
Define a new assistant tool that can be executed through structured function-calling. Use this when: - You want the assistant to call an external API using structured logic - You want to define when, how, and what to send to a tool/function ### Fields - `name`: A friendly name for the tool (e.g., "GetMenu", "SubmitReservation") - `body`: The tool function definition, following the function-calling schema. This includes: - `name`: The function name (e.g., "getMenu") - `description`: A short explanation of what the function does - `parameters`: A JSON Schema object describing the expected parameters. Each parameter includes a name, type, and description. **Example:** ```json { "name": "getMenu", "description": "Fetches the current menu for a location", "parameters": { "type": "object", "properties": { "locationId": { "type": "string", "description": "Unique ID of the restaurant location" } }, "required": ["locationId"] } } ``` - `instruction`: A list of step-by-step instructions the assistant should follow before calling the tool. This lets you tightly control the assistant's behavior and validation. **Example:** ```json [ { "step": "check_requirements", "description": "Ensure the user has specified a location" }, { "step": "call_tool", "description": "Invoke the getMenu function with the locationId" }, { "step": "respond", "description": "Summarize the menu results back to the user" } ] ``` - `textInstructions` (optional): Instructions in the same shape as `instruction`, used instead of it when the assistant is in a text conversation (SMS, WhatsApp, webchat). Voice calls always use `instruction`. Leave it out or set it to `null` and text conversations use `instruction` too. Per-assistant step overrides for this version are set through the `text-override` endpoints. - `serverUrl`: The URL endpoint to which the assistant will send the final tool payload (e.g., "https://api.myapp.com/v1/tools/get-menu") This enables deep integration between the assistant's reasoning and your backend systems. ⚠️ All tools are tenant-scoped. Make sure each tool is specific to the use case of your assistant.
Try it in the API ExplorerExample request
curl -X POST "https://core-api.heysadie.ai/tools" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Transfer to contact",
"serverUrl": "https://your-directory-server.example.com/find-destination",
"body": {
"type": "dynamicTransfer",
"function": {
"name": "transferToContact",
"description": "Look up a person by name in the company directory and transfer the caller to them. Use whenever the caller asks to be connected or transferred to a specific person or department.",
"parameters": {
"type": "object",
"properties": {
"firstName": {
"type": "string",
"description": "First name of the contact the caller wants to reach"
}
},
"required": [
"firstName"
]
}
},
"defaultMode": "cold",
"messages": [
{
"type": "request-start",
"mode": "static",
"content": "One moment, connecting you now."
}
]
},
"instruction": {
"title": "Transfer caller to a named contact",
"description": "How to use transferToContact to connect the caller to the right person.",
"steps": [
{
"title": "Get the contact name",
"action": "Ask who the caller wants to reach and capture their first name.",
"wait_for_response": true
},
{
"title": "Look up and connect",
"action": "Call transferToContact with the first name. If several matches come back, read the options to the caller and ask which one, then call it again. If there's no match, tell the caller you couldn't find that person.",
"wait_for_response": false
}
]
}
}'Authentication
Authenticate with an API key in the Authorization header using the ApiKey scheme. See Authentication for how keys work and where to get them.
AuthorizationstringrequiredAPI key in the ApiKey scheme: ApiKey YOUR_API_KEY. Tenant keys authorize their own tenant; organization keys can act on any tenant in the organization.
X-Tenant-Idstring (uuid)optionalRequired when authenticating with an organization key: it selects the tenant the request acts on. Omit with tenant keys.
Request
Body application/json · required
nameanyoptionalFriendly name for the tool (e.g., 'CheckAvailability')
bodyanyoptionalThe full tool definition. `body.type` is `function`, `dynamicTransfer` or `sendDtmf`. For dynamicTransfer: { type, function, defaultMode?, messages? } (see docs/dynamic-transfer-tool.md). For sendDtmf (press dial-pad digits into the call, e.g. a door intercom's open code): { type, function, digits? | codes? } where `digits` is a single dial code and `codes` maps named codes to digits ({ front_door: '#235' }); one of the two is required, allowed characters 0-9 * #. sendDtmf tools have no server: serverUrl may be omitted.
instructionanyoptionalStructured steps or logic the assistant should follow before invoking the tool
textInstructionsanyoptionalOptional instructions used instead of `instruction` when the assistant is in a text conversation (SMS, WhatsApp, webchat). Same shape as `instruction`. Omit to leave the current value unchanged; send null to clear it, so text conversations use `instruction` again.
serverUrlanyoptionalThe URL endpoint to call when this tool is invoked
Responses
successbooleanrequiredtrue on every 2xx
dataobjectoptionalThe result
Show 10 child properties
idstringrequirednamestringrequiredbodyanyrequiredinstructionanyrequiredtextInstructionsanyoptionalserverUrlstring | nullrequiredtenantIdstring | nulloptionalhasTenantInstructionbooleanoptionalcreatedAtstring (date-time) | string (date) | number | nullrequiredupdatedAtstring (date-time) | string (date) | number | nullrequiredmetadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
400The request is invalid. `details` lists each field that failed
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 3 child properties
codeenumrequiredA parameter or body field broke a rule
"VALIDATION_ERROR"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
detailsobject[]optionalOne entry per field that failed
Show 2 item properties
fieldstringrequiredThe offending field
messagestringrequiredThe rule it broke
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
401Missing or invalid credentials
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredNo valid credentials
"UNAUTHORIZED"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
403The credentials are valid but may not use this route
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredThe credentials may not use this route
"FORBIDDEN"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
404Not found, or outside the caller's scope
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredAn id names nothing the caller can see
"RESOURCE_NOT_FOUND"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
500An unexpected server error
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredAn unexpected server failure
"INTERNAL_SERVER_ERROR"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested