curl --request POST \
--url https://api.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"persona": {
"label": "بے صبرا گاہک",
"behavior": "Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.",
"path": "negative"
},
"context": "Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.",
"variables": {
"name": "عائشہ صدیقی",
"city": "لاہور",
"dream": "پانی میں چلنے کا خواب"
}
}
'import requests
url = "https://api.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate"
payload = {
"persona": {
"label": "بے صبرا گاہک",
"behavior": "Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.",
"path": "negative"
},
"context": "Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.",
"variables": {
"name": "عائشہ صدیقی",
"city": "لاہور",
"dream": "پانی میں چلنے کا خواب"
}
}
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({
persona: {
label: 'بے صبرا گاہک',
behavior: 'Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.',
path: 'negative'
},
context: 'Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.',
variables: {name: 'عائشہ صدیقی', city: 'لاہور', dream: 'پانی میں چلنے کا خواب'}
})
};
fetch('https://api.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate', 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.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate",
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([
'persona' => [
'label' => 'بے صبرا گاہک',
'behavior' => 'Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.',
'path' => 'negative'
],
'context' => 'Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.',
'variables' => [
'name' => 'عائشہ صدیقی',
'city' => 'لاہور',
'dream' => 'پانی میں چلنے کا خواب'
]
]),
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.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate"
payload := strings.NewReader("{\n \"persona\": {\n \"label\": \"بے صبرا گاہک\",\n \"behavior\": \"Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.\",\n \"path\": \"negative\"\n },\n \"context\": \"Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.\",\n \"variables\": {\n \"name\": \"عائشہ صدیقی\",\n \"city\": \"لاہور\",\n \"dream\": \"پانی میں چلنے کا خواب\"\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.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"persona\": {\n \"label\": \"بے صبرا گاہک\",\n \"behavior\": \"Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.\",\n \"path\": \"negative\"\n },\n \"context\": \"Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.\",\n \"variables\": {\n \"name\": \"عائشہ صدیقی\",\n \"city\": \"لاہور\",\n \"dream\": \"پانی میں چلنے کا خواب\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate")
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 \"persona\": {\n \"label\": \"بے صبرا گاہک\",\n \"behavior\": \"Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.\",\n \"path\": \"negative\"\n },\n \"context\": \"Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.\",\n \"variables\": {\n \"name\": \"عائشہ صدیقی\",\n \"city\": \"لاہور\",\n \"dream\": \"پانی میں چلنے کا خواب\"\n }\n}"
response = http.request(request)
puts response.read_body"event: turn\ndata: {\"index\":1,\"role\":\"agent\",\"text\":\"السلام علیکم، میں خواب کلینک سے ڈاکٹر عامرہ بات کر رہی ہوں۔\"}\n\nevent: turn\ndata: {\"index\":2,\"role\":\"caller\",\"text\":\"جی، کون؟ آپ کو میرا نمبر کہاں سے ملا؟\"}\n\nevent: done\ndata: {\"personaId\":\"b8bed320-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\"personaLabel\":\"بے صبرا گاہک\",\"archetype\":\"happy\",\"path\":\"negative\",\"turns\":[{\"speaker\":\"agent\",\"text\":\"السلام علیکم، میں خواب کلینک سے ڈاکٹر عامرہ بات کر رہی ہوں۔\"},{\"speaker\":\"caller\",\"text\":\"جی، کون؟ آپ کو میرا نمبر کہاں سے ملا؟\"}]}\n"Rehearse a call against a persona
Text-only: no call is placed, and it runs whatever prompt the assistant has saved right now, on the assistant’s own LLM provider, model, and generation settings. Despite the builds path, it works on any assistant — built or hand-written.
Three inputs aim the simulation:
persona— who answers.behaviorgoes verbatim into the caller model’s system prompt;pathdefaults tonegative, because the uncooperative arc is where prompts break.context— the scene: what the caller already knows about who is calling and why. Omit it to fall back to the build brief’s context; with neither, the caller answers like a genuine cold call.variables— the customer record for this one call, same asvariableson a real outbound call. Both sides see it: the agent substitutes its tokens, the caller answers consistently with it.
Anything wrong with the setup — an unsupported provider, a bad body — fails as a plain JSON 400 before any streaming starts. Seen enough mid-conversation? Just disconnect: the run stops server-side, and so does the spend.
curl --request POST \
--url https://api.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"persona": {
"label": "بے صبرا گاہک",
"behavior": "Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.",
"path": "negative"
},
"context": "Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.",
"variables": {
"name": "عائشہ صدیقی",
"city": "لاہور",
"dream": "پانی میں چلنے کا خواب"
}
}
'import requests
url = "https://api.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate"
payload = {
"persona": {
"label": "بے صبرا گاہک",
"behavior": "Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.",
"path": "negative"
},
"context": "Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.",
"variables": {
"name": "عائشہ صدیقی",
"city": "لاہور",
"dream": "پانی میں چلنے کا خواب"
}
}
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({
persona: {
label: 'بے صبرا گاہک',
behavior: 'Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.',
path: 'negative'
},
context: 'Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.',
variables: {name: 'عائشہ صدیقی', city: 'لاہور', dream: 'پانی میں چلنے کا خواب'}
})
};
fetch('https://api.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate', 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.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate",
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([
'persona' => [
'label' => 'بے صبرا گاہک',
'behavior' => 'Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.',
'path' => 'negative'
],
'context' => 'Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.',
'variables' => [
'name' => 'عائشہ صدیقی',
'city' => 'لاہور',
'dream' => 'پانی میں چلنے کا خواب'
]
]),
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.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate"
payload := strings.NewReader("{\n \"persona\": {\n \"label\": \"بے صبرا گاہک\",\n \"behavior\": \"Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.\",\n \"path\": \"negative\"\n },\n \"context\": \"Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.\",\n \"variables\": {\n \"name\": \"عائشہ صدیقی\",\n \"city\": \"لاہور\",\n \"dream\": \"پانی میں چلنے کا خواب\"\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.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"persona\": {\n \"label\": \"بے صبرا گاہک\",\n \"behavior\": \"Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.\",\n \"path\": \"negative\"\n },\n \"context\": \"Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.\",\n \"variables\": {\n \"name\": \"عائشہ صدیقی\",\n \"city\": \"لاہور\",\n \"dream\": \"پانی میں چلنے کا خواب\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.upliftai.org/v1/realtime-assistants/builds/{assistantId}/simulate")
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 \"persona\": {\n \"label\": \"بے صبرا گاہک\",\n \"behavior\": \"Interrupts early, demands to know who is calling and where they got the number, and hangs up if the answer is vague.\",\n \"path\": \"negative\"\n },\n \"context\": \"Khwab Clinic, Lahore. You booked a dream-interpretation session last week and the clinic is calling back to walk you through the dream you submitted.\",\n \"variables\": {\n \"name\": \"عائشہ صدیقی\",\n \"city\": \"لاہور\",\n \"dream\": \"پانی میں چلنے کا خواب\"\n }\n}"
response = http.request(request)
puts response.read_body"event: turn\ndata: {\"index\":1,\"role\":\"agent\",\"text\":\"السلام علیکم، میں خواب کلینک سے ڈاکٹر عامرہ بات کر رہی ہوں۔\"}\n\nevent: turn\ndata: {\"index\":2,\"role\":\"caller\",\"text\":\"جی، کون؟ آپ کو میرا نمبر کہاں سے ملا؟\"}\n\nevent: done\ndata: {\"personaId\":\"b8bed320-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\"personaLabel\":\"بے صبرا گاہک\",\"archetype\":\"happy\",\"path\":\"negative\",\"turns\":[{\"speaker\":\"agent\",\"text\":\"السلام علیکم، میں خواب کلینک سے ڈاکٹر عامرہ بات کر رہی ہوں۔\"},{\"speaker\":\"caller\",\"text\":\"جی، کون؟ آپ کو میرا نمبر کہاں سے ملا؟\"}]}\n"Authorizations
Project API key (sk_api_…).
Path Parameters
The assistant to rehearse.
Body
Who picks up. Kept separate from context and variables so one persona can be re-run across scenarios and contacts.
Show child attributes
Show child attributes
What the person picking up knows about who is ringing them and why. Overrides the context in the assistant's stored brief; with neither, they go in cold.
8000The contact record for this one simulated call, handed to the agent under test as its caller record. Falls back to the first sampleRows entry of the stored brief. Keys are at most 64 characters, and the whole object under 3000 characters of JSON.
Show child attributes
Show child attributes
Response
An event stream, not a JSON body. It looks like this on the wire:
event: turn
data: {"index":1,"role":"agent","text":"السلام علیکم، میں شفا کلینک سے ثناء بات کر رہی ہوں۔"}
: ping
event: turn
data: {"index":2,"role":"caller","text":"جی، کون؟ آپ کو میرا نمبر کہاں سے ملا؟"}
event: done
data: {"personaId":"b8bed320-…","personaLabel":"بے صبرا گاہک","archetype":"happy","path":"negative","turns":[…]}
turncarries{index, role, text}—indexis 1-based speaking order,roleisagentorcaller.- Exactly one terminal event ends the stream:
donewith the whole transcript, orerrorwith a{message}— a conversation that broke mid-flight, or one that hit the five-minute ceiling. - Either side can end the conversation, and the caller often does — don't assume the transcript ends on the agent's closing line.
- On
done,personaIdis minted for this run andarchetypeis alwayshappy, whateverpathyou sent. : pingkeepalives arrive every 15 seconds; SSE parsers drop them.- A stream that ends with neither terminal event is a dropped connection — there is no resume, so run it again.
The response is of type string.
