atteq API
  • Guides
  • Recipes
  • Cookbook
  • API Reference
Information
agents
    List AgentsgetCreate AgentpostDocument AttachmentsgetGet VersiongetEdit DraftpatchReplace Draft GraphputPublish VersionpostGet AgentgetDelete AgentdeleteCopy AgentpostGet DraftgetGet Agent MapgetPending ChangesgetList PlacementsgetRestore VersionpostList VersionsgetGet Mapget
voice_agent
    Open Browser CallpostEnd Browser CalldeleteGet Agent Test LinkgetGet Bridge CeilinggetSet Bridge Ceilingpatch
ai_profiles
    Get Ai Profile CapabilitiesgetList Live SettingsgetCreate Live SettingspostDelete Live SettingsdeleteUpdate Live SettingspatchList Llm SettingsgetCreate Llm SettingspostDelete Llm SettingsdeleteUpdate Llm SettingspatchList ProfilesgetCreate ProfilepostGet ProfilegetDelete ProfiledeleteUpdate ProfilepatchCopy ProfilepostSet Text SectionputSet Voice SectionputList Stt SettingsgetCreate Stt SettingspostDelete Stt SettingsdeleteUpdate Stt SettingspatchList Tts SettingsgetCreate Tts SettingspostDelete Tts SettingsdeleteUpdate Tts SettingspatchList Vad SettingsgetCreate Vad SettingspostDelete Vad SettingsdeleteUpdate Vad Settingspatch
analyst
    List Agent FindingsgetCall Back FindingpostDismiss FindingpostUndo Finding DismissaldeleteTeach FindingpostWatch FindingpostList Question ChartsgetList Tracked QuestionsgetCreate Tracked QuestionpostGet Question Search CostgetSearch For Tracked QuestionpostPropose Tracked QuestionpostDelete Tracked QuestiondeleteUpdate Tracked QuestionpatchGet Reading SwitchgetSet Reading SwitchputGet Agent Summaryget
analytics
    List ChartsgetCreate ChartpostPreview ChartpostGet ChartgetDelete ChartdeleteUpdate ChartpatchRun ChartpostList DatasetsgetList BoardsgetCreate BoardpostGet TraversalgetGet BoardgetDelete BoarddeleteUpdate Boardpatch
authentication
    List InvitationsgetInvite MemberpostRevoke InvitationdeleteResend InvitationpostList MembersgetRemove MemberdeleteGet Member Conversation AccessgetSet Member Conversation AccesspatchSet Member FlagspatchSet Member RolepatchGet OrganizationgetUpdate OrganizationpatchGet Role FlagsgetSet Role Flagspatch
automations
    List AutomationsgetCreate AutomationpostGet AutomationgetDelete AutomationdeleteUpdate AutomationpatchSet Automation EnabledputGet Automation MapgetRun AutomationpostList Automation RunsgetGet Automation Runget
billable-metrics
    List MetricsgetUsage SummarygetGet Metricget
outbound_calls
    Place CallpostList CampaignsgetCreate CampaignpostGet CampaigngetDelete CampaigndeleteUpdate CampaignpatchActivate CampaignpostLink CollectionpostAdd ContactspostAdd Contacts From CollectionpostRemove Contacts From CollectionpostSet Campaign HoursputPreview Campaign HourspostPause CampaignpostGet Campaign SummarygetExclude ContactpostInclude Contactpost
channels
    List ChannelsgetCreate ChannelpostList Thread SubjectsgetClose Channel ThreadpostList Thread DecisionsgetGet Thread Contact FilegetHand Thread To AgentpostList Thread MailgetGet Prepared ReplygetAsk Again For Prepared ReplypostDiscard Prepared ReplypostSend Prepared ReplypostReply On Channel ThreadpostGet ChannelgetDelete ChanneldeleteUpdate ChannelpatchSend On ChannelpostList Channel ThreadsgetList RostergetCreate Roster EntrypostGet Own Roster EntrygetGet Roster EntrygetDelete Roster EntrydeleteUpdate Roster EntrypatchAdd Roster AddresspostChange Roster AddressputRemove Roster Addressdelete
custom-data
    List CollectionsgetCreate CollectionpostList Collection NamesgetGet CollectiongetDelete CollectiondeleteUpdate CollectionpatchAdd FieldpostDelete FielddeleteUpdate FieldpatchImport RecordspostPlan ImportpostPropose ImportpostGet ImportgetList RecordsgetCreate RecordpostBulk Delete RecordspostBulk Set FieldpostCount RecordsgetList Records Of ContactgetDelete Records Of ContactdeleteGet RecordgetDelete RecorddeleteUpdate Recordpatch
connections
    List ConnectionsgetCreate ConnectionpostCreate Forwarded AddresspostCreate Mail ServerpostDiscover Mail ServerpostAuthorize Microsoft MailboxpostList ProvidersgetGet ConnectiongetDelete ConnectiondeleteUpdate ConnectionpatchGet Forwarded AddressgetCheck Forwarded AddresspostList Person GrantsgetSet Person GrantputRemove Person GrantdeleteGet Mail ServergetUpdate Mail ServerpatchList Mail Server FoldersgetEnter Mail Server PasswordputChange Mail Server ServersputTest Mail Server AgainpostGet Microsoft MailboxgetUpdate Microsoft MailboxpatchList Microsoft Mailbox FoldersgetConsent To Microsoft Mailbox WritespostWithdraw Microsoft Mailbox Writesdelete
custom-tools
    List Custom ToolsgetCreate Custom ToolpostGet Custom ToolgetDelete Custom TooldeleteGet Custom Tool DraftgetEdit Custom Tool DraftpatchPublish Custom ToolpostRestore Custom Tool VersionpostTry Custom ToolpostList Custom Tool Versionsget
rag
    List DocumentsgetUpload DocumentpostSearch DocumentspostGet DocumentgetDelete DocumentdeleteDownload DocumentgetReingest Documentpost
flows
    List FlowsgetCreate FlowpostGet FlowgetDelete FlowdeleteRename FlowpatchAdd Flow EdgepostDelete Flow EdgedeleteSet Entry SteppatchAdd SteppostDelete StepdeleteUpdate SteppatchTest FlowpostList Flow Testsget
dynamic_context
    Create GraphpostGet GraphgetDelete GraphdeleteAdd EdgepostDelete EdgedeleteAdd NodepostDelete NodedeleteUpdate NodepatchSet Rootput
inbox
    Get Inbox Open CountgetSet Inbox PreferencespatchGet Inbox RailgetCreate Inbox ViewpostDelete Inbox ViewdeleteUpdate Inbox Viewpatch
handoff
    Assign Threadpost
interactions
    List InteractionsgetCount InteractionsgetGet InteractiongetSet Conversation LabelspostGet TracegetGet TranscriptgetList LabelsgetCreate LabelpostDelete LabeldeleteUpdate Labelpatch
legal
    Agree To Processing AgreementpostAgree To TermspostLegal BoxesgetList Legal DocumentsgetRead Legal DocumentgetList Legal VersionsgetRead Legal VersiongetDownload Legal VersiongetOrganization Legal HistorygetOwn Legal HistorygetObject To SubprocessorspostWithdraw ObjectionpostLegal Pendingget
not-a-tool
    Agree To Processing AgreementpostAgree To TermspostObject To SubprocessorspostWithdraw Objectionpost
memory
    List MemoriesgetList Memory LinesgetCreate Memory LinepostDelete Memory LinedeleteUpdate Memory LinepatchList Memory PeoplegetGet Memory PersongetForget PersondeleteGet Memory SwitchgetSet Memory SwitchputWipe ContactdeleteGet Conversation MemorygetRecall MemoriespostGet MemorygetDelete MemorydeletePatch Memorypatch
notifications
    List InboxgetGet Unread CountgetMark ReadpostMark Unreaddelete
recipes
    List RecipesgetList Installed RecipesgetGet Installed RecipegetUninstall RecipedeleteSet Recipe EnabledputUpdate Recipe ParameterspatchUpdate RecipepostInstall Recipepost
data-retention
    Get RetentiongetSet Retentionpatch
text
    Open ConversationpostClose ConversationpostAnswer ConfirmationpostGet Sent FilegetSend MessagepostSet Modepatch
tools
    List ToolsgetCreate ToolpostList BuiltinsgetImport Mcp ServerpostImport OpenapipostPreview Openapi ImportpostSuggest Tool ExamplespostGet ToolgetDelete TooldeleteUpdate ToolpatchTest ToolpostList Tool Testsget
trunks
    List Transfer DirectorygetCreate Transfer Directory EntrypostGet Transfer Directory EntrygetDelete Transfer Directory EntrydeleteUpdate Transfer Directory EntrypatchList TrunksgetCreate TrunkpostGet TrunkgetDelete TrunkdeleteUpdate TrunkpatchList Forward Recordsget
Schemas
powered by Zudoku
attek API
attek API

tools


List Tools

GET
/api/v1/tools

List the tool instances this organization can attach to an agent: its own and the global built-ins. Each carries its input schema, fixed parameters, deadline, whether it asks before running, and the connection or destination it uses; credentials are never included.

The whole list can be long, so narrow it: search keeps the tools whose name contains it, include_platform=false leaves out the operations imported from this platform's own server, and limit with offset reads it a page at a time, in a stable order.

List Tools › query Parameters

search
​
include_platform
​boolean
Default: true
limit
​
offset
​integer · min: 0
Default: 0

List Tools › Responses

Successful Response

​ToolView[]
A tool as the API returns it. A tool's `config` is write-only: it is set through `ToolIn`/`ToolUpdate` and never returned, because it holds the credentials the tool runs with.
ToolView
​required
conversation_only
​boolean · required
deadline_seconds
​integer · required
description
​string · required
​object · required
id
​string · uuid · required
​object · required
name
​string · required
​required
requires_confirmation
​boolean · required
source
​backend__features__tools__schemas__Source · enum · required

Where a tool comes from. Provenance matters to us (config/auth/billing), never to the LLM — which sees every source identically.

CUSTOM is retired and unreachable, and it is still here. It used to mean "code written for one organization", and runtime.execution._route refused it by name because nothing could run one. Code written for one organization now runs the way every other first-party tool does — BUILTIN, with config naming which built-in and the composition root binding it (ADR 0014, widened by ADR 0017) — so there is one dispatch path and this member names none of them. It is kept rather than removed because tool_source is a native Postgres enum: dropping a value means recreating the type, rewriting every dependent column and taking a lock on tools to delete a name no row has any reason to carry. backend/features/custom_tools/DECISIONS.md D10 records the trade. A row that somehow carries it is dispatched like any other non-MCP row and answers execute_http's "this tool has no destination configured", which is one answer rather than two.

Enum values:
builtin
custom
mcp
​
​
example_requests
​string[]
holds_credential
​boolean
Default: false
​
namespace
​string
Default:
​
​
tags
​string[]
visibility
​Visibility · enum

Whether the model is shown a tool whenever it is in reach, or only once the conversation has found it (tools.md rules 87-89). A fact about the tool, the same wherever it is attached; never what an agent may do, which attachment decides.

Enum values:
pinned
discoverable
Default: pinned
GET/api/v1/tools
curl /api/v1/tools \ --header 'Authorization: Bearer <token>'
Example Responses
[ { "builtin": "string", "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": true, "deadline_seconds": 0, "description": "description", "example_requests": [ "string" ], "fixed_parameters": {}, "holds_credential": false, "id": "00000000-0000-0000-0000-000000000000", "input_schema": {}, "mcp_server": "string", "name": "name", "namespace": "", "org_id": "00000000-0000-0000-0000-000000000000", "owner": { "id": "00000000-0000-0000-0000-000000000000", "kind": "kind" }, "owner_holds": [ "string" ], "requires_confirmation": true, "source": "builtin", "tags": [ "string" ], "visibility": "pinned" } ]
json
application/json

Create Tool

POST
/api/v1/tools

Create a tool instance: one named action with a schema, reusable across agents and attachable to a node, globally, or as a pre/post hook. Use when the agent needs one new action to call — one endpoint, or one flow offered as a tool. An instance with config.endpoint is the HTTP tool, the way the client's own system is reached, authorized through connection_id and never through a header. Where each person has their own key, set connection_group instead -- never both -- and every run uses the connection in that group whose subject_number is the conversation's number, else whose subject_ref is its subject_ref; nobody matching fails the run naming the group, with no fallback.

A flow is offered as a tool by an instance with source "builtin" and config.flow_id set to the flow's id, and nothing else in config: no endpoint, no connection_id, no header. The platform runs the flow itself, so there is no address to call it at; never invent one. The agent calls it by the instance's name with the parameters input_schema declares, and the flow's steps read them as $ref:trigger.<key>. Testing the instance runs the flow. A minimal body:

Code
{"name": "check_order", "description": "Look up the status of an order by its number.", "source": "builtin", "config": {"flow_id": "<the flow's id>"}, "input_schema": {"type": "object", "properties": {"order_number": {"type": "string"}}, "required": ["order_number"]}}

Keep each instance to one action; a job with several steps or a branch is a flow of instances, not one instance that does everything. A fixed_parameters value written $ref:conversation.<key> names what the conversation was opened with (number on either leg of a call, called_number on an inbound one, and number on a WhatsApp conversation from its first message; contact is who the conversation is with -- the number on a call, the address on a thread -- in every slot, post included, and absent for a withheld number; id is the conversation's own id) and is resolved when the tool runs. A key beginning atteq_ is the platform's own and cannot be fixed.

For a built-in, read list_builtins first: it gives the current parameters and which are usually fixed; the instance always carries the current ones, so input_schema need not be sent.

Create Tool › Request Body

ToolIn
name
​string · required
source
​Source-Input · enum · required

Where a tool comes from. Provenance matters to us (config/auth/billing), never to the LLM — which sees every source identically.

CUSTOM is retired and unreachable, and it is still here. It used to mean "code written for one organization", and runtime.execution._route refused it by name because nothing could run one. Code written for one organization now runs the way every other first-party tool does — BUILTIN, with config naming which built-in and the composition root binding it (ADR 0014, widened by ADR 0017) — so there is one dispatch path and this member names none of them. It is kept rather than removed because tool_source is a native Postgres enum: dropping a value means recreating the type, rewriting every dependent column and taking a lock on tools to delete a name no row has any reason to carry. backend/features/custom_tools/DECISIONS.md D10 records the trade. A row that somehow carries it is dispatched like any other non-MCP row and answers execute_http's "this tool has no destination configured", which is one answer rather than two.

Enum values:
builtin
custom
mcp
​object
​
​
conversation_only
​boolean
Default: false
deadline_seconds
​integer · min: 1 · max: 300
Default: 30
description
​string
Default:
example_requests
​string[]
​object
​object
requires_confirmation
​boolean
Default: false
tags
​string[]

Create Tool › Responses

Successful Response

A tool as the API returns it. A tool's `config` is write-only: it is set through `ToolIn`/`ToolUpdate` and never returned, because it holds the credentials the tool runs with.
ToolView
​required
conversation_only
​boolean · required
deadline_seconds
​integer · required
description
​string · required
​object · required
id
​string · uuid · required
​object · required
name
​string · required
​required
requires_confirmation
​boolean · required
source
​backend__features__tools__schemas__Source · enum · required

Where a tool comes from. Provenance matters to us (config/auth/billing), never to the LLM — which sees every source identically.

CUSTOM is retired and unreachable, and it is still here. It used to mean "code written for one organization", and runtime.execution._route refused it by name because nothing could run one. Code written for one organization now runs the way every other first-party tool does — BUILTIN, with config naming which built-in and the composition root binding it (ADR 0014, widened by ADR 0017) — so there is one dispatch path and this member names none of them. It is kept rather than removed because tool_source is a native Postgres enum: dropping a value means recreating the type, rewriting every dependent column and taking a lock on tools to delete a name no row has any reason to carry. backend/features/custom_tools/DECISIONS.md D10 records the trade. A row that somehow carries it is dispatched like any other non-MCP row and answers execute_http's "this tool has no destination configured", which is one answer rather than two.

Enum values:
builtin
custom
mcp
​
​
example_requests
​string[]
holds_credential
​boolean
Default: false
​
namespace
​string
Default:
​
​
tags
​string[]
visibility
​Visibility · enum

Whether the model is shown a tool whenever it is in reach, or only once the conversation has found it (tools.md rules 87-89). A fact about the tool, the same wherever it is attached; never what an agent may do, which attachment decides.

Enum values:
pinned
discoverable
Default: pinned
POST/api/v1/tools
curl /api/v1/tools \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "config": {}, "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": false, "deadline_seconds": 30, "description": "", "example_requests": [ "string" ], "fixed_parameters": {}, "input_schema": {}, "name": "name", "requires_confirmation": false, "source": "builtin", "tags": [ "string" ] }'
Example Request Body
{ "config": {}, "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": false, "deadline_seconds": 30, "description": "", "example_requests": [ "string" ], "fixed_parameters": {}, "input_schema": {}, "name": "name", "requires_confirmation": false, "source": "builtin", "tags": [ "string" ] }
json
Example Responses
{ "builtin": "string", "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": true, "deadline_seconds": 0, "description": "description", "example_requests": [ "string" ], "fixed_parameters": {}, "holds_credential": false, "id": "00000000-0000-0000-0000-000000000000", "input_schema": {}, "mcp_server": "string", "name": "name", "namespace": "", "org_id": "00000000-0000-0000-0000-000000000000", "owner": { "id": "00000000-0000-0000-0000-000000000000", "kind": "kind" }, "owner_holds": [ "string" ], "requires_confirmation": true, "source": "builtin", "tags": [ "string" ], "visibility": "pinned" }
json
application/json

List Builtins

GET
/api/v1/tools/builtins

The first-party built-ins this deployment runs, sorted by name — read it before creating a built-in instance, so you learn what one accepts instead of guessing or copying. search keeps the built-ins whose name contains it (calendar, sheet, mail), which is how to read the one you need rather than the whole catalogue.

name is what the instance carries in config.builtin; it is the only way to name a built-in. input_schema is what that built-in accepts today, fixed keys included, and an instance always carries this schema whenever it was made — so create_tool need not send one. fixed_parameters names the keys a person normally fixes on the instance, filling them in fixed_parameters on the instance so the model never sees them (a calendar id, a spreadsheet id). provider is the connection provider an instance needs, so connection_id must point at a connection of that provider, or null where it needs no authorization of yours. required_flag is the feature an organization must have for the built-in to be addable at all. input_schema is null for a built-in nobody creates by hand — one the platform makes where it applies — and there is nothing else to offer for it.

The same answer for every organization: it describes this deployment and nobody's rows, less any built-in that needs a feature you do not have.

List Builtins › query Parameters

search
​

List Builtins › Responses

Successful Response

​BuiltinOut[]
One first-party built-in this deployment runs, described so a person can make an instance of it from the panel (#558) -- `GET /tools/builtins`. `name` is what a row carries in `config["builtin"]`. `input_schema` is the schema that row is created with, fixed keys included; `fixed_parameters` names the keys a human usually fills on the instance and the model never sees; `provider` is the connection provider the instance needs (`google` for the calendar pair), or `providers` the several that can carry it. A built-in no client creates by hand -- one an organization gets made for it, like a collection's three -- is still listed, because the deployment binds it, with `input_schema` `None` and nothing else to offer.
BuiltinOut
name
​string · required
config_keys
​string[]
fixed_parameters
​string[]
​
​
providers
​string[]
​
GET/api/v1/tools/builtins
curl /api/v1/tools/builtins \ --header 'Authorization: Bearer <token>'
Example Responses
[ { "config_keys": [ "string" ], "fixed_parameters": [ "string" ], "input_schema": {}, "name": "name", "provider": "string", "providers": [ "string" ], "required_flag": "voice_agents" } ]
json
application/json

Import Mcp Server

POST
/api/v1/tools/import-mcp

Import every tool an MCP server offers, one configured tool per remote tool. Use when the client's actions already exist behind an MCP server, instead of creating one HTTP tool per endpoint by hand.

Each one arrives with the server's name, description and parameter schema, and with everything else left at its default for you to configure: fix a parameter, set a deadline, rename it. Importing the same server again refreshes what the server owns and keeps what you changed.

The server must be reachable on the public internet, with one exception: this platform's own MCP server, which is how an agent is given the API as tools. A tool calling it acts as whoever is talking to the agent.

Point the import at a connection to authorize it; the imported tools then carry no credential of their own. The older auth field still works for a stored bearer, but give one or the other, not both.

A server that will not list its tools is answered 502, naming it as you wrote it and saying what it answered. One that asks you to sign in first is connected from Connections, where your organization holds the MCP door, and imported again choosing that connection.

Reach for it when the client's actions already exist behind an MCP server. For a plain HTTP API of theirs, create one HTTP tool per endpoint instead (create_tool with config.endpoint and a connection_id). Each imported tool is one action like any other instance: attach it to a node, or make it a step of a flow.

Import Mcp Server › Request Body

Which MCP server to import, how to reach it, and what authorizes it. `connection_id` points every imported instance at a connection, which is how an import authorizes: the grant stays with the connection and the instance carries no key of its own. `auth` is the **legacy** way to say the same thing — an opaque bearer for a third party's server, stored on each instance's `config` and therefore write-only, like every other credential here: it goes in and never comes back out. It is kept because it is a published parameter with existing callers and because no stored bearer can be turned into a connection; prefer `connection_id` for anything new. **Give one or the other, never both.** Leave both unset for our own server — a tool that calls this platform runs as whoever is talking to the agent, and no credential is stored for it at all. `name_prefix` is put in front of every imported tool's name. Two servers may each publish a `search`, and a person attaching both to one agent has to be able to tell them apart.
McpImportIn
server_url
​string · required
​
​
​

Import Mcp Server › Responses

Successful Response

​ToolView[]
A tool as the API returns it. A tool's `config` is write-only: it is set through `ToolIn`/`ToolUpdate` and never returned, because it holds the credentials the tool runs with.
ToolView
​required
conversation_only
​boolean · required
deadline_seconds
​integer · required
description
​string · required
​object · required
id
​string · uuid · required
​object · required
name
​string · required
​required
requires_confirmation
​boolean · required
source
​backend__features__tools__schemas__Source · enum · required

Where a tool comes from. Provenance matters to us (config/auth/billing), never to the LLM — which sees every source identically.

CUSTOM is retired and unreachable, and it is still here. It used to mean "code written for one organization", and runtime.execution._route refused it by name because nothing could run one. Code written for one organization now runs the way every other first-party tool does — BUILTIN, with config naming which built-in and the composition root binding it (ADR 0014, widened by ADR 0017) — so there is one dispatch path and this member names none of them. It is kept rather than removed because tool_source is a native Postgres enum: dropping a value means recreating the type, rewriting every dependent column and taking a lock on tools to delete a name no row has any reason to carry. backend/features/custom_tools/DECISIONS.md D10 records the trade. A row that somehow carries it is dispatched like any other non-MCP row and answers execute_http's "this tool has no destination configured", which is one answer rather than two.

Enum values:
builtin
custom
mcp
​
​
example_requests
​string[]
holds_credential
​boolean
Default: false
​
namespace
​string
Default:
​
​
tags
​string[]
visibility
​Visibility · enum

Whether the model is shown a tool whenever it is in reach, or only once the conversation has found it (tools.md rules 87-89). A fact about the tool, the same wherever it is attached; never what an agent may do, which attachment decides.

Enum values:
pinned
discoverable
Default: pinned
POST/api/v1/tools/import-mcp
curl /api/v1/tools/import-mcp \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "auth": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "name_prefix": "string", "server_url": "server_url" }'
Example Request Body
{ "auth": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "name_prefix": "string", "server_url": "server_url" }
json
Example Responses
[ { "builtin": "string", "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": true, "deadline_seconds": 0, "description": "description", "example_requests": [ "string" ], "fixed_parameters": {}, "holds_credential": false, "id": "00000000-0000-0000-0000-000000000000", "input_schema": {}, "mcp_server": "string", "name": "name", "namespace": "", "org_id": "00000000-0000-0000-0000-000000000000", "owner": { "id": "00000000-0000-0000-0000-000000000000", "kind": "kind" }, "owner_holds": [ "string" ], "requires_confirmation": true, "source": "builtin", "tags": [ "string" ], "visibility": "pinned" } ]
json
application/json

Import Openapi

POST
/api/v1/tools/import-openapi

Turn the operations a client chose from a published API description into ordinary HTTP tools, one per operation, with one connection (or one group of connections, or none) for the whole set. Use it when the client's system publishes an OpenAPI 3.x or Google Discovery description, instead of creating one HTTP tool per endpoint by hand. Call import-openapi/preview first to get the key of each operation and the server to choose.

Send the same url or document as the preview, the server for the set, the operations (keys, at most 50) and connection_id or connection_group. Nothing is created unless all of it can be: a failure leaves no tool behind.

Importing again with the same server refreshes the tools already made from it (address, method, parameters, description) and keeps what the client changed (name, fixed values, deadline, connection, attachments); chosen operations not made yet are created. A tool whose operation the description no longer holds is left as it is and listed in missing; nothing is deleted. A different server is a new set. Each tool is then one action like any other instance: fix a parameter, set a deadline, attach it to a node, or make it a step of a flow.

Import Openapi › Request Body

What to create from a description: the server for the set, the operations the client chose (by the `key` the preview gave each, at most 50), and one connection or one group of connections for all of them, or neither. Importing again with the same server refreshes the tools already made from it and creates the ones not made yet.
ApiImportIn
operations
​string[] · minItems: 1 · required
server
​string · required
​
​
​
​
​

Import Openapi › Responses

Successful Response

The tools created or refreshed, and the ones whose operation is gone.
ApiImportOut
​ApiMissingOut[] · required
​ToolView[] · required
POST/api/v1/tools/import-openapi
curl /api/v1/tools/import-openapi \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "document": "string", "name_prefix": "string", "operations": [ "string" ], "server": "server", "url": "string" }'
Example Request Body
{ "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "document": "string", "name_prefix": "string", "operations": [ "string" ], "server": "server", "url": "string" }
json
Example Responses
{ "missing": [ { "name": "name", "operation": "operation", "tool_id": "00000000-0000-0000-0000-000000000000" } ], "tools": [ { "builtin": "string", "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": true, "deadline_seconds": 0, "description": "description", "example_requests": [ "string" ], "fixed_parameters": {}, "holds_credential": false, "id": "00000000-0000-0000-0000-000000000000", "input_schema": {}, "mcp_server": "string", "name": "name", "namespace": "", "org_id": "00000000-0000-0000-0000-000000000000", "owner": { "id": "00000000-0000-0000-0000-000000000000", "kind": "kind" }, "owner_holds": [ "string" ], "requires_confirmation": true, "source": "builtin", "tags": [ "string" ], "visibility": "pinned" } ] }
json
application/json

Preview Openapi Import

POST
/api/v1/tools/import-openapi/preview

Read a published API description and list what could become tools. Writes nothing, costs nothing, and involves no model. Use it before import-openapi to let the client choose.

Give the description's url (fetched by the platform, from the public internet only) or its document (the text of the file). It must be JSON: an OpenAPI 3.x description or a Google Discovery document; anything else is refused naming what was found, and so is one larger than 16 MB or holding more than 3,000 operations.

The answer lists, in the description's order, every operations entry that can become an HTTP tool -- its key (what import-openapi takes), method, path, the tool name and description it would get, its input_schema and where each value goes (locations) -- the unimportable ones with the reason (a form or file body, a webhook, an unresolved reference...), the servers to choose one from (url is null for a server given relative to a file: the client types it), each with the connection the description's authorization suggests, and the bound of operations per import. name_prefix shows the names with a prefix, joined by _ unless it already ends in _ or - (crm gives crm_get_contacts).

Preview Openapi Import › Request Body

A published API description, by its address or as the file's text (api-import.md rule 1). Give exactly one. `url` is fetched by the platform, to the internet only. `document` is the text of a JSON OpenAPI 3.x or Google Discovery description.
ApiDescriptionIn
​
​
​

Preview Openapi Import › Responses

Successful Response

What the client chooses from. Nothing was written.
ApiPreviewOut
kind
​string · required
max_operations_per_import
​integer · required
​ApiOperationOut[] · required
​ApiServerOut[] · required
title
​string · required
​ApiUnimportableOut[] · required
POST/api/v1/tools/import-openapi/preview
curl /api/v1/tools/import-openapi/preview \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "document": "string", "name_prefix": "string", "url": "string" }'
Example Request Body
{ "document": "string", "name_prefix": "string", "url": "string" }
json
Example Responses
{ "kind": "kind", "max_operations_per_import": 0, "operations": [ { "description": "description", "input_schema": {}, "key": "key", "locations": {}, "method": "method", "name": "name", "path": "path", "summary": "summary" } ], "servers": [ { "description": "", "suggestion": { "header": "string", "note": "", "parameter": "string", "placement": "string", "prefix": "string", "provider": "string" }, "url": "string" } ], "title": "title", "unimportable": [ { "key": "key", "method": "method", "path": "path", "reason": "reason", "summary": "summary" } ] }
json
application/json

Suggest Tool Examples

POST
/api/v1/tools/suggest-examples

Ask the platform's drafting model for example requests for a tool, written as a person would ask for what it does. Use while writing a tool's card, from its name, description and parameters, when none is written yet or a few more are wanted.

It is paid work, and nothing is stored. The language model's input and output tokens are recorded against the organization, with no conversation and no tool execution; the answer is a list to keep, change or drop, saved only by writing it onto the tool (example_requests on create or update). Never called by an import. Answers at most what is left of the card's bound after the requests sent in, and nothing at all, asking no model, when the card is full. Refused with 402 while the organization may not spend, and with 502 when the model could not answer.

Suggest Tool Examples › Request Body

What the model is shown of a tool, read off the form -- which may not be saved yet.
ExampleSuggestionIn
name
​string · minLength: 1 · required
description
​string
Default:
example_requests
​string[]
​object

Suggest Tool Examples › Responses

Successful Response

The requests the model wrote, to be kept, changed or dropped one by one. Never stored by this answer.
ExampleSuggestionOut
example_requests
​string[] · required
POST/api/v1/tools/suggest-examples
curl /api/v1/tools/suggest-examples \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "description": "", "example_requests": [ "string" ], "input_schema": {}, "name": "name" }'
Example Request Body
{ "description": "", "example_requests": [ "string" ], "input_schema": {}, "name": "name" }
json
Example Responses
{ "example_requests": [ "string" ] }
json
application/json

Get Tool

GET
/api/v1/tools/{tool_id}

Read one tool instance, own or global built-in: its source, input schema, fixed parameters, deadline, whether it asks before running, and the connection or destination it uses. Credentials are never included.

Get Tool › path Parameters

tool_id
​string · uuid · required

Get Tool › Responses

Successful Response

A tool as the API returns it. A tool's `config` is write-only: it is set through `ToolIn`/`ToolUpdate` and never returned, because it holds the credentials the tool runs with.
ToolView
​required
conversation_only
​boolean · required
deadline_seconds
​integer · required
description
​string · required
​object · required
id
​string · uuid · required
​object · required
name
​string · required
​required
requires_confirmation
​boolean · required
source
​backend__features__tools__schemas__Source · enum · required

Where a tool comes from. Provenance matters to us (config/auth/billing), never to the LLM — which sees every source identically.

CUSTOM is retired and unreachable, and it is still here. It used to mean "code written for one organization", and runtime.execution._route refused it by name because nothing could run one. Code written for one organization now runs the way every other first-party tool does — BUILTIN, with config naming which built-in and the composition root binding it (ADR 0014, widened by ADR 0017) — so there is one dispatch path and this member names none of them. It is kept rather than removed because tool_source is a native Postgres enum: dropping a value means recreating the type, rewriting every dependent column and taking a lock on tools to delete a name no row has any reason to carry. backend/features/custom_tools/DECISIONS.md D10 records the trade. A row that somehow carries it is dispatched like any other non-MCP row and answers execute_http's "this tool has no destination configured", which is one answer rather than two.

Enum values:
builtin
custom
mcp
​
​
example_requests
​string[]
holds_credential
​boolean
Default: false
​
namespace
​string
Default:
​
​
tags
​string[]
visibility
​Visibility · enum

Whether the model is shown a tool whenever it is in reach, or only once the conversation has found it (tools.md rules 87-89). A fact about the tool, the same wherever it is attached; never what an agent may do, which attachment decides.

Enum values:
pinned
discoverable
Default: pinned
GET/api/v1/tools/{tool_id}
curl /api/v1/tools/:tool_id \ --header 'Authorization: Bearer <token>'
Example Responses
{ "builtin": "string", "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": true, "deadline_seconds": 0, "description": "description", "example_requests": [ "string" ], "fixed_parameters": {}, "holds_credential": false, "id": "00000000-0000-0000-0000-000000000000", "input_schema": {}, "mcp_server": "string", "name": "name", "namespace": "", "org_id": "00000000-0000-0000-0000-000000000000", "owner": { "id": "00000000-0000-0000-0000-000000000000", "kind": "kind" }, "owner_holds": [ "string" ], "requires_confirmation": true, "source": "builtin", "tags": [ "string" ], "visibility": "pinned" }
json
application/json

Delete Tool

DELETE
/api/v1/tools/{tool_id}

Delete a tool permanently. Use when the action should no longer exist; agents that referenced it stop being able to call it.

Delete Tool › path Parameters

tool_id
​string · uuid · required

Delete Tool › Responses

Successful Response

No data returned
DELETE/api/v1/tools/{tool_id}
curl /api/v1/tools/:tool_id \ --request DELETE \ --header 'Authorization: Bearer <token>'
Example Responses
No example specified for this content type

Update Tool

PATCH
/api/v1/tools/{tool_id}

Change a tool's name, description, fixed parameters, or the destination it may reach. Use when adjusting an existing tool instance's configuration, not when the agent needs a new action. A fixed_parameters value written $ref:conversation.<key> names what the conversation was opened with (number on either leg of a call, called_number on an inbound one, contact on a channel; id is the conversation's own id) and is resolved when the tool runs. A key beginning atteq_ is the platform's own and cannot be fixed.

fixed_parameters replaces the whole set: send every value you want fixed, not only the new one.

Update Tool › path Parameters

tool_id
​string · uuid · required

Update Tool › Request Body

Partial edit — only the provided fields change (`model_dump(exclude_unset)`).
ToolUpdate
​
​
​
​
​
​
​
​
​
​
​
​
​
​

Update Tool › Responses

Successful Response

A tool as the API returns it. A tool's `config` is write-only: it is set through `ToolIn`/`ToolUpdate` and never returned, because it holds the credentials the tool runs with.
ToolView
​required
conversation_only
​boolean · required
deadline_seconds
​integer · required
description
​string · required
​object · required
id
​string · uuid · required
​object · required
name
​string · required
​required
requires_confirmation
​boolean · required
source
​backend__features__tools__schemas__Source · enum · required

Where a tool comes from. Provenance matters to us (config/auth/billing), never to the LLM — which sees every source identically.

CUSTOM is retired and unreachable, and it is still here. It used to mean "code written for one organization", and runtime.execution._route refused it by name because nothing could run one. Code written for one organization now runs the way every other first-party tool does — BUILTIN, with config naming which built-in and the composition root binding it (ADR 0014, widened by ADR 0017) — so there is one dispatch path and this member names none of them. It is kept rather than removed because tool_source is a native Postgres enum: dropping a value means recreating the type, rewriting every dependent column and taking a lock on tools to delete a name no row has any reason to carry. backend/features/custom_tools/DECISIONS.md D10 records the trade. A row that somehow carries it is dispatched like any other non-MCP row and answers execute_http's "this tool has no destination configured", which is one answer rather than two.

Enum values:
builtin
custom
mcp
​
​
example_requests
​string[]
holds_credential
​boolean
Default: false
​
namespace
​string
Default:
​
​
tags
​string[]
visibility
​Visibility · enum

Whether the model is shown a tool whenever it is in reach, or only once the conversation has found it (tools.md rules 87-89). A fact about the tool, the same wherever it is attached; never what an agent may do, which attachment decides.

Enum values:
pinned
discoverable
Default: pinned
PATCH/api/v1/tools/{tool_id}
curl /api/v1/tools/:tool_id \ --request PATCH \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "config": {}, "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": true, "deadline_seconds": 1, "description": "string", "example_requests": [ "string" ], "fixed_parameters": {}, "input_schema": {}, "name": "string", "requires_confirmation": true, "source": "builtin", "tags": [ "string" ], "visibility": "pinned" }'
Example Request Body
{ "config": {}, "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": true, "deadline_seconds": 1, "description": "string", "example_requests": [ "string" ], "fixed_parameters": {}, "input_schema": {}, "name": "string", "requires_confirmation": true, "source": "builtin", "tags": [ "string" ], "visibility": "pinned" }
json
Example Responses
{ "builtin": "string", "connection_group": "string", "connection_id": "00000000-0000-0000-0000-000000000000", "conversation_only": true, "deadline_seconds": 0, "description": "description", "example_requests": [ "string" ], "fixed_parameters": {}, "holds_credential": false, "id": "00000000-0000-0000-0000-000000000000", "input_schema": {}, "mcp_server": "string", "name": "name", "namespace": "", "org_id": "00000000-0000-0000-0000-000000000000", "owner": { "id": "00000000-0000-0000-0000-000000000000", "kind": "kind" }, "owner_holds": [ "string" ], "requires_confirmation": true, "source": "builtin", "tags": [ "string" ], "visibility": "pinned" }
json
application/json

Test Tool

POST
/api/v1/tools/{tool_id}/test

Testing a tool runs it. Use right after create_tool, before the instance is attached to a node or made a step of a flow, with the parameters a real call would carry; not for a custom tool's draft, which is try_custom_tool. Nothing is simulated: the instance executes against the destination it is configured for, with its own credentials — or, where it points at a connection, with that connection's authorization. An instance with config.flow_id runs its flow, every step, as a conversation would, with these parameters as what the flow is started with. Testing a tool that sends an email sends the email; testing one that writes into your own system writes into it. The only thing this supplies is parameters — pointing the test at a safe environment is your decision to make, on the instance.

Because the call is real, a provider that refuses the connection's authorization marks that connection broken, exactly as it would during a conversation.

A tool that only exists inside a conversation has nothing to test here and is refused rather than executed, and a test is refused with 402 while the organization may not spend.

A refusal here is the refusal a conversation would get, so it is where a wrong endpoint or a broken connection shows up first.

Test Tool › path Parameters

tool_id
​string · uuid · required

Test Tool › Request Body

What a test supplies, and the only thing it supplies: parameters. The destination, the credentials and the fixed values are the instance's own — a test that could replace them would be testing something else.
ToolTestIn
​object

Test Tool › Responses

Successful Response

What one test of an instance did. Recorded against the instance, not as a conversation, because there was none. `parameters` is what the tool **actually ran with**, fixed values included — the client is shown what the model is not. It never contains `config`: those are the credentials, and they are not parameters.
ToolTestOut
attempts
​integer · required
created_at
​string · date-time · required
detail
​string · required
duration_ms
​integer · required
id
​string · uuid · required
outcome
​Outcome · enum · required

How one execution of a tool ended.

Enum values:
succeeded
failed
refused
​object · required
response_body
​string · required
​required
tool_id
​string · uuid · required
POST/api/v1/tools/{tool_id}/test
curl /api/v1/tools/:tool_id/test \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "parameters": {} }'
Example Request Body
{ "parameters": {} }
json
Example Responses
{ "attempts": 0, "created_at": "2024-08-25T15:00:00Z", "detail": "detail", "duration_ms": 0, "id": "00000000-0000-0000-0000-000000000000", "outcome": "succeeded", "parameters": {}, "response_body": "response_body", "status_code": 0, "tool_id": "00000000-0000-0000-0000-000000000000" }
json
application/json

List Tool Tests

GET
/api/v1/tools/{tool_id}/tests

What this instance's tests did, newest first. Use when reviewing a tool's test history instead of running a new test.

List Tool Tests › path Parameters

tool_id
​string · uuid · required

List Tool Tests › Responses

Successful Response

​ToolTestOut[]
What one test of an instance did. Recorded against the instance, not as a conversation, because there was none. `parameters` is what the tool **actually ran with**, fixed values included — the client is shown what the model is not. It never contains `config`: those are the credentials, and they are not parameters.
ToolTestOut
attempts
​integer · required
created_at
​string · date-time · required
detail
​string · required
duration_ms
​integer · required
id
​string · uuid · required
outcome
​Outcome · enum · required

How one execution of a tool ended.

Enum values:
succeeded
failed
refused
​object · required
response_body
​string · required
​required
tool_id
​string · uuid · required
GET/api/v1/tools/{tool_id}/tests
curl /api/v1/tools/:tool_id/tests \ --header 'Authorization: Bearer <token>'
Example Responses
[ { "attempts": 0, "created_at": "2024-08-25T15:00:00Z", "detail": "detail", "duration_ms": 0, "id": "00000000-0000-0000-0000-000000000000", "outcome": "succeeded", "parameters": {}, "response_body": "response_body", "status_code": 0, "tool_id": "00000000-0000-0000-0000-000000000000" } ]
json
application/json

texttrunks