Skip to main content
POST
/
api
/
v1
/
simulations
Create a simulation
curl --request POST \
  --url https://{subdomain}.mihu.ai/api/v1/simulations \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "name": "booking-flow-voice",
  "agent_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "test_cases": [
    {
      "title": "Reserves a seat with a valid ticket",
      "criteria": [
        "<string>"
      ],
      "scenario": "<string>",
      "expected": "<string>"
    }
  ],
  "description": "<string>",
  "personas": [
    {
      "name": "Mehmet Yılmaz",
      "role": "Concert ticket owner who wants a front seat",
      "traits": [
        "<string>"
      ]
    }
  ],
  "runs_per_case": 3,
  "max_turns": 8,
  "pass_threshold": 80,
  "call_mode": "simulated",
  "caller_agent_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "with_intents": false,
  "run": false
}
'
import requests

url = "https://{subdomain}.mihu.ai/api/v1/simulations"

payload = {
"name": "booking-flow-voice",
"agent_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"test_cases": [
{
"title": "Reserves a seat with a valid ticket",
"criteria": ["<string>"],
"scenario": "<string>",
"expected": "<string>"
}
],
"description": "<string>",
"personas": [
{
"name": "Mehmet Yılmaz",
"role": "Concert ticket owner who wants a front seat",
"traits": ["<string>"]
}
],
"runs_per_case": 3,
"max_turns": 8,
"pass_threshold": 80,
"call_mode": "simulated",
"caller_agent_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"with_intents": False,
"run": False
}
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: 'booking-flow-voice',
agent_uuid: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
test_cases: [
{
title: 'Reserves a seat with a valid ticket',
criteria: ['<string>'],
scenario: '<string>',
expected: '<string>'
}
],
description: '<string>',
personas: [
{
name: 'Mehmet Yılmaz',
role: 'Concert ticket owner who wants a front seat',
traits: ['<string>']
}
],
runs_per_case: 3,
max_turns: 8,
pass_threshold: 80,
call_mode: 'simulated',
caller_agent_uuid: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
with_intents: false,
run: false
})
};

fetch('https://{subdomain}.mihu.ai/api/v1/simulations', 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://{subdomain}.mihu.ai/api/v1/simulations",
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' => 'booking-flow-voice',
'agent_uuid' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'test_cases' => [
[
'title' => 'Reserves a seat with a valid ticket',
'criteria' => [
'<string>'
],
'scenario' => '<string>',
'expected' => '<string>'
]
],
'description' => '<string>',
'personas' => [
[
'name' => 'Mehmet Yılmaz',
'role' => 'Concert ticket owner who wants a front seat',
'traits' => [
'<string>'
]
]
],
'runs_per_case' => 3,
'max_turns' => 8,
'pass_threshold' => 80,
'call_mode' => 'simulated',
'caller_agent_uuid' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'with_intents' => false,
'run' => false
]),
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://{subdomain}.mihu.ai/api/v1/simulations"

payload := strings.NewReader("{\n \"name\": \"booking-flow-voice\",\n \"agent_uuid\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"test_cases\": [\n {\n \"title\": \"Reserves a seat with a valid ticket\",\n \"criteria\": [\n \"<string>\"\n ],\n \"scenario\": \"<string>\",\n \"expected\": \"<string>\"\n }\n ],\n \"description\": \"<string>\",\n \"personas\": [\n {\n \"name\": \"Mehmet Yılmaz\",\n \"role\": \"Concert ticket owner who wants a front seat\",\n \"traits\": [\n \"<string>\"\n ]\n }\n ],\n \"runs_per_case\": 3,\n \"max_turns\": 8,\n \"pass_threshold\": 80,\n \"call_mode\": \"simulated\",\n \"caller_agent_uuid\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"with_intents\": false,\n \"run\": false\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://{subdomain}.mihu.ai/api/v1/simulations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"booking-flow-voice\",\n \"agent_uuid\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"test_cases\": [\n {\n \"title\": \"Reserves a seat with a valid ticket\",\n \"criteria\": [\n \"<string>\"\n ],\n \"scenario\": \"<string>\",\n \"expected\": \"<string>\"\n }\n ],\n \"description\": \"<string>\",\n \"personas\": [\n {\n \"name\": \"Mehmet Yılmaz\",\n \"role\": \"Concert ticket owner who wants a front seat\",\n \"traits\": [\n \"<string>\"\n ]\n }\n ],\n \"runs_per_case\": 3,\n \"max_turns\": 8,\n \"pass_threshold\": 80,\n \"call_mode\": \"simulated\",\n \"caller_agent_uuid\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"with_intents\": false,\n \"run\": false\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://{subdomain}.mihu.ai/api/v1/simulations")

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\": \"booking-flow-voice\",\n \"agent_uuid\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"test_cases\": [\n {\n \"title\": \"Reserves a seat with a valid ticket\",\n \"criteria\": [\n \"<string>\"\n ],\n \"scenario\": \"<string>\",\n \"expected\": \"<string>\"\n }\n ],\n \"description\": \"<string>\",\n \"personas\": [\n {\n \"name\": \"Mehmet Yılmaz\",\n \"role\": \"Concert ticket owner who wants a front seat\",\n \"traits\": [\n \"<string>\"\n ]\n }\n ],\n \"runs_per_case\": 3,\n \"max_turns\": 8,\n \"pass_threshold\": 80,\n \"call_mode\": \"simulated\",\n \"caller_agent_uuid\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"with_intents\": false,\n \"run\": false\n}"

response = http.request(request)
puts response.read_body

Authorizations

Authorization
string
header
required

Use a Bearer token to access these API endpoints. Example: "Bearer {your-token}"

Body

application/json
name
string
required

Required. A label for this simulation; shown in the list and on the report.

Example:

"booking-flow-voice"

channel
enum<string>
required

Required. The channel the assistant is tested on; the agent must have it connected (see /options).

Available options:
voice,
sms,
whatsapp,
whatsapp_call,
email,
instagram,
messenger
agent_uuid
string<uuid>
required

Required. The agent being tested; must have the chosen channel connected (422 otherwise).

test_cases
object[]
required

Required, at least one. Each is one scenario the assistant is scored against.

Minimum array length: 1
description
string | null

Optional. Free-text note about what this simulation verifies.

personas
object[] | null

Optional. The simulated customers. Omit to auto-generate them from the test cases at run time.

runs_per_case
integer
default:3

Optional. How many conversations to run per test case; criteria resolve by majority across them. Default 3.

Required range: 1 <= x <= 20
max_turns
integer
default:8

Optional. Max customer turns per conversation. Use 3-4 for smoke tests, 6-10 for discovery/booking flows. Default 8.

Required range: 2 <= x <= 30
pass_threshold
integer
default:80

Optional. Average score (0-100) at or above which the simulation is 'passed'. Default 80.

Required range: 50 <= x <= 100
call_mode
enum<string>
default:simulated

Voice only. real = the caller line dials the assistant's number with the persona taking over the call

Available options:
simulated,
real
caller_agent_uuid
string<uuid> | null

Required for call_mode=real: the agent whose line plays the customer (must differ from agent_uuid and have a phone line)

with_intents
boolean
default:false

The assistant uses its real intent tools; detected intents EXECUTE their events for real

run
boolean
default:false

Queue the simulation immediately after creating it

Response

Created. With run=true check data.state: queued = started; draft = it could not start and message states why (fix, then POST /{uuid}/run)