Run one connection tool
Rails runs one tool of a connection the bot may use (we-bots phase 012). That is a company connection, or a personal one made by the bot’s owner or a steward, whose connector the company still allows and whose tool is switched on. Rails makes the call, so no connection secret reaches the runtime. Each call that reaches the server is recorded with its tool, effect class and outcome, never its arguments or answer. The answer is marked untrusted.
A tool in approval mode (one that writes, sends or deletes) runs only on a person’s approval, which the We-Bots runtime asks for first: it parks the call and records it with POST /internal/we-bots/runs/{run}/approval-requests as a connection_call, and calls here once a person approves it in Fluid. Rails authorizes the call as the bot’s owner and does not gate it by bot.
curl --request POST \
--url https://api.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tool": "search_tickets",
"tool_arguments": {
"query": "refund"
}
}
'import requests
url = "https://api.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call"
payload = {
"tool": "search_tickets",
"tool_arguments": { "query": "refund" }
}
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({tool: 'search_tickets', tool_arguments: {query: 'refund'}})
};
fetch('https://api.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call', 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.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call",
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([
'tool' => 'search_tickets',
'tool_arguments' => [
'query' => 'refund'
]
]),
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.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call"
payload := strings.NewReader("{\n \"tool\": \"search_tickets\",\n \"tool_arguments\": {\n \"query\": \"refund\"\n }\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.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tool\": \"search_tickets\",\n \"tool_arguments\": {\n \"query\": \"refund\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call")
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 \"tool\": \"search_tickets\",\n \"tool_arguments\": {\n \"query\": \"refund\"\n }\n}"
response = http.request(request)
puts response.read_body{
"answer": {
"text": "Ticket 4412: Refund for order 1009 (open)",
"truncated": false,
"tool_error": false,
"untrusted": true
},
"status": 200,
"meta": {
"request_uuid": "0192f0a4-7c1e-7d1a-9f3b-2a6c4d8e1f00",
"timestamp": "2026-10-25T02:00:00Z"
}
}{
"message": "Invalid credentials."
}{
"message": "Not authorized."
}{
"error": {
"message": "Run not found",
"details": {}
},
"status": 404,
"meta": {
"request_uuid": "7e2c9b41-3f8a-4d15-b6e0-9a4c21d7f583",
"timestamp": "2026-10-26T15:32:08Z"
}
}{
"error": {
"message": "The run is not open",
"details": {
"type": "run_closed"
}
},
"status": 409,
"meta": {
"request_uuid": "7e2c9b41-3f8a-4d15-b6e0-9a4c21d7f583",
"timestamp": "2026-10-26T15:32:08Z"
}
}Authorizations
The session token of an admin of your company. Company API, partner and droplet installation tokens are refused.
Path Parameters
The connection's id.
The bot's id.
The id of one of the bot's runs.
Body
Response
The tool's answer, or why it was refused.
curl --request POST \
--url https://api.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tool": "search_tickets",
"tool_arguments": {
"query": "refund"
}
}
'import requests
url = "https://api.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call"
payload = {
"tool": "search_tickets",
"tool_arguments": { "query": "refund" }
}
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({tool: 'search_tickets', tool_arguments: {query: 'refund'}})
};
fetch('https://api.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call', 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.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call",
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([
'tool' => 'search_tickets',
'tool_arguments' => [
'query' => 'refund'
]
]),
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.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call"
payload := strings.NewReader("{\n \"tool\": \"search_tickets\",\n \"tool_arguments\": {\n \"query\": \"refund\"\n }\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.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tool\": \"search_tickets\",\n \"tool_arguments\": {\n \"query\": \"refund\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/company/v2026-10/bots/{bot_id}/runs/{run_id}/connections/{id}/call")
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 \"tool\": \"search_tickets\",\n \"tool_arguments\": {\n \"query\": \"refund\"\n }\n}"
response = http.request(request)
puts response.read_body{
"answer": {
"text": "Ticket 4412: Refund for order 1009 (open)",
"truncated": false,
"tool_error": false,
"untrusted": true
},
"status": 200,
"meta": {
"request_uuid": "0192f0a4-7c1e-7d1a-9f3b-2a6c4d8e1f00",
"timestamp": "2026-10-25T02:00:00Z"
}
}{
"message": "Invalid credentials."
}{
"message": "Not authorized."
}{
"error": {
"message": "Run not found",
"details": {}
},
"status": 404,
"meta": {
"request_uuid": "7e2c9b41-3f8a-4d15-b6e0-9a4c21d7f583",
"timestamp": "2026-10-26T15:32:08Z"
}
}{
"error": {
"message": "The run is not open",
"details": {
"type": "run_closed"
}
},
"status": 409,
"meta": {
"request_uuid": "7e2c9b41-3f8a-4d15-b6e0-9a4c21d7f583",
"timestamp": "2026-10-26T15:32:08Z"
}
}