curl --request POST \
--url https://api.dualmindlab.tech/api/arena/dualchat \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"prompt": "Write a haiku about distributed systems"
}
'import requests
url = "https://api.dualmindlab.tech/api/arena/dualchat"
payload = { "prompt": "Write a haiku about distributed systems" }
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({prompt: 'Write a haiku about distributed systems'})
};
fetch('https://api.dualmindlab.tech/api/arena/dualchat', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({prompt: 'Write a haiku about distributed systems'})
};
fetch('https://api.dualmindlab.tech/api/arena/dualchat', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.dualmindlab.tech/api/arena/dualchat"
payload := strings.NewReader("{\n \"prompt\": \"Write a haiku about distributed systems\"\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))
}using RestSharp;
var options = new RestClientOptions("https://api.dualmindlab.tech/api/arena/dualchat");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("Authorization", "Bearer <token>");
request.AddJsonBody("{\n \"prompt\": \"Write a haiku about distributed systems\"\n}", false);
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);
HttpResponse<String> response = Unirest.post("https://api.dualmindlab.tech/api/arena/dualchat")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"Write a haiku about distributed systems\"\n}")
.asString();{
"success": true,
"agent1": {
"object": "ai.response",
"output": {
"type": "message",
"content": [
{
"type": "output_text",
"text": "Packets cross the sea / two clocks disagree on now / quorum settles it"
}
]
},
"success": true,
"message": "Packets cross the sea / two clocks disagree on now / quorum settles it",
"model": {
"name": "llama-3.3-70b-versatile",
"displayName": "Llama 3.3 70B Versatile",
"provider": "groq"
},
"prompt": "Write a haiku about distributed systems",
"selectionMode": "random",
"responseTimeMs": 1880,
"usage": {
"promptTokens": 9,
"completionTokens": 19,
"totalTokens": 28
},
"timestamp": "2026-10-17T12:00:00Z"
},
"agent2": {
"object": "ai.response",
"output": {
"type": "message",
"content": [
{
"type": "output_text",
"text": "Nodes drift apart / consensus is a rumour / the log remembers"
}
]
},
"success": true,
"message": "Nodes drift apart / consensus is a rumour / the log remembers",
"model": {
"name": "gemini-2.5-flash",
"displayName": "Gemini 2.5 Flash",
"provider": "google"
},
"prompt": "Write a haiku about distributed systems",
"selectionMode": "random",
"responseTimeMs": 1880,
"usage": {
"promptTokens": 9,
"completionTokens": 17,
"totalTokens": 26
},
"timestamp": "2026-10-17T12:00:00Z"
},
"comparisonId": "3f6c1a2b-9d4e-4f7a-8b1c-0e2d3f4a5b6c",
"arena": {
"comparison": {
"winnerByLength": "agent1",
"winnerByTokens": "agent1",
"verdict": "Agent 1 produced the longer, more token-heavy answer.",
"agent1MessageLength": 70,
"agent2MessageLength": 61,
"agent1Tokens": 28,
"agent2Tokens": 26
},
"models": {
"agent1": "llama-3.3-70b-versatile",
"agent2": "gemini-2.5-flash"
}
},
"timestamp": "2026-10-17T12:00:02Z",
"totalResponseTimeMs": 1880
}{
"object": "ai.error",
"code": "INVALID_REQUEST",
"message": "Prompt is required and cannot be empty",
"timestamp": "2026-10-17T12:00:00Z"
}{
"object": "ai.error",
"code": "INVALID_REQUEST",
"message": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}Start a battle
Send one prompt to two models in parallel and get both answers plus a comparisonId to vote with. Leave model1/model2 empty for a blind Battle (random or topper), or set both for Side by Side.
curl --request POST \
--url https://api.dualmindlab.tech/api/arena/dualchat \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"prompt": "Write a haiku about distributed systems"
}
'import requests
url = "https://api.dualmindlab.tech/api/arena/dualchat"
payload = { "prompt": "Write a haiku about distributed systems" }
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({prompt: 'Write a haiku about distributed systems'})
};
fetch('https://api.dualmindlab.tech/api/arena/dualchat', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({prompt: 'Write a haiku about distributed systems'})
};
fetch('https://api.dualmindlab.tech/api/arena/dualchat', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.dualmindlab.tech/api/arena/dualchat"
payload := strings.NewReader("{\n \"prompt\": \"Write a haiku about distributed systems\"\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))
}using RestSharp;
var options = new RestClientOptions("https://api.dualmindlab.tech/api/arena/dualchat");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("Authorization", "Bearer <token>");
request.AddJsonBody("{\n \"prompt\": \"Write a haiku about distributed systems\"\n}", false);
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);
HttpResponse<String> response = Unirest.post("https://api.dualmindlab.tech/api/arena/dualchat")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"Write a haiku about distributed systems\"\n}")
.asString();{
"success": true,
"agent1": {
"object": "ai.response",
"output": {
"type": "message",
"content": [
{
"type": "output_text",
"text": "Packets cross the sea / two clocks disagree on now / quorum settles it"
}
]
},
"success": true,
"message": "Packets cross the sea / two clocks disagree on now / quorum settles it",
"model": {
"name": "llama-3.3-70b-versatile",
"displayName": "Llama 3.3 70B Versatile",
"provider": "groq"
},
"prompt": "Write a haiku about distributed systems",
"selectionMode": "random",
"responseTimeMs": 1880,
"usage": {
"promptTokens": 9,
"completionTokens": 19,
"totalTokens": 28
},
"timestamp": "2026-10-17T12:00:00Z"
},
"agent2": {
"object": "ai.response",
"output": {
"type": "message",
"content": [
{
"type": "output_text",
"text": "Nodes drift apart / consensus is a rumour / the log remembers"
}
]
},
"success": true,
"message": "Nodes drift apart / consensus is a rumour / the log remembers",
"model": {
"name": "gemini-2.5-flash",
"displayName": "Gemini 2.5 Flash",
"provider": "google"
},
"prompt": "Write a haiku about distributed systems",
"selectionMode": "random",
"responseTimeMs": 1880,
"usage": {
"promptTokens": 9,
"completionTokens": 17,
"totalTokens": 26
},
"timestamp": "2026-10-17T12:00:00Z"
},
"comparisonId": "3f6c1a2b-9d4e-4f7a-8b1c-0e2d3f4a5b6c",
"arena": {
"comparison": {
"winnerByLength": "agent1",
"winnerByTokens": "agent1",
"verdict": "Agent 1 produced the longer, more token-heavy answer.",
"agent1MessageLength": 70,
"agent2MessageLength": 61,
"agent1Tokens": 28,
"agent2Tokens": 26
},
"models": {
"agent1": "llama-3.3-70b-versatile",
"agent2": "gemini-2.5-flash"
}
},
"timestamp": "2026-10-17T12:00:02Z",
"totalResponseTimeMs": 1880
}{
"object": "ai.error",
"code": "INVALID_REQUEST",
"message": "Prompt is required and cannot be empty",
"timestamp": "2026-10-17T12:00:00Z"
}{
"object": "ai.error",
"code": "INVALID_REQUEST",
"message": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}agent1.model, agent2.model and arena.models so you can reveal names after a vote. Keep them hidden from voters until they vote, as the Arena does. See Run a battle.| You want | Send |
|---|---|
| A blind random battle | prompt only (or selectionMode: "random") |
| The leader vs a challenger | selectionMode: "topper" |
| Two models you choose (Side by Side) | model1 and model2 |
| To save it in a thread | threadId of a thread you own |
message starts with [System Note]. Use a client timeout of at least 120 seconds.Authorizations
The access token from your DualMind Arena session (a Supabase JWT). See Authentication.
Body
The prompt both models answer. Must not be empty.
"Write a haiku about distributed systems"
How the two models are picked when model1 and model2 are not set. random: two different random models. topper: the model with the best win rate against a random challenger.
random, topper Left model (modelName or modelId). Set both model1 and model2 for a Side by Side comparison; setting only one is an error.
Right model (modelName or modelId).
Optional system prompt sent to both models.
Maximum tokens per response.
x >= 1Sampling temperature for both models.
0 <= x <= 2Save this battle to a thread you own.
Response
Both responses and the comparison ID.
Pass this to POST /api/arena/model-vote.
Left response (vote left).
Show child attributes
Show child attributes
Right response (vote right).
Show child attributes
Show child attributes
Simple length and token heuristics plus the model names. Clients that want a blind experience should keep model names hidden until the user votes, as the Arena does.
Show child attributes
Show child attributes