Experiments
Create experiment
POST
/
api
/
v2
/
experiments
/
Create experiment
curl --request POST \
--url https://api.keywordsai.co/api/v2/experiments/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"description": "<string>",
"dataset_id": "<string>",
"workflows": [
{
"type": "<string>",
"config": {
"allow_submission": true,
"timeout_hours": 123,
"model": "<string>",
"temperature": 123,
"max_tokens": 123,
"top_p": 123,
"frequency_penalty": 123,
"presence_penalty": 123,
"stop": {},
"response_format": {},
"tools": [
{}
],
"tool_choice": {},
"reasoning_effort": "<string>",
"prompt_id": "<string>"
}
}
],
"evaluator_slugs": [
{}
]
}
'import requests
url = "https://api.keywordsai.co/api/v2/experiments/"
payload = {
"name": "<string>",
"description": "<string>",
"dataset_id": "<string>",
"workflows": [
{
"type": "<string>",
"config": {
"allow_submission": True,
"timeout_hours": 123,
"model": "<string>",
"temperature": 123,
"max_tokens": 123,
"top_p": 123,
"frequency_penalty": 123,
"presence_penalty": 123,
"stop": {},
"response_format": {},
"tools": [{}],
"tool_choice": {},
"reasoning_effort": "<string>",
"prompt_id": "<string>"
}
}
],
"evaluator_slugs": [{}]
}
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({
name: '<string>',
description: '<string>',
dataset_id: '<string>',
workflows: [
{
type: '<string>',
config: {
allow_submission: true,
timeout_hours: 123,
model: '<string>',
temperature: 123,
max_tokens: 123,
top_p: 123,
frequency_penalty: 123,
presence_penalty: 123,
stop: {},
response_format: {},
tools: [{}],
tool_choice: {},
reasoning_effort: '<string>',
prompt_id: '<string>'
}
}
],
evaluator_slugs: [{}]
})
};
fetch('https://api.keywordsai.co/api/v2/experiments/', 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.keywordsai.co/api/v2/experiments/",
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([
'name' => '<string>',
'description' => '<string>',
'dataset_id' => '<string>',
'workflows' => [
[
'type' => '<string>',
'config' => [
'allow_submission' => true,
'timeout_hours' => 123,
'model' => '<string>',
'temperature' => 123,
'max_tokens' => 123,
'top_p' => 123,
'frequency_penalty' => 123,
'presence_penalty' => 123,
'stop' => [
],
'response_format' => [
],
'tools' => [
[
]
],
'tool_choice' => [
],
'reasoning_effort' => '<string>',
'prompt_id' => '<string>'
]
]
],
'evaluator_slugs' => [
[
]
]
]),
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.keywordsai.co/api/v2/experiments/"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"dataset_id\": \"<string>\",\n \"workflows\": [\n {\n \"type\": \"<string>\",\n \"config\": {\n \"allow_submission\": true,\n \"timeout_hours\": 123,\n \"model\": \"<string>\",\n \"temperature\": 123,\n \"max_tokens\": 123,\n \"top_p\": 123,\n \"frequency_penalty\": 123,\n \"presence_penalty\": 123,\n \"stop\": {},\n \"response_format\": {},\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"reasoning_effort\": \"<string>\",\n \"prompt_id\": \"<string>\"\n }\n }\n ],\n \"evaluator_slugs\": [\n {}\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.keywordsai.co/api/v2/experiments/")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"dataset_id\": \"<string>\",\n \"workflows\": [\n {\n \"type\": \"<string>\",\n \"config\": {\n \"allow_submission\": true,\n \"timeout_hours\": 123,\n \"model\": \"<string>\",\n \"temperature\": 123,\n \"max_tokens\": 123,\n \"top_p\": 123,\n \"frequency_penalty\": 123,\n \"presence_penalty\": 123,\n \"stop\": {},\n \"response_format\": {},\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"reasoning_effort\": \"<string>\",\n \"prompt_id\": \"<string>\"\n }\n }\n ],\n \"evaluator_slugs\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.keywordsai.co/api/v2/experiments/")
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 \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"dataset_id\": \"<string>\",\n \"workflows\": [\n {\n \"type\": \"<string>\",\n \"config\": {\n \"allow_submission\": true,\n \"timeout_hours\": 123,\n \"model\": \"<string>\",\n \"temperature\": 123,\n \"max_tokens\": 123,\n \"top_p\": 123,\n \"frequency_penalty\": 123,\n \"presence_penalty\": 123,\n \"stop\": {},\n \"response_format\": {},\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"reasoning_effort\": \"<string>\",\n \"prompt_id\": \"<string>\"\n }\n }\n ],\n \"evaluator_slugs\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_bodyCreates a new experiment with workflows. Supports three workflow types:
- Custom: Submit your own workflow results via API
- Completion: Direct LLM completions with custom parameters
- Prompt: Load and render Jinja2 prompt templates with dataset variables
Authentication
All endpoints require API key authentication:Authorization: Bearer YOUR_API_KEY
Parameters
string
required
The name of the experiment.
string
Description of the experiment.
string
required
The ID of the dataset to run the experiment on.
array
required
List of workflow configurations.
Properties
Properties
string
required
Type of workflow. Options:
custom, completion, or prompt.custom: Submit your own workflow resultscompletion: Direct LLM completionsprompt: Load and render Jinja2 prompt templates
object
Configuration for the workflow. Structure depends on workflow type:
Custom Workflow Config
Custom Workflow Config
Completion Workflow Config
Completion Workflow Config
string
required
Model identifier (e.g., “gpt-4o-mini”).
number
Sampling temperature (0-2, default: 1.0).
integer
Maximum completion tokens (default: 150).
number
Nucleus sampling (0-1, default: 1.0).
number
Frequency penalty (-2 to 2, default: 0).
number
Presence penalty (-2 to 2, default: 0).
string or array
Stop sequences.
object
Response format (e.g.,
{"type": "json_object"}).array
Function calling tools.
string or object
Tool choice strategy.
string
Reasoning effort for o1 models.
Prompt Workflow Config
Prompt Workflow Config
string
required
Prompt identifier to load and render.
array
List of evaluator slugs to run on the experiment results.
Response
{
"id": "experiment-123",
"name": "My Custom Workflow Experiment",
"description": "Testing custom workflow implementation",
"dataset_id": "your-dataset-id",
"workflows": [
{
"type": "custom",
"config": {
"allow_submission": true,
"timeout_hours": 24
}
}
],
"evaluator_slugs": [
"response_quality_v1",
"factual_accuracy"
],
"status": "running",
"created_at": "2025-11-18T10:00:00Z",
"updated_at": "2025-11-18T10:00:00Z"
}
Examples
Custom Workflow
curl -X POST "https://api.keywordsai.co/api/v2/experiments/" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Custom Processing Experiment",
"dataset_id": "dataset-123",
"workflows": [{"type": "custom", "config": {"allow_submission": true}}],
"evaluator_slugs": ["response_quality_v1"]
}'
Completion Workflow
curl -X POST "https://api.keywordsai.co/api/v2/experiments/" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Completion Experiment",
"dataset_id": "dataset-123",
"workflows": [{
"type": "completion",
"config": {
"model": "gpt-4o-mini",
"temperature": 0.7,
"max_tokens": 150
}
}],
"evaluator_slugs": ["response_quality_v1"]
}'
Prompt Workflow
curl -X POST "https://api.keywordsai.co/api/v2/experiments/" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Prompt Experiment",
"dataset_id": "dataset-123",
"workflows": [{
"type": "prompt",
"config": {
"prompt_id": "6caa11b48d4d440986b3eb3b96ae795e"
}
}],
"evaluator_slugs": ["response_quality_v1"]
}'
Workflow Rules
✅ Valid Combinations:- Single custom workflow
- Single built-in workflow (prompt or completion)
- Multiple built-in workflows chained together
- Multiple custom workflows
- Custom workflow + built-in workflow
- Mixing custom and built-in types
Was this page helpful?
⌘I
Create experiment
curl --request POST \
--url https://api.keywordsai.co/api/v2/experiments/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"description": "<string>",
"dataset_id": "<string>",
"workflows": [
{
"type": "<string>",
"config": {
"allow_submission": true,
"timeout_hours": 123,
"model": "<string>",
"temperature": 123,
"max_tokens": 123,
"top_p": 123,
"frequency_penalty": 123,
"presence_penalty": 123,
"stop": {},
"response_format": {},
"tools": [
{}
],
"tool_choice": {},
"reasoning_effort": "<string>",
"prompt_id": "<string>"
}
}
],
"evaluator_slugs": [
{}
]
}
'import requests
url = "https://api.keywordsai.co/api/v2/experiments/"
payload = {
"name": "<string>",
"description": "<string>",
"dataset_id": "<string>",
"workflows": [
{
"type": "<string>",
"config": {
"allow_submission": True,
"timeout_hours": 123,
"model": "<string>",
"temperature": 123,
"max_tokens": 123,
"top_p": 123,
"frequency_penalty": 123,
"presence_penalty": 123,
"stop": {},
"response_format": {},
"tools": [{}],
"tool_choice": {},
"reasoning_effort": "<string>",
"prompt_id": "<string>"
}
}
],
"evaluator_slugs": [{}]
}
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({
name: '<string>',
description: '<string>',
dataset_id: '<string>',
workflows: [
{
type: '<string>',
config: {
allow_submission: true,
timeout_hours: 123,
model: '<string>',
temperature: 123,
max_tokens: 123,
top_p: 123,
frequency_penalty: 123,
presence_penalty: 123,
stop: {},
response_format: {},
tools: [{}],
tool_choice: {},
reasoning_effort: '<string>',
prompt_id: '<string>'
}
}
],
evaluator_slugs: [{}]
})
};
fetch('https://api.keywordsai.co/api/v2/experiments/', 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.keywordsai.co/api/v2/experiments/",
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([
'name' => '<string>',
'description' => '<string>',
'dataset_id' => '<string>',
'workflows' => [
[
'type' => '<string>',
'config' => [
'allow_submission' => true,
'timeout_hours' => 123,
'model' => '<string>',
'temperature' => 123,
'max_tokens' => 123,
'top_p' => 123,
'frequency_penalty' => 123,
'presence_penalty' => 123,
'stop' => [
],
'response_format' => [
],
'tools' => [
[
]
],
'tool_choice' => [
],
'reasoning_effort' => '<string>',
'prompt_id' => '<string>'
]
]
],
'evaluator_slugs' => [
[
]
]
]),
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.keywordsai.co/api/v2/experiments/"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"dataset_id\": \"<string>\",\n \"workflows\": [\n {\n \"type\": \"<string>\",\n \"config\": {\n \"allow_submission\": true,\n \"timeout_hours\": 123,\n \"model\": \"<string>\",\n \"temperature\": 123,\n \"max_tokens\": 123,\n \"top_p\": 123,\n \"frequency_penalty\": 123,\n \"presence_penalty\": 123,\n \"stop\": {},\n \"response_format\": {},\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"reasoning_effort\": \"<string>\",\n \"prompt_id\": \"<string>\"\n }\n }\n ],\n \"evaluator_slugs\": [\n {}\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.keywordsai.co/api/v2/experiments/")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"dataset_id\": \"<string>\",\n \"workflows\": [\n {\n \"type\": \"<string>\",\n \"config\": {\n \"allow_submission\": true,\n \"timeout_hours\": 123,\n \"model\": \"<string>\",\n \"temperature\": 123,\n \"max_tokens\": 123,\n \"top_p\": 123,\n \"frequency_penalty\": 123,\n \"presence_penalty\": 123,\n \"stop\": {},\n \"response_format\": {},\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"reasoning_effort\": \"<string>\",\n \"prompt_id\": \"<string>\"\n }\n }\n ],\n \"evaluator_slugs\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.keywordsai.co/api/v2/experiments/")
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 \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"dataset_id\": \"<string>\",\n \"workflows\": [\n {\n \"type\": \"<string>\",\n \"config\": {\n \"allow_submission\": true,\n \"timeout_hours\": 123,\n \"model\": \"<string>\",\n \"temperature\": 123,\n \"max_tokens\": 123,\n \"top_p\": 123,\n \"frequency_penalty\": 123,\n \"presence_penalty\": 123,\n \"stop\": {},\n \"response_format\": {},\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"reasoning_effort\": \"<string>\",\n \"prompt_id\": \"<string>\"\n }\n }\n ],\n \"evaluator_slugs\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body