Submit Turn
Submit a turn in an episode and receive observation, reward, and completion status
curl --request POST \
--url https://labs.tacitintelligence.co/api/v1/episodes/{id}/turns \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"id": "<string>",
"messages": [
{
"content": "<string>",
"tool_calls": [
{
"name": "<string>",
"input": {}
}
]
}
],
"reward_config": {
"quality_weights": {
"success_metrics": 0.5,
"failure_metrics": 0.5,
"best_practices": 0.5,
"rubrics": 0.5,
"discovery": 0.5,
"output_similarity": 0.5,
"decision_match": 0.5
},
"skip_safety_gate": true
}
}
'import requests
url = "https://labs.tacitintelligence.co/api/v1/episodes/{id}/turns"
payload = {
"id": "<string>",
"messages": [
{
"content": "<string>",
"tool_calls": [
{
"name": "<string>",
"input": {}
}
]
}
],
"reward_config": {
"quality_weights": {
"success_metrics": 0.5,
"failure_metrics": 0.5,
"best_practices": 0.5,
"rubrics": 0.5,
"discovery": 0.5,
"output_similarity": 0.5,
"decision_match": 0.5
},
"skip_safety_gate": True
}
}
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({
id: '<string>',
messages: [{content: '<string>', tool_calls: [{name: '<string>', input: {}}]}],
reward_config: {
quality_weights: {
success_metrics: 0.5,
failure_metrics: 0.5,
best_practices: 0.5,
rubrics: 0.5,
discovery: 0.5,
output_similarity: 0.5,
decision_match: 0.5
},
skip_safety_gate: true
}
})
};
fetch('https://labs.tacitintelligence.co/api/v1/episodes/{id}/turns', 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://labs.tacitintelligence.co/api/v1/episodes/{id}/turns",
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([
'id' => '<string>',
'messages' => [
[
'content' => '<string>',
'tool_calls' => [
[
'name' => '<string>',
'input' => [
]
]
]
]
],
'reward_config' => [
'quality_weights' => [
'success_metrics' => 0.5,
'failure_metrics' => 0.5,
'best_practices' => 0.5,
'rubrics' => 0.5,
'discovery' => 0.5,
'output_similarity' => 0.5,
'decision_match' => 0.5
],
'skip_safety_gate' => true
]
]),
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://labs.tacitintelligence.co/api/v1/episodes/{id}/turns"
payload := strings.NewReader("{\n \"id\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"tool_calls\": [\n {\n \"name\": \"<string>\",\n \"input\": {}\n }\n ]\n }\n ],\n \"reward_config\": {\n \"quality_weights\": {\n \"success_metrics\": 0.5,\n \"failure_metrics\": 0.5,\n \"best_practices\": 0.5,\n \"rubrics\": 0.5,\n \"discovery\": 0.5,\n \"output_similarity\": 0.5,\n \"decision_match\": 0.5\n },\n \"skip_safety_gate\": true\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://labs.tacitintelligence.co/api/v1/episodes/{id}/turns")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"id\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"tool_calls\": [\n {\n \"name\": \"<string>\",\n \"input\": {}\n }\n ]\n }\n ],\n \"reward_config\": {\n \"quality_weights\": {\n \"success_metrics\": 0.5,\n \"failure_metrics\": 0.5,\n \"best_practices\": 0.5,\n \"rubrics\": 0.5,\n \"discovery\": 0.5,\n \"output_similarity\": 0.5,\n \"decision_match\": 0.5\n },\n \"skip_safety_gate\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://labs.tacitintelligence.co/api/v1/episodes/{id}/turns")
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 \"id\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"tool_calls\": [\n {\n \"name\": \"<string>\",\n \"input\": {}\n }\n ]\n }\n ],\n \"reward_config\": {\n \"quality_weights\": {\n \"success_metrics\": 0.5,\n \"failure_metrics\": 0.5,\n \"best_practices\": 0.5,\n \"rubrics\": 0.5,\n \"discovery\": 0.5,\n \"output_similarity\": 0.5,\n \"decision_match\": 0.5\n },\n \"skip_safety_gate\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"turn": 123,
"observation": {
"role": "<string>",
"content": "<string>"
},
"reward": 0.5,
"episode_complete": true,
"scores": {},
"score_breakdown": {}
}{
"error": "<string>",
"details": {}
}Authorizations
API key obtained from Labs Portal
Path Parameters
The episode ID (from path parameter)
Body
The episode ID (from path parameter)
New messages in this turn (user prompt and model response)
Show child attributes
Show child attributes
Per-turn reward configuration. Controls which scorers run and their weights. Omitted quality weight keys default to 0, so only specified scorers execute. Saves tokens during curriculum learning.
Show child attributes
Show child attributes
Response
Success
Current turn number (1-indexed)
The observation for the next turn
Show child attributes
Show child attributes
Reward score (0 to 1) based on the full conversation so far
0 <= x <= 1Whether the episode has ended
Optional breakdown of individual score dimensions. When omitted, only the combined reward is provided.
Show child attributes
Show child attributes
Textual reasoning per score dimension. Only included for subscriptions with full score access.
Show child attributes
Show child attributes
Reason for episode termination (only present when episode_complete is true)
client_terminated, max_turns_reached, error, completed curl --request POST \
--url https://labs.tacitintelligence.co/api/v1/episodes/{id}/turns \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"id": "<string>",
"messages": [
{
"content": "<string>",
"tool_calls": [
{
"name": "<string>",
"input": {}
}
]
}
],
"reward_config": {
"quality_weights": {
"success_metrics": 0.5,
"failure_metrics": 0.5,
"best_practices": 0.5,
"rubrics": 0.5,
"discovery": 0.5,
"output_similarity": 0.5,
"decision_match": 0.5
},
"skip_safety_gate": true
}
}
'import requests
url = "https://labs.tacitintelligence.co/api/v1/episodes/{id}/turns"
payload = {
"id": "<string>",
"messages": [
{
"content": "<string>",
"tool_calls": [
{
"name": "<string>",
"input": {}
}
]
}
],
"reward_config": {
"quality_weights": {
"success_metrics": 0.5,
"failure_metrics": 0.5,
"best_practices": 0.5,
"rubrics": 0.5,
"discovery": 0.5,
"output_similarity": 0.5,
"decision_match": 0.5
},
"skip_safety_gate": True
}
}
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({
id: '<string>',
messages: [{content: '<string>', tool_calls: [{name: '<string>', input: {}}]}],
reward_config: {
quality_weights: {
success_metrics: 0.5,
failure_metrics: 0.5,
best_practices: 0.5,
rubrics: 0.5,
discovery: 0.5,
output_similarity: 0.5,
decision_match: 0.5
},
skip_safety_gate: true
}
})
};
fetch('https://labs.tacitintelligence.co/api/v1/episodes/{id}/turns', 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://labs.tacitintelligence.co/api/v1/episodes/{id}/turns",
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([
'id' => '<string>',
'messages' => [
[
'content' => '<string>',
'tool_calls' => [
[
'name' => '<string>',
'input' => [
]
]
]
]
],
'reward_config' => [
'quality_weights' => [
'success_metrics' => 0.5,
'failure_metrics' => 0.5,
'best_practices' => 0.5,
'rubrics' => 0.5,
'discovery' => 0.5,
'output_similarity' => 0.5,
'decision_match' => 0.5
],
'skip_safety_gate' => true
]
]),
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://labs.tacitintelligence.co/api/v1/episodes/{id}/turns"
payload := strings.NewReader("{\n \"id\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"tool_calls\": [\n {\n \"name\": \"<string>\",\n \"input\": {}\n }\n ]\n }\n ],\n \"reward_config\": {\n \"quality_weights\": {\n \"success_metrics\": 0.5,\n \"failure_metrics\": 0.5,\n \"best_practices\": 0.5,\n \"rubrics\": 0.5,\n \"discovery\": 0.5,\n \"output_similarity\": 0.5,\n \"decision_match\": 0.5\n },\n \"skip_safety_gate\": true\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://labs.tacitintelligence.co/api/v1/episodes/{id}/turns")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"id\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"tool_calls\": [\n {\n \"name\": \"<string>\",\n \"input\": {}\n }\n ]\n }\n ],\n \"reward_config\": {\n \"quality_weights\": {\n \"success_metrics\": 0.5,\n \"failure_metrics\": 0.5,\n \"best_practices\": 0.5,\n \"rubrics\": 0.5,\n \"discovery\": 0.5,\n \"output_similarity\": 0.5,\n \"decision_match\": 0.5\n },\n \"skip_safety_gate\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://labs.tacitintelligence.co/api/v1/episodes/{id}/turns")
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 \"id\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"tool_calls\": [\n {\n \"name\": \"<string>\",\n \"input\": {}\n }\n ]\n }\n ],\n \"reward_config\": {\n \"quality_weights\": {\n \"success_metrics\": 0.5,\n \"failure_metrics\": 0.5,\n \"best_practices\": 0.5,\n \"rubrics\": 0.5,\n \"discovery\": 0.5,\n \"output_similarity\": 0.5,\n \"decision_match\": 0.5\n },\n \"skip_safety_gate\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"turn": 123,
"observation": {
"role": "<string>",
"content": "<string>"
},
"reward": 0.5,
"episode_complete": true,
"scores": {},
"score_breakdown": {}
}{
"error": "<string>",
"details": {}
}