Update tool
https://app.sulus.ai/api/tools/{id}
Publish changes — creates or patches the live tool, sets status published
Authentication
Send a bearer token created on your dashboard's Developer page:
Authorization: Bearer <YOUR_API_KEY>
Path parameters
id
string
Required
The tool's public id.
the tool's external_tool_id (UUID, or draft_… slug for drafts)tools.external_tool_idRequest body
name
string
Required
Tool display name.
required|string|max:100tools.nametype
string
Required
Tool-type discriminator. Fixed at creation — cannot be changed on update.
required|string|in:apiRequest,function,transferCall,endCall,dtmf,voicemail,handoff,query,mcptools.typeuser_id
integer
Optional
Nullable
Owner assignment — honoured only for admin roles.
nullable|integer|exists:users,idtools.user_idreseller_id
string
Optional
Nullable
Reseller assignment — honoured only for super admins.
nullable|uuid|exists:resellers,idtools.reseller_idisGlobal
boolean
Optional
Nullable
Marks the tool a platform Global Tool (no owner). Super-admin only; clears user_id.
nullable|booleanfunctionName
string
Optional
Nullable
The callable name the model uses to invoke the tool. Falls back to a slug of name when omitted.
nullable|string|max:64|regex:/^[a-zA-Z0-9_-]+$/tools.function_defdescription
string
Optional
Nullable
Top-level tool description (apiRequest). Function tools keep their description inside function_def.
nullable|string|max:2000tools.descriptionparameters
array
Optional
Nullable
Function/handoff parameter schema-builder rows: {name, type, description, required, enum}.
nullable|arraytools.function_defparametersLockSchema
boolean
Optional
Nullable
Locks the parameters schema (additionalProperties:false).
nullable|booleantools.function_defstrict
boolean
Optional
Nullable
Enforce exact schema adherence on the tool call (function tools).
nullable|booleantools.function_defserver
object
Optional
Nullable
Request configuration (apiRequest) / webhook target (function). See Fields page.
nullable|arraytools.serverserver.url
string
Optional
Nullable
nullable|url|max:2000tools.serverserver.method
string
Optional
Nullable
nullable|string|in:GET,POST,PUT,PATCH,DELETEtools.serverserver.timeoutSeconds
integer
Optional
Nullable
nullable|integer|min:1|max:300tools.serverserver.headers
array
Optional
Nullable
Rows of {key, value}.
nullable|arraytools.serverserver.bodyProperties
array
Optional
Nullable
Recursive request-body schema tree — validated as a whole array (see Fields page).
nullable|arraytools.serverserver.staticFields
array
Optional
Nullable
Rows of {key, type, value} merged into the request body as typed literals.
nullable|arraytools.serverserver.lockSchema
boolean
Optional
Nullable
nullable|booleantools.serverserver.encryptedFields
array
Optional
Nullable
Header/body field names whose values are stored encrypted.
nullable|arraytools.serverserver.encryptedFields.*
string
Optional
string|max:200tools.serverserver.backoffPlan
object
Optional
Nullable
Retry policy for failed requests.
nullable|arraytools.serverserver.backoffPlan.type
string
Optional
Nullable
nullable|string|in:fixed,exponentialtools.serverserver.backoffPlan.maxRetries
integer
Optional
Nullable
nullable|integer|min:0|max:10tools.serverserver.backoffPlan.baseDelaySeconds
integer
Optional
Nullable
nullable|integer|min:0|max:300tools.serverserver.backoffPlan.excludedStatusCodes
array
Optional
Nullable
nullable|arraytools.serverserver.backoffPlan.excludedStatusCodes.*
integer
Optional
integer|min:100|max:599tools.serverserver.credentialId
string
Optional
Nullable
A personal credential's id (see Credentials group) used to authenticate the outbound request.
nullable|string|max:100tools.serverserver.staticIpAddressesEnabled
boolean
Optional
Nullable
nullable|booleantools.serverserver.serverEncryptedPaths
array
Optional
Nullable
nullable|arraytools.serverserver.serverEncryptedPaths.*
string
Optional
string|max:200tools.serverserver.sipInfoDtmfEnabled
boolean
Optional
Nullable
dtmf tools only.
nullable|booleantools.serverserver.beepDetectionEnabled
boolean
Optional
Nullable
voicemail tools only — wait for the answering-machine beep.
nullable|booleantools.serverserver.protocol
string
Optional
Nullable
mcp tools only — transport: shttp (Streamable HTTP, default) or sse (legacy). Sent to the voice platform as metadata.protocol.
nullable|string|in:shttp,ssetools.servervariableExtractionPlan
object
Optional
Nullable
Extracts variables from the API response (apiRequest). See Fields page.
nullable|arraytools.variable_extraction_planvariableExtractionPlan.properties
array
Optional
Nullable
Schema rows: {name, type, description, required, enum}.
nullable|arraytools.variable_extraction_planvariableExtractionPlan.aliases
array
Optional
Nullable
Rows of {key, value}.
nullable|arraytools.variable_extraction_plandestinations
array
Optional
Nullable
Transfer/handoff targets (transferCall, handoff). See Fields page.
nullable|arraytools.destinationsdestinations.*.type
string
Optional
Nullable
nullable|string|in:number,sip,assistant,dynamic,squadtools.destinationsdestinations.*.server
object
Optional
Nullable
Handoff dynamic-destination server config.
nullable|arraytools.destinationsdestinations.*.server.url
string
Optional
Nullable
nullable|url|max:2000tools.destinationsdestinations.*.server.timeoutSeconds
integer
Optional
Nullable
nullable|integer|min:1|max:300tools.destinationsdestinations.*.server.headers
array
Optional
Nullable
nullable|arraytools.destinationsdestinations.*.squadId
string
Optional
Nullable
Handoff squad-destination reference.
nullable|string|max:100tools.destinationsdestinations.*.entryAssistantName
string
Optional
Nullable
nullable|string|max:255tools.destinationsdestinations.*.number
string
Optional
Nullable
nullable|string|max:50tools.destinationsdestinations.*.extension
string
Optional
Nullable
nullable|string|max:20tools.destinationsdestinations.*.callerId
string
Optional
Nullable
nullable|string|max:50tools.destinationsdestinations.*.sipUri
string
Optional
Nullable
nullable|string|max:255tools.destinationsdestinations.*.assistantId
string
Optional
Nullable
nullable|string|max:100tools.destinationsdestinations.*.assistantName
string
Optional
Nullable
nullable|string|max:255tools.destinationsdestinations.*.transferMode
string
Optional
Nullable
nullable|string|in:rolling-history,swap-system-message-in-history,swap-system-message-in-history-and-remove-transfer-tool-messages,delete-historytools.destinationsdestinations.*.message
string
Optional
Nullable
nullable|string|max:1000tools.destinationsdestinations.*.description
string
Optional
Nullable
nullable|string|max:2000tools.destinationsdestinations.*.numberE164CheckEnabled
boolean
Optional
Nullable
nullable|booleantools.destinationsdestinations.*.sipHeaders
array
Optional
Nullable
Rows of {key, value}.
nullable|arraytools.destinationsdestinations.*.contextEngineeringPlan
object
Optional
Nullable
Handoff destination context-carry strategy.
nullable|arraytools.destinationsdestinations.*.contextEngineeringPlan.type
string
Optional
Nullable
nullable|string|in:none,all,lastNMessages,userAndAssistantMessages,previousAssistantMessagestools.destinationsdestinations.*.contextEngineeringPlan.maxMessages
integer
Optional
Nullable
nullable|integer|min:1|max:1000tools.destinationsdestinations.*.transferPlan
object
Optional
Nullable
nullable|arraytools.destinationsdestinations.*.transferPlan.mode
string
Optional
Nullable
nullable|string|max:80tools.destinationsdestinations.*.transferPlan.message
string
Optional
Nullable
nullable|string|max:1000tools.destinationsdestinations.*.transferPlan.sipVerb
string
Optional
Nullable
nullable|string|in:refer,bye,dialtools.destinationsdestinations.*.transferPlan.timeout
integer
Optional
Nullable
nullable|integer|min:1|max:600tools.destinationsdestinations.*.transferPlan.dialTimeout
integer
Optional
Nullable
nullable|integer|min:1|max:600tools.destinationsdestinations.*.transferPlan.holdAudioUrl
string
Optional
Nullable
nullable|string|max:2000tools.destinationsdestinations.*.transferPlan.transferCompleteAudioUrl
string
Optional
Nullable
nullable|string|max:2000tools.destinationsdestinations.*.transferPlan.twiml
string
Optional
Nullable
Raw call-control markup for the transfer (sipVerb: dial).
nullable|string|max:4000tools.destinationsdestinations.*.transferPlan.sipHeadersInReferToEnabled
boolean
Optional
Nullable
nullable|booleantools.destinationstoolMessages
array
Optional
Nullable
mcp tools only — spoken-message overrides for individual tools on the MCP server. An empty messages list silences that tool.
nullable|arraytools.function_deftoolMessages.*.name
string
Required
The name of the tool on the MCP server.
required|string|max:64tools.function_deftoolMessages.*.messages
array
Optional
Nullable
Same message shape as messages.
nullable|arraytools.function_defknowledgeBases
array
Optional
Nullable
query tools — knowledge bases the assistant can search.
nullable|arraytools.function_defknowledgeBases.*.name
string
Optional
Nullable
nullable|string|max:255tools.function_defknowledgeBases.*.description
string
Optional
Nullable
nullable|string|max:2000tools.function_defknowledgeBases.*.provider
string
Optional
Nullable
nullable|string|in:googletools.function_defknowledgeBases.*.fileIds
array
Optional
Nullable
Array of file ids, or a comma-separated string.
nullabletools.function_defrejectionPlan
object
Optional
Nullable
Conditions under which the model's tool call is rejected. Supported by every tool type.
nullable|arraytools.rejection_planrejectionPlan.conditions
array
Optional
Nullable
nullable|arraytools.rejection_planrejectionPlan.conditions.*.type
string
Optional
Nullable
nullable|string|in:regex,liquidtools.rejection_planrejectionPlan.conditions.*.value
string
Optional
Nullable
nullable|string|max:2000tools.rejection_planmessages
array
Optional
Nullable
Lifecycle messages. See Fields page.
nullable|arraytools.messagesmessages.*.type
string
Required
required_with:messages|string|in:request-start,request-complete,request-failed,request-response-delayedtools.messagesmessages.*.mode
string
Optional
Nullable
request-start only.
nullable|string|in:default,none,customtools.messagesmessages.*.content
string
Optional
Nullable
nullable|string|max:1000tools.messagesmessages.*.blocking
boolean
Optional
Nullable
nullable|booleantools.messagesmessages.*.role
string
Optional
Nullable
nullable|string|in:assistant,systemtools.messagesmessages.*.endCallAfterSpokenEnabled
boolean
Optional
Nullable
nullable|booleantools.messagesmessages.*.timingMilliseconds
integer
Optional
Nullable
request-response-delayed only.
nullable|integer|min:100|max:120000tools.messagesmessages.*.contents
array
Optional
Nullable
Spoken-message variants — one is picked at random.
nullable|arraytools.messagesmessages.*.contents.*.type
string
Optional
Nullable
nullable|string|max:20tools.messagesmessages.*.contents.*.text
string
Optional
Nullable
nullable|string|max:1000tools.messagesmessages.*.contents.*.language
string
Optional
Nullable
nullable|string|max:20tools.messagesmessages.*.conditions
array
Optional
Nullable
Gating conditions for this message.
nullable|arraytools.messagesmessages.*.conditions.*.param
string
Optional
Nullable
nullable|string|max:200tools.messagesmessages.*.conditions.*.operator
string
Optional
Nullable
nullable|string|in:eq,neq,gt,gte,lt,ltetools.messagesmessages.*.conditions.*.value
string
Optional
Nullable
nullable|string|max:1000tools.messagesasync
boolean
Optional
Nullable
Run the tool call without blocking the conversation.
nullable|booleantools.asyncmetadata
object
Optional
Nullable
Arbitrary metadata.
nullable|arraytools.metadataErrors
| Status | Meaning | Body |
|---|---|---|
404 |
Tool not found, or outside your account scope | {"success":false,"message":"Tool not found"} |
403 |
Global tool mutation attempted by a non-super-admin | {"success":false,"message":"Global tools are read-only and cannot be edited or deleted."} |
422 |
Composition invalid for the live platform | {"success":false,"message":"Tool payload invalid: <detail>"} |
502 |
Live platform write failed | |
422 |
Validation failed | {"message":"…","errors":{"field":["…"]}} |
403 |
Workspace permission denied | |
401 |
Missing or invalid bearer token | |
403 |
Feature tools not enabled for the account |
Notes
- The type discriminator cannot be changed on an existing upstream tool — the update request is stripped of type before being sent live, though the field is still validated on input.
- coreData mirrors the live voice platform's own tool object; only its id is guaranteed to appear — the rest of its shape is internal and not part of the documented contract (see Overview).
curl --request PUT \
--url https://app.sulus.ai/api/tools/{id} \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"name": "Check Order Status",
"type": "apiRequest",
"description": "Looks up an order by ID and returns its current status, including estimated delivery date.",
"server": {
"url": "https://api.example-business.com/orders/lookup",
"method": "POST",
"timeoutSeconds": 25,
"headers": [{"key": "X-Api-Key", "value": "{{env.ORDERS_API_KEY}}"}],
"bodyProperties": [
{"name": "orderId", "type": "string", "description": "The order confirmation number", "required": true}
],
"credentialId": "3f9c2a10-6b4e-4a2d-9f0a-1c2d3e4f5a6b"
},
"variableExtractionPlan": {
"properties": [
{"name": "orderStatus", "type": "string", "description": "Current status of the order", "required": false},
{"name": "estimatedDelivery", "type": "string", "description": "Estimated delivery date", "required": false}
]
},
"messages": [
{"type": "request-start", "mode": "custom", "content": "Let me check on that order for you."}
],
"async": false,
"metadata": {"category": "orders"}
}'
import requests
url = "https://app.sulus.ai/api/tools/{id}"
headers = {"Authorization": "Bearer <YOUR_API_KEY>"}
payload = {
"name": "Check Order Status",
"type": "apiRequest",
"description": "Looks up an order by ID and returns its current status, including estimated delivery date.",
"server": {
"url": "https://api.example-business.com/orders/lookup",
"method": "POST",
"timeoutSeconds": 25,
"headers": [{"key": "X-Api-Key", "value": "{{env.ORDERS_API_KEY}}"}],
"bodyProperties": [
{"name": "orderId", "type": "string", "description": "The order confirmation number", "required": true}
],
"credentialId": "3f9c2a10-6b4e-4a2d-9f0a-1c2d3e4f5a6b"
},
"variableExtractionPlan": {
"properties": [
{"name": "orderStatus", "type": "string", "description": "Current status of the order", "required": false},
{"name": "estimatedDelivery", "type": "string", "description": "Estimated delivery date", "required": false}
]
},
"messages": [
{"type": "request-start", "mode": "custom", "content": "Let me check on that order for you."}
],
"async": false,
"metadata": {"category": "orders"}
}
response = requests.put(url, json=payload, headers=headers)
print(response.json())
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
url := "https://app.sulus.ai/api/tools/{id}"
payload := strings.NewReader(`{
"name": "Check Order Status",
"type": "apiRequest",
"description": "Looks up an order by ID and returns its current status, including estimated delivery date.",
"server": {
"url": "https://api.example-business.com/orders/lookup",
"method": "POST",
"timeoutSeconds": 25,
"headers": [{"key": "X-Api-Key", "value": "{{env.ORDERS_API_KEY}}"}],
"bodyProperties": [
{"name": "orderId", "type": "string", "description": "The order confirmation number", "required": true}
],
"credentialId": "3f9c2a10-6b4e-4a2d-9f0a-1c2d3e4f5a6b"
},
"variableExtractionPlan": {
"properties": [
{"name": "orderStatus", "type": "string", "description": "Current status of the order", "required": false},
{"name": "estimatedDelivery", "type": "string", "description": "Estimated delivery date", "required": false}
]
},
"messages": [
{"type": "request-start", "mode": "custom", "content": "Let me check on that order for you."}
],
"async": false,
"metadata": {"category": "orders"}
}`)
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <YOUR_API_KEY>")
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))
}
{
"success": true,
"data": {
"name": "Check Order Status",
"user_id": 42,
"external_tool_id": "d4e5f6a7-8b9c-4a1d-9e2f-3a4b5c6d7e8f",
"status": "published",
"created_by": 42,
"reseller_id": "f1e2d3c4-b5a6-4978-8901-234567890abc",
"workspace_id": "9a8b7c6d-5e4f-4a3b-9c8d-7e6f5a4b3c2d",
"type": "apiRequest",
"description": "Looks up an order by ID and returns its current status, including estimated delivery date.",
"function_def": {
"name": "check_order_status"
},
"server": {
"url": "https://api.example-business.com/orders/lookup",
"method": "POST",
"timeoutSeconds": 25,
"headers": [
{
"key": "X-Api-Key",
"value": "{{env.ORDERS_API_KEY}}"
}
],
"bodyProperties": [
{
"name": "orderId",
"type": "string",
"required": true,
"description": "The order confirmation number"
}
],
"credentialId": "3f9c2a10-6b4e-4a2d-9f0a-1c2d3e4f5a6b"
},
"variable_extraction_plan": {
"properties": [
{
"name": "orderStatus",
"type": "string",
"description": "Current status of the order",
"required": false
},
{
"name": "estimatedDelivery",
"type": "string",
"description": "Estimated delivery date",
"required": false
}
]
},
"destinations": null,
"rejection_plan": null,
"messages": [
{
"type": "request-start",
"content": "Let me check on that order for you."
}
],
"metadata": {
"category": "orders"
},
"async": false,
"created_at": "2026-06-01T14:22:03+00:00",
"updated_at": "2026-07-30T14:30:52+00:00",
"user": {
"id": 42,
"name": "Jane Cooper",
"email": "[email protected]"
},
"creator": {
"id": 42,
"name": "Jane Cooper",
"email": "[email protected]"
},
"read_only": false,
"coreData": {
"id": "d4e5f6a7-8b9c-4a1d-9e2f-3a4b5c6d7e8f"
}
}
}
/tools/{id}
200
{
"success": true,
"data": {
"name": "Check Order Status",
"user_id": 42,
"external_tool_id": "d4e5f6a7-8b9c-4a1d-9e2f-3a4b5c6d7e8f",
"status": "published",
"created_by": 42,
"reseller_id": "f1e2d3c4-b5a6-4978-8901-234567890abc",
"workspace_id": "9a8b7c6d-5e4f-4a3b-9c8d-7e6f5a4b3c2d",
"type": "apiRequest",
"description": "Looks up an order by ID and returns its current status, including estimated delivery date.",
"function_def": {
"name": "check_order_status"
},
"server": {
"url": "https://api.example-business.com/orders/lookup",
"method": "POST",
"timeoutSeconds": 25,
"headers": [
{
"key": "X-Api-Key",
"value": "{{env.ORDERS_API_KEY}}"
}
],
"bodyProperties": [
{
"name": "orderId",
"type": "string",
"required": true,
"description": "The order confirmation number"
}
],
"credentialId": "3f9c2a10-6b4e-4a2d-9f0a-1c2d3e4f5a6b"
},
"variable_extraction_plan": {
"properties": [
{
"name": "orderStatus",
"type": "string",
"description": "Current status of the order",
"required": false
},
{
"name": "estimatedDelivery",
"type": "string",
"description": "Estimated delivery date",
"required": false
}
]
},
"destinations": null,
"rejection_plan": null,
"messages": [
{
"type": "request-start",
"content": "Let me check on that order for you."
}
],
"metadata": {
"category": "orders"
},
"async": false,
"created_at": "2026-06-01T14:22:03+00:00",
"updated_at": "2026-07-30T14:30:52+00:00",
"user": {
"id": 42,
"name": "Jane Cooper",
"email": "[email protected]"
},
"creator": {
"id": 42,
"name": "Jane Cooper",
"email": "[email protected]"
},
"read_only": false,
"coreData": {
"id": "d4e5f6a7-8b9c-4a1d-9e2f-3a4b5c6d7e8f"
}
}
}