Plan Research Task
Estimates a research task without creating it. Returns the resolved retrieval depth and estimates of cost, latency, and work, including whether they fit the proposed budget.
For the plan, create, poll, and read flow, see Run a Research Task.
curl --request POST \
--url https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"budgetUsd": 0.05,
"mode": "research",
"query": "What changed in the 2025 refund policy, and which regions are affected?",
"topK": 10
}
'import requests
url = "https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan"
payload = {
"budgetUsd": 0.05,
"mode": "research",
"query": "What changed in the 2025 refund policy, and which regions are affected?",
"topK": 10
}
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({
budgetUsd: 0.05,
mode: 'research',
query: 'What changed in the 2025 refund policy, and which regions are affected?',
topK: 10
})
};
fetch('https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan', 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_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan",
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([
'budgetUsd' => 0.05,
'mode' => 'research',
'query' => 'What changed in the 2025 refund policy, and which regions are affected?',
'topK' => 10
]),
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_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan"
payload := strings.NewReader("{\n \"budgetUsd\": 0.05,\n \"mode\": \"research\",\n \"query\": \"What changed in the 2025 refund policy, and which regions are affected?\",\n \"topK\": 10\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_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"budgetUsd\": 0.05,\n \"mode\": \"research\",\n \"query\": \"What changed in the 2025 refund policy, and which regions are affected?\",\n \"topK\": 10\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan")
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 \"budgetUsd\": 0.05,\n \"mode\": \"research\",\n \"query\": \"What changed in the 2025 refund policy, and which regions are affected?\",\n \"topK\": 10\n}"
response = http.request(request)
puts response.read_body{
"budget": {
"budget_usd": 0.05,
"exceeds_budget": false,
"remaining_budget_usd": 0.018238
},
"estimates": {
"cacheHitProbability": 0.25,
"costUsd": {
"currency": "USD",
"estimated": 0.031762,
"max": 0.042879,
"min": 0.020645
},
"inputTokens": 3070,
"latencyMs": {
"p50": 2800,
"p95": 5040
},
"outputTokens": 1776,
"retrievalSteps": 3,
"scannedResources": 620,
"toolCalls": 6,
"totalTokens": 4846,
"workBounds": {
"modelCalls": {
"estimated": 3,
"max": 4,
"min": 2
},
"openedResources": {
"estimated": 20,
"max": 40,
"min": 0
},
"retrievalSteps": {
"estimated": 3,
"max": 5,
"min": 1
}
}
},
"knowledge_space_id": "b2f1d3a4-5e6c-4a7b-8c9d-0e1f2a3b4c5d",
"query": "What changed in the 2025 refund policy, and which regions are affected?",
"retrieval_plan": {
"dense_top_k": 100,
"fts_top_k": 100,
"fusion_limit": 50,
"query_language": "latin",
"requested_mode": "research",
"rerank_candidate_limit": 50,
"resolved_mode": "research",
"strategy_version": "retrieval-planner-v2",
"top_k": 10
},
"steps": [
{
"estimatedCostUsd": 0.003126,
"estimatedInputTokens": 274,
"estimatedLatencyMs": 350,
"estimatedOutputTokens": 192,
"estimatedToolCalls": 1,
"name": "plan"
},
{
"estimatedCostUsd": 0.00124,
"estimatedInputTokens": 0,
"estimatedLatencyMs": 600,
"estimatedOutputTokens": 0,
"estimatedToolCalls": 3,
"name": "retrieve"
},
{
"estimatedCostUsd": 0.007542,
"estimatedInputTokens": 978,
"estimatedLatencyMs": 650,
"estimatedOutputTokens": 384,
"estimatedToolCalls": 1,
"name": "analyze"
},
{
"estimatedCostUsd": 0.019854,
"estimatedInputTokens": 1818,
"estimatedLatencyMs": 1200,
"estimatedOutputTokens": 1200,
"estimatedToolCalls": 1,
"name": "generate"
}
],
"strategy_version": "research-dry-run-planner-v1"
}Authorizations
Every request authenticates with an API key: Authorization: Bearer {API_KEY}. App endpoints take an app API key; knowledge endpoints take a knowledge base API key (Get Started).
Keep keys server-side; never embed them in client code. Requests with a missing or invalid key fail with HTTP 401 (unauthorized).
Path Parameters
Knowledge base ID: the last segment of the Service API endpoint shown in the knowledge base's API Access dialog (…/knowledge-fs/spaces/<knowledge base ID>), and the segment after /datasets/new/ in the address bar.
Body
Optional fields marked nullable treat null as omitted.
The normalized request must fit within 65,536 UTF-8 bytes. See Request Size Limits.
Provide a nonblank query.
The question. Use a nonblank query. Also limited to 16,384 UTF-8 bytes.
16000\SSpend ceiling in USD to compare with the cost estimate. Sets budget.exceeds_budget and budget.remaining_budget_usd in the response.
x >= 0Retrieval depth: fast, deep, or research (see Retrieval Depth). Omit it to use the knowledge base's default depth, retrieval.default_mode in Get Knowledge Base Settings.
fast, deep, research, null Maximum number of chunks kept after the search results are merged and reranked. Explicit values must be between 1 and 50. If omitted, uses the knowledge base's published TOP K setting, which can be up to 100. Higher values give the model more context and more noise. Lower values stay focused and can miss relevant chunks.
1 <= x <= 50Response
The plan and its estimates.
Verdict of the cost estimate against the request's budgetUsd.
Show child attributes
Show child attributes
Work, cost, and latency estimates for the task. Compare them with the limits you intend to send to Create Research Task.
Show child attributes
Show child attributes
Internal ID of the knowledge base. Not the knowledge base ID in the path.
The question with surrounding whitespace removed.
How the search would be run.
Show child attributes
Show child attributes
Per-step estimates, in execution order.
Show child attributes
Show child attributes
Version of the estimator.
Was this page helpful?
curl --request POST \
--url https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"budgetUsd": 0.05,
"mode": "research",
"query": "What changed in the 2025 refund policy, and which regions are affected?",
"topK": 10
}
'import requests
url = "https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan"
payload = {
"budgetUsd": 0.05,
"mode": "research",
"query": "What changed in the 2025 refund policy, and which regions are affected?",
"topK": 10
}
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({
budgetUsd: 0.05,
mode: 'research',
query: 'What changed in the 2025 refund policy, and which regions are affected?',
topK: 10
})
};
fetch('https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan', 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_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan",
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([
'budgetUsd' => 0.05,
'mode' => 'research',
'query' => 'What changed in the 2025 refund policy, and which regions are affected?',
'topK' => 10
]),
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_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan"
payload := strings.NewReader("{\n \"budgetUsd\": 0.05,\n \"mode\": \"research\",\n \"query\": \"What changed in the 2025 refund policy, and which regions are affected?\",\n \"topK\": 10\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_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"budgetUsd\": 0.05,\n \"mode\": \"research\",\n \"query\": \"What changed in the 2025 refund policy, and which regions are affected?\",\n \"topK\": 10\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/research-tasks/plan")
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 \"budgetUsd\": 0.05,\n \"mode\": \"research\",\n \"query\": \"What changed in the 2025 refund policy, and which regions are affected?\",\n \"topK\": 10\n}"
response = http.request(request)
puts response.read_body{
"budget": {
"budget_usd": 0.05,
"exceeds_budget": false,
"remaining_budget_usd": 0.018238
},
"estimates": {
"cacheHitProbability": 0.25,
"costUsd": {
"currency": "USD",
"estimated": 0.031762,
"max": 0.042879,
"min": 0.020645
},
"inputTokens": 3070,
"latencyMs": {
"p50": 2800,
"p95": 5040
},
"outputTokens": 1776,
"retrievalSteps": 3,
"scannedResources": 620,
"toolCalls": 6,
"totalTokens": 4846,
"workBounds": {
"modelCalls": {
"estimated": 3,
"max": 4,
"min": 2
},
"openedResources": {
"estimated": 20,
"max": 40,
"min": 0
},
"retrievalSteps": {
"estimated": 3,
"max": 5,
"min": 1
}
}
},
"knowledge_space_id": "b2f1d3a4-5e6c-4a7b-8c9d-0e1f2a3b4c5d",
"query": "What changed in the 2025 refund policy, and which regions are affected?",
"retrieval_plan": {
"dense_top_k": 100,
"fts_top_k": 100,
"fusion_limit": 50,
"query_language": "latin",
"requested_mode": "research",
"rerank_candidate_limit": 50,
"resolved_mode": "research",
"strategy_version": "retrieval-planner-v2",
"top_k": 10
},
"steps": [
{
"estimatedCostUsd": 0.003126,
"estimatedInputTokens": 274,
"estimatedLatencyMs": 350,
"estimatedOutputTokens": 192,
"estimatedToolCalls": 1,
"name": "plan"
},
{
"estimatedCostUsd": 0.00124,
"estimatedInputTokens": 0,
"estimatedLatencyMs": 600,
"estimatedOutputTokens": 0,
"estimatedToolCalls": 3,
"name": "retrieve"
},
{
"estimatedCostUsd": 0.007542,
"estimatedInputTokens": 978,
"estimatedLatencyMs": 650,
"estimatedOutputTokens": 384,
"estimatedToolCalls": 1,
"name": "analyze"
},
{
"estimatedCostUsd": 0.019854,
"estimatedInputTokens": 1818,
"estimatedLatencyMs": 1200,
"estimatedOutputTokens": 1200,
"estimatedToolCalls": 1,
"name": "generate"
}
],
"strategy_version": "research-dry-run-planner-v1"
}