curl --request POST \
--url https://api.usetuner.ai/api/v1/public/call \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"call_id": "<string>",
"call_type": "<string>",
"transcript_with_tool_calls": [
{
"text": "<string>",
"words": [
{
"word": "<string>",
"start_ms": 123,
"end_ms": 123,
"confidence": 123
}
],
"start_ms": 123,
"end_ms": 123,
"duration_ms": 123,
"node": {
"to": "<string>",
"from": "<string>",
"reason": "<string>"
},
"tool": {
"name": "<string>",
"request_id": "<string>",
"params": {},
"result": {},
"is_error": true,
"error": "<string>",
"start_ms": 123,
"end_ms": 123
},
"metadata": {
"e2e_latency": 123,
"interrupted": true,
"llm_node_ttft": 123,
"tts_node_ttfb": 123,
"transcript_confidence": 123,
"stt_node_ttfb": 123,
"eou_delay": 123
}
}
],
"start_timestamp": 123,
"end_timestamp": 123,
"recording_url": "<string>",
"sip_call_id": "<string>",
"recipient": "<string>",
"agent_version": 1,
"transcript": "<string>",
"duration_ms": 123,
"call_status": "<string>",
"disconnection_reason": "<string>",
"caller_phone_number": "<string>",
"call_successful": true,
"user_sentiment": "<string>",
"in_voicemail": true,
"collected_dynamic_variables": {},
"call_cost": 123,
"call_analysis": {},
"metadata": {
"ai_models": {
"asr_model": "<string>",
"llm_model": "<string>",
"tts_model": "<string>"
},
"usage_token": {
"stt_duration_seconds": 123,
"llm_token": 123,
"tts_characters_count": 123
}
},
"general_meta_data_raw": {},
"recording_multi_channel_url": "<string>",
"recording_file_extension": "<string>",
"recording_s3_multi_channel": true,
"recording_s3_caller_channel": 1
}
'import requests
url = "https://api.usetuner.ai/api/v1/public/call"
payload = {
"call_id": "<string>",
"call_type": "<string>",
"transcript_with_tool_calls": [
{
"text": "<string>",
"words": [
{
"word": "<string>",
"start_ms": 123,
"end_ms": 123,
"confidence": 123
}
],
"start_ms": 123,
"end_ms": 123,
"duration_ms": 123,
"node": {
"to": "<string>",
"from": "<string>",
"reason": "<string>"
},
"tool": {
"name": "<string>",
"request_id": "<string>",
"params": {},
"result": {},
"is_error": True,
"error": "<string>",
"start_ms": 123,
"end_ms": 123
},
"metadata": {
"e2e_latency": 123,
"interrupted": True,
"llm_node_ttft": 123,
"tts_node_ttfb": 123,
"transcript_confidence": 123,
"stt_node_ttfb": 123,
"eou_delay": 123
}
}
],
"start_timestamp": 123,
"end_timestamp": 123,
"recording_url": "<string>",
"sip_call_id": "<string>",
"recipient": "<string>",
"agent_version": 1,
"transcript": "<string>",
"duration_ms": 123,
"call_status": "<string>",
"disconnection_reason": "<string>",
"caller_phone_number": "<string>",
"call_successful": True,
"user_sentiment": "<string>",
"in_voicemail": True,
"collected_dynamic_variables": {},
"call_cost": 123,
"call_analysis": {},
"metadata": {
"ai_models": {
"asr_model": "<string>",
"llm_model": "<string>",
"tts_model": "<string>"
},
"usage_token": {
"stt_duration_seconds": 123,
"llm_token": 123,
"tts_characters_count": 123
}
},
"general_meta_data_raw": {},
"recording_multi_channel_url": "<string>",
"recording_file_extension": "<string>",
"recording_s3_multi_channel": True,
"recording_s3_caller_channel": 1
}
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({
call_id: '<string>',
call_type: '<string>',
transcript_with_tool_calls: [
{
text: '<string>',
words: [{word: '<string>', start_ms: 123, end_ms: 123, confidence: 123}],
start_ms: 123,
end_ms: 123,
duration_ms: 123,
node: {to: '<string>', from: '<string>', reason: '<string>'},
tool: {
name: '<string>',
request_id: '<string>',
params: {},
result: {},
is_error: true,
error: '<string>',
start_ms: 123,
end_ms: 123
},
metadata: {
e2e_latency: 123,
interrupted: true,
llm_node_ttft: 123,
tts_node_ttfb: 123,
transcript_confidence: 123,
stt_node_ttfb: 123,
eou_delay: 123
}
}
],
start_timestamp: 123,
end_timestamp: 123,
recording_url: '<string>',
sip_call_id: '<string>',
recipient: '<string>',
agent_version: 1,
transcript: '<string>',
duration_ms: 123,
call_status: '<string>',
disconnection_reason: '<string>',
caller_phone_number: '<string>',
call_successful: true,
user_sentiment: '<string>',
in_voicemail: true,
collected_dynamic_variables: {},
call_cost: 123,
call_analysis: {},
metadata: {
ai_models: {asr_model: '<string>', llm_model: '<string>', tts_model: '<string>'},
usage_token: {stt_duration_seconds: 123, llm_token: 123, tts_characters_count: 123}
},
general_meta_data_raw: {},
recording_multi_channel_url: '<string>',
recording_file_extension: '<string>',
recording_s3_multi_channel: true,
recording_s3_caller_channel: 1
})
};
fetch('https://api.usetuner.ai/api/v1/public/call', 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.usetuner.ai/api/v1/public/call",
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([
'call_id' => '<string>',
'call_type' => '<string>',
'transcript_with_tool_calls' => [
[
'text' => '<string>',
'words' => [
[
'word' => '<string>',
'start_ms' => 123,
'end_ms' => 123,
'confidence' => 123
]
],
'start_ms' => 123,
'end_ms' => 123,
'duration_ms' => 123,
'node' => [
'to' => '<string>',
'from' => '<string>',
'reason' => '<string>'
],
'tool' => [
'name' => '<string>',
'request_id' => '<string>',
'params' => [
],
'result' => [
],
'is_error' => true,
'error' => '<string>',
'start_ms' => 123,
'end_ms' => 123
],
'metadata' => [
'e2e_latency' => 123,
'interrupted' => true,
'llm_node_ttft' => 123,
'tts_node_ttfb' => 123,
'transcript_confidence' => 123,
'stt_node_ttfb' => 123,
'eou_delay' => 123
]
]
],
'start_timestamp' => 123,
'end_timestamp' => 123,
'recording_url' => '<string>',
'sip_call_id' => '<string>',
'recipient' => '<string>',
'agent_version' => 1,
'transcript' => '<string>',
'duration_ms' => 123,
'call_status' => '<string>',
'disconnection_reason' => '<string>',
'caller_phone_number' => '<string>',
'call_successful' => true,
'user_sentiment' => '<string>',
'in_voicemail' => true,
'collected_dynamic_variables' => [
],
'call_cost' => 123,
'call_analysis' => [
],
'metadata' => [
'ai_models' => [
'asr_model' => '<string>',
'llm_model' => '<string>',
'tts_model' => '<string>'
],
'usage_token' => [
'stt_duration_seconds' => 123,
'llm_token' => 123,
'tts_characters_count' => 123
]
],
'general_meta_data_raw' => [
],
'recording_multi_channel_url' => '<string>',
'recording_file_extension' => '<string>',
'recording_s3_multi_channel' => true,
'recording_s3_caller_channel' => 1
]),
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.usetuner.ai/api/v1/public/call"
payload := strings.NewReader("{\n \"call_id\": \"<string>\",\n \"call_type\": \"<string>\",\n \"transcript_with_tool_calls\": [\n {\n \"text\": \"<string>\",\n \"words\": [\n {\n \"word\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"confidence\": 123\n }\n ],\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"duration_ms\": 123,\n \"node\": {\n \"to\": \"<string>\",\n \"from\": \"<string>\",\n \"reason\": \"<string>\"\n },\n \"tool\": {\n \"name\": \"<string>\",\n \"request_id\": \"<string>\",\n \"params\": {},\n \"result\": {},\n \"is_error\": true,\n \"error\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123\n },\n \"metadata\": {\n \"e2e_latency\": 123,\n \"interrupted\": true,\n \"llm_node_ttft\": 123,\n \"tts_node_ttfb\": 123,\n \"transcript_confidence\": 123,\n \"stt_node_ttfb\": 123,\n \"eou_delay\": 123\n }\n }\n ],\n \"start_timestamp\": 123,\n \"end_timestamp\": 123,\n \"recording_url\": \"<string>\",\n \"sip_call_id\": \"<string>\",\n \"recipient\": \"<string>\",\n \"agent_version\": 1,\n \"transcript\": \"<string>\",\n \"duration_ms\": 123,\n \"call_status\": \"<string>\",\n \"disconnection_reason\": \"<string>\",\n \"caller_phone_number\": \"<string>\",\n \"call_successful\": true,\n \"user_sentiment\": \"<string>\",\n \"in_voicemail\": true,\n \"collected_dynamic_variables\": {},\n \"call_cost\": 123,\n \"call_analysis\": {},\n \"metadata\": {\n \"ai_models\": {\n \"asr_model\": \"<string>\",\n \"llm_model\": \"<string>\",\n \"tts_model\": \"<string>\"\n },\n \"usage_token\": {\n \"stt_duration_seconds\": 123,\n \"llm_token\": 123,\n \"tts_characters_count\": 123\n }\n },\n \"general_meta_data_raw\": {},\n \"recording_multi_channel_url\": \"<string>\",\n \"recording_file_extension\": \"<string>\",\n \"recording_s3_multi_channel\": true,\n \"recording_s3_caller_channel\": 1\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.usetuner.ai/api/v1/public/call")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"call_id\": \"<string>\",\n \"call_type\": \"<string>\",\n \"transcript_with_tool_calls\": [\n {\n \"text\": \"<string>\",\n \"words\": [\n {\n \"word\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"confidence\": 123\n }\n ],\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"duration_ms\": 123,\n \"node\": {\n \"to\": \"<string>\",\n \"from\": \"<string>\",\n \"reason\": \"<string>\"\n },\n \"tool\": {\n \"name\": \"<string>\",\n \"request_id\": \"<string>\",\n \"params\": {},\n \"result\": {},\n \"is_error\": true,\n \"error\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123\n },\n \"metadata\": {\n \"e2e_latency\": 123,\n \"interrupted\": true,\n \"llm_node_ttft\": 123,\n \"tts_node_ttfb\": 123,\n \"transcript_confidence\": 123,\n \"stt_node_ttfb\": 123,\n \"eou_delay\": 123\n }\n }\n ],\n \"start_timestamp\": 123,\n \"end_timestamp\": 123,\n \"recording_url\": \"<string>\",\n \"sip_call_id\": \"<string>\",\n \"recipient\": \"<string>\",\n \"agent_version\": 1,\n \"transcript\": \"<string>\",\n \"duration_ms\": 123,\n \"call_status\": \"<string>\",\n \"disconnection_reason\": \"<string>\",\n \"caller_phone_number\": \"<string>\",\n \"call_successful\": true,\n \"user_sentiment\": \"<string>\",\n \"in_voicemail\": true,\n \"collected_dynamic_variables\": {},\n \"call_cost\": 123,\n \"call_analysis\": {},\n \"metadata\": {\n \"ai_models\": {\n \"asr_model\": \"<string>\",\n \"llm_model\": \"<string>\",\n \"tts_model\": \"<string>\"\n },\n \"usage_token\": {\n \"stt_duration_seconds\": 123,\n \"llm_token\": 123,\n \"tts_characters_count\": 123\n }\n },\n \"general_meta_data_raw\": {},\n \"recording_multi_channel_url\": \"<string>\",\n \"recording_file_extension\": \"<string>\",\n \"recording_s3_multi_channel\": true,\n \"recording_s3_caller_channel\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usetuner.ai/api/v1/public/call")
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 \"call_id\": \"<string>\",\n \"call_type\": \"<string>\",\n \"transcript_with_tool_calls\": [\n {\n \"text\": \"<string>\",\n \"words\": [\n {\n \"word\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"confidence\": 123\n }\n ],\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"duration_ms\": 123,\n \"node\": {\n \"to\": \"<string>\",\n \"from\": \"<string>\",\n \"reason\": \"<string>\"\n },\n \"tool\": {\n \"name\": \"<string>\",\n \"request_id\": \"<string>\",\n \"params\": {},\n \"result\": {},\n \"is_error\": true,\n \"error\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123\n },\n \"metadata\": {\n \"e2e_latency\": 123,\n \"interrupted\": true,\n \"llm_node_ttft\": 123,\n \"tts_node_ttfb\": 123,\n \"transcript_confidence\": 123,\n \"stt_node_ttfb\": 123,\n \"eou_delay\": 123\n }\n }\n ],\n \"start_timestamp\": 123,\n \"end_timestamp\": 123,\n \"recording_url\": \"<string>\",\n \"sip_call_id\": \"<string>\",\n \"recipient\": \"<string>\",\n \"agent_version\": 1,\n \"transcript\": \"<string>\",\n \"duration_ms\": 123,\n \"call_status\": \"<string>\",\n \"disconnection_reason\": \"<string>\",\n \"caller_phone_number\": \"<string>\",\n \"call_successful\": true,\n \"user_sentiment\": \"<string>\",\n \"in_voicemail\": true,\n \"collected_dynamic_variables\": {},\n \"call_cost\": 123,\n \"call_analysis\": {},\n \"metadata\": {\n \"ai_models\": {\n \"asr_model\": \"<string>\",\n \"llm_model\": \"<string>\",\n \"tts_model\": \"<string>\"\n },\n \"usage_token\": {\n \"stt_duration_seconds\": 123,\n \"llm_token\": 123,\n \"tts_characters_count\": 123\n }\n },\n \"general_meta_data_raw\": {},\n \"recording_multi_channel_url\": \"<string>\",\n \"recording_file_extension\": \"<string>\",\n \"recording_s3_multi_channel\": true,\n \"recording_s3_caller_channel\": 1\n}"
response = http.request(request)
puts response.read_body{
"id": 123,
"provider_call_id": "<string>",
"is_new": true,
"recording_upload": {
"url": "<string>",
"fields": {},
"key": "<string>",
"content_type": "<string>",
"max_bytes": 123,
"expires_at": "2023-11-07T05:31:56Z"
}
}{
"detail": "end_timestamp must be after start_timestamp"
}{
"detail": "Not authenticated"
}{
"detail": "Workspace has insufficient credits"
}{
"detail": "User does not have access to workspace 42"
}{
"detail": "Agent with remote identifier agent_abc123 not found"
}{
"detail": "Call with ID call_abc123 already exists for provider 4"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}{
"detail": "Rate limit exceeded: 60 requests per minute allowed for this workspace."
}{
"detail": "Failed to create call"
}{
"detail": "Recording uploads are not available in this environment."
}Create a Call
Send call data from your voice AI platform to Tuner for analysis. This endpoint accepts call transcripts and metadata, then processes them through Tuner’s evaluation pipeline.
curl --request POST \
--url https://api.usetuner.ai/api/v1/public/call \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"call_id": "<string>",
"call_type": "<string>",
"transcript_with_tool_calls": [
{
"text": "<string>",
"words": [
{
"word": "<string>",
"start_ms": 123,
"end_ms": 123,
"confidence": 123
}
],
"start_ms": 123,
"end_ms": 123,
"duration_ms": 123,
"node": {
"to": "<string>",
"from": "<string>",
"reason": "<string>"
},
"tool": {
"name": "<string>",
"request_id": "<string>",
"params": {},
"result": {},
"is_error": true,
"error": "<string>",
"start_ms": 123,
"end_ms": 123
},
"metadata": {
"e2e_latency": 123,
"interrupted": true,
"llm_node_ttft": 123,
"tts_node_ttfb": 123,
"transcript_confidence": 123,
"stt_node_ttfb": 123,
"eou_delay": 123
}
}
],
"start_timestamp": 123,
"end_timestamp": 123,
"recording_url": "<string>",
"sip_call_id": "<string>",
"recipient": "<string>",
"agent_version": 1,
"transcript": "<string>",
"duration_ms": 123,
"call_status": "<string>",
"disconnection_reason": "<string>",
"caller_phone_number": "<string>",
"call_successful": true,
"user_sentiment": "<string>",
"in_voicemail": true,
"collected_dynamic_variables": {},
"call_cost": 123,
"call_analysis": {},
"metadata": {
"ai_models": {
"asr_model": "<string>",
"llm_model": "<string>",
"tts_model": "<string>"
},
"usage_token": {
"stt_duration_seconds": 123,
"llm_token": 123,
"tts_characters_count": 123
}
},
"general_meta_data_raw": {},
"recording_multi_channel_url": "<string>",
"recording_file_extension": "<string>",
"recording_s3_multi_channel": true,
"recording_s3_caller_channel": 1
}
'import requests
url = "https://api.usetuner.ai/api/v1/public/call"
payload = {
"call_id": "<string>",
"call_type": "<string>",
"transcript_with_tool_calls": [
{
"text": "<string>",
"words": [
{
"word": "<string>",
"start_ms": 123,
"end_ms": 123,
"confidence": 123
}
],
"start_ms": 123,
"end_ms": 123,
"duration_ms": 123,
"node": {
"to": "<string>",
"from": "<string>",
"reason": "<string>"
},
"tool": {
"name": "<string>",
"request_id": "<string>",
"params": {},
"result": {},
"is_error": True,
"error": "<string>",
"start_ms": 123,
"end_ms": 123
},
"metadata": {
"e2e_latency": 123,
"interrupted": True,
"llm_node_ttft": 123,
"tts_node_ttfb": 123,
"transcript_confidence": 123,
"stt_node_ttfb": 123,
"eou_delay": 123
}
}
],
"start_timestamp": 123,
"end_timestamp": 123,
"recording_url": "<string>",
"sip_call_id": "<string>",
"recipient": "<string>",
"agent_version": 1,
"transcript": "<string>",
"duration_ms": 123,
"call_status": "<string>",
"disconnection_reason": "<string>",
"caller_phone_number": "<string>",
"call_successful": True,
"user_sentiment": "<string>",
"in_voicemail": True,
"collected_dynamic_variables": {},
"call_cost": 123,
"call_analysis": {},
"metadata": {
"ai_models": {
"asr_model": "<string>",
"llm_model": "<string>",
"tts_model": "<string>"
},
"usage_token": {
"stt_duration_seconds": 123,
"llm_token": 123,
"tts_characters_count": 123
}
},
"general_meta_data_raw": {},
"recording_multi_channel_url": "<string>",
"recording_file_extension": "<string>",
"recording_s3_multi_channel": True,
"recording_s3_caller_channel": 1
}
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({
call_id: '<string>',
call_type: '<string>',
transcript_with_tool_calls: [
{
text: '<string>',
words: [{word: '<string>', start_ms: 123, end_ms: 123, confidence: 123}],
start_ms: 123,
end_ms: 123,
duration_ms: 123,
node: {to: '<string>', from: '<string>', reason: '<string>'},
tool: {
name: '<string>',
request_id: '<string>',
params: {},
result: {},
is_error: true,
error: '<string>',
start_ms: 123,
end_ms: 123
},
metadata: {
e2e_latency: 123,
interrupted: true,
llm_node_ttft: 123,
tts_node_ttfb: 123,
transcript_confidence: 123,
stt_node_ttfb: 123,
eou_delay: 123
}
}
],
start_timestamp: 123,
end_timestamp: 123,
recording_url: '<string>',
sip_call_id: '<string>',
recipient: '<string>',
agent_version: 1,
transcript: '<string>',
duration_ms: 123,
call_status: '<string>',
disconnection_reason: '<string>',
caller_phone_number: '<string>',
call_successful: true,
user_sentiment: '<string>',
in_voicemail: true,
collected_dynamic_variables: {},
call_cost: 123,
call_analysis: {},
metadata: {
ai_models: {asr_model: '<string>', llm_model: '<string>', tts_model: '<string>'},
usage_token: {stt_duration_seconds: 123, llm_token: 123, tts_characters_count: 123}
},
general_meta_data_raw: {},
recording_multi_channel_url: '<string>',
recording_file_extension: '<string>',
recording_s3_multi_channel: true,
recording_s3_caller_channel: 1
})
};
fetch('https://api.usetuner.ai/api/v1/public/call', 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.usetuner.ai/api/v1/public/call",
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([
'call_id' => '<string>',
'call_type' => '<string>',
'transcript_with_tool_calls' => [
[
'text' => '<string>',
'words' => [
[
'word' => '<string>',
'start_ms' => 123,
'end_ms' => 123,
'confidence' => 123
]
],
'start_ms' => 123,
'end_ms' => 123,
'duration_ms' => 123,
'node' => [
'to' => '<string>',
'from' => '<string>',
'reason' => '<string>'
],
'tool' => [
'name' => '<string>',
'request_id' => '<string>',
'params' => [
],
'result' => [
],
'is_error' => true,
'error' => '<string>',
'start_ms' => 123,
'end_ms' => 123
],
'metadata' => [
'e2e_latency' => 123,
'interrupted' => true,
'llm_node_ttft' => 123,
'tts_node_ttfb' => 123,
'transcript_confidence' => 123,
'stt_node_ttfb' => 123,
'eou_delay' => 123
]
]
],
'start_timestamp' => 123,
'end_timestamp' => 123,
'recording_url' => '<string>',
'sip_call_id' => '<string>',
'recipient' => '<string>',
'agent_version' => 1,
'transcript' => '<string>',
'duration_ms' => 123,
'call_status' => '<string>',
'disconnection_reason' => '<string>',
'caller_phone_number' => '<string>',
'call_successful' => true,
'user_sentiment' => '<string>',
'in_voicemail' => true,
'collected_dynamic_variables' => [
],
'call_cost' => 123,
'call_analysis' => [
],
'metadata' => [
'ai_models' => [
'asr_model' => '<string>',
'llm_model' => '<string>',
'tts_model' => '<string>'
],
'usage_token' => [
'stt_duration_seconds' => 123,
'llm_token' => 123,
'tts_characters_count' => 123
]
],
'general_meta_data_raw' => [
],
'recording_multi_channel_url' => '<string>',
'recording_file_extension' => '<string>',
'recording_s3_multi_channel' => true,
'recording_s3_caller_channel' => 1
]),
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.usetuner.ai/api/v1/public/call"
payload := strings.NewReader("{\n \"call_id\": \"<string>\",\n \"call_type\": \"<string>\",\n \"transcript_with_tool_calls\": [\n {\n \"text\": \"<string>\",\n \"words\": [\n {\n \"word\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"confidence\": 123\n }\n ],\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"duration_ms\": 123,\n \"node\": {\n \"to\": \"<string>\",\n \"from\": \"<string>\",\n \"reason\": \"<string>\"\n },\n \"tool\": {\n \"name\": \"<string>\",\n \"request_id\": \"<string>\",\n \"params\": {},\n \"result\": {},\n \"is_error\": true,\n \"error\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123\n },\n \"metadata\": {\n \"e2e_latency\": 123,\n \"interrupted\": true,\n \"llm_node_ttft\": 123,\n \"tts_node_ttfb\": 123,\n \"transcript_confidence\": 123,\n \"stt_node_ttfb\": 123,\n \"eou_delay\": 123\n }\n }\n ],\n \"start_timestamp\": 123,\n \"end_timestamp\": 123,\n \"recording_url\": \"<string>\",\n \"sip_call_id\": \"<string>\",\n \"recipient\": \"<string>\",\n \"agent_version\": 1,\n \"transcript\": \"<string>\",\n \"duration_ms\": 123,\n \"call_status\": \"<string>\",\n \"disconnection_reason\": \"<string>\",\n \"caller_phone_number\": \"<string>\",\n \"call_successful\": true,\n \"user_sentiment\": \"<string>\",\n \"in_voicemail\": true,\n \"collected_dynamic_variables\": {},\n \"call_cost\": 123,\n \"call_analysis\": {},\n \"metadata\": {\n \"ai_models\": {\n \"asr_model\": \"<string>\",\n \"llm_model\": \"<string>\",\n \"tts_model\": \"<string>\"\n },\n \"usage_token\": {\n \"stt_duration_seconds\": 123,\n \"llm_token\": 123,\n \"tts_characters_count\": 123\n }\n },\n \"general_meta_data_raw\": {},\n \"recording_multi_channel_url\": \"<string>\",\n \"recording_file_extension\": \"<string>\",\n \"recording_s3_multi_channel\": true,\n \"recording_s3_caller_channel\": 1\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.usetuner.ai/api/v1/public/call")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"call_id\": \"<string>\",\n \"call_type\": \"<string>\",\n \"transcript_with_tool_calls\": [\n {\n \"text\": \"<string>\",\n \"words\": [\n {\n \"word\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"confidence\": 123\n }\n ],\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"duration_ms\": 123,\n \"node\": {\n \"to\": \"<string>\",\n \"from\": \"<string>\",\n \"reason\": \"<string>\"\n },\n \"tool\": {\n \"name\": \"<string>\",\n \"request_id\": \"<string>\",\n \"params\": {},\n \"result\": {},\n \"is_error\": true,\n \"error\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123\n },\n \"metadata\": {\n \"e2e_latency\": 123,\n \"interrupted\": true,\n \"llm_node_ttft\": 123,\n \"tts_node_ttfb\": 123,\n \"transcript_confidence\": 123,\n \"stt_node_ttfb\": 123,\n \"eou_delay\": 123\n }\n }\n ],\n \"start_timestamp\": 123,\n \"end_timestamp\": 123,\n \"recording_url\": \"<string>\",\n \"sip_call_id\": \"<string>\",\n \"recipient\": \"<string>\",\n \"agent_version\": 1,\n \"transcript\": \"<string>\",\n \"duration_ms\": 123,\n \"call_status\": \"<string>\",\n \"disconnection_reason\": \"<string>\",\n \"caller_phone_number\": \"<string>\",\n \"call_successful\": true,\n \"user_sentiment\": \"<string>\",\n \"in_voicemail\": true,\n \"collected_dynamic_variables\": {},\n \"call_cost\": 123,\n \"call_analysis\": {},\n \"metadata\": {\n \"ai_models\": {\n \"asr_model\": \"<string>\",\n \"llm_model\": \"<string>\",\n \"tts_model\": \"<string>\"\n },\n \"usage_token\": {\n \"stt_duration_seconds\": 123,\n \"llm_token\": 123,\n \"tts_characters_count\": 123\n }\n },\n \"general_meta_data_raw\": {},\n \"recording_multi_channel_url\": \"<string>\",\n \"recording_file_extension\": \"<string>\",\n \"recording_s3_multi_channel\": true,\n \"recording_s3_caller_channel\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usetuner.ai/api/v1/public/call")
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 \"call_id\": \"<string>\",\n \"call_type\": \"<string>\",\n \"transcript_with_tool_calls\": [\n {\n \"text\": \"<string>\",\n \"words\": [\n {\n \"word\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"confidence\": 123\n }\n ],\n \"start_ms\": 123,\n \"end_ms\": 123,\n \"duration_ms\": 123,\n \"node\": {\n \"to\": \"<string>\",\n \"from\": \"<string>\",\n \"reason\": \"<string>\"\n },\n \"tool\": {\n \"name\": \"<string>\",\n \"request_id\": \"<string>\",\n \"params\": {},\n \"result\": {},\n \"is_error\": true,\n \"error\": \"<string>\",\n \"start_ms\": 123,\n \"end_ms\": 123\n },\n \"metadata\": {\n \"e2e_latency\": 123,\n \"interrupted\": true,\n \"llm_node_ttft\": 123,\n \"tts_node_ttfb\": 123,\n \"transcript_confidence\": 123,\n \"stt_node_ttfb\": 123,\n \"eou_delay\": 123\n }\n }\n ],\n \"start_timestamp\": 123,\n \"end_timestamp\": 123,\n \"recording_url\": \"<string>\",\n \"sip_call_id\": \"<string>\",\n \"recipient\": \"<string>\",\n \"agent_version\": 1,\n \"transcript\": \"<string>\",\n \"duration_ms\": 123,\n \"call_status\": \"<string>\",\n \"disconnection_reason\": \"<string>\",\n \"caller_phone_number\": \"<string>\",\n \"call_successful\": true,\n \"user_sentiment\": \"<string>\",\n \"in_voicemail\": true,\n \"collected_dynamic_variables\": {},\n \"call_cost\": 123,\n \"call_analysis\": {},\n \"metadata\": {\n \"ai_models\": {\n \"asr_model\": \"<string>\",\n \"llm_model\": \"<string>\",\n \"tts_model\": \"<string>\"\n },\n \"usage_token\": {\n \"stt_duration_seconds\": 123,\n \"llm_token\": 123,\n \"tts_characters_count\": 123\n }\n },\n \"general_meta_data_raw\": {},\n \"recording_multi_channel_url\": \"<string>\",\n \"recording_file_extension\": \"<string>\",\n \"recording_s3_multi_channel\": true,\n \"recording_s3_caller_channel\": 1\n}"
response = http.request(request)
puts response.read_body{
"id": 123,
"provider_call_id": "<string>",
"is_new": true,
"recording_upload": {
"url": "<string>",
"fields": {},
"key": "<string>",
"content_type": "<string>",
"max_bytes": 123,
"expires_at": "2023-11-07T05:31:56Z"
}
}{
"detail": "end_timestamp must be after start_timestamp"
}{
"detail": "Not authenticated"
}{
"detail": "Workspace has insufficient credits"
}{
"detail": "User does not have access to workspace 42"
}{
"detail": "Agent with remote identifier agent_abc123 not found"
}{
"detail": "Call with ID call_abc123 already exists for provider 4"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}{
"detail": "Rate limit exceeded: 60 requests per minute allowed for this workspace."
}{
"detail": "Failed to create call"
}{
"detail": "Recording uploads are not available in this environment."
}Send your API key in the
Authorization header as a Bearer token.Authorizations
Use Tuner API key (tr_api_...) or user session token. Find your API key in Workspace Settings > API Keys.
Query Parameters
Workspace ID. Find this in Workspace > General Settings.
Your Agent ID configured in Tuner. Get this value from Agent Settings > Agent Connection > Agent ID.
Body
Request schema for public call creation.
Unique call identifier from your provider (used for idempotency).
1 - 200Call channel/type from your provider (e.g., 'phone_call', 'web_call').
1 - 100The call timeline in chronological order. Each item is a user turn, an agent turn, a tool call or its result, or a workflow node transition.
User and agent turns must carry timing — as words, as start_ms and end_ms, or as start_ms and duration_ms. Latency and voice metrics are computed from it.
1Show child attributes
Show child attributes
Call start time as Unix epoch. Accepts either seconds or milliseconds.
Call end time as Unix epoch. Accepts either seconds or milliseconds. Must be greater than or equal to start_timestamp.
Publicly reachable recording URL (audio file or provider recording link).
1 - 1024Optional SIP call identifier. When provided, it is used as provider_call_id for persistence and idempotency.
1 - 200Recipient phone number (E.164) or SIP URL for outbound calls.
1 - 500The version of the agent that handled this call (e.g. 3).
x >= 0Diarized plain-text transcript (fallback for display/search). If omitted, we derive it from transcript_with_tool_calls when possible.
Call duration in milliseconds. If omitted, we compute it from start_timestamp and end_timestamp.
Provider call status at ingest time. Preferred values: 'call_ended'.
100Why the call ended (e.g. user_hangup, agent_hangup).
100Caller phone number in E.164 format when available (e.g., '+14155550123').
50Whether the call was successful
User sentiment label. Must be one of [positive, neutral, negative, unknown]
50Whether the call reached voicemail
Dynamic variables collected during the call (free-form JSON)
Total call cost in cents (e.g. 125 for $1.25). Client sends cents; frontend converts from dollars for UX.
Provider-native analysis payload (free-form JSON; stored as-is)
Call-level metadata (e.g. context, custom attributes). Supports structured ai_models and usage_token fields; extra keys are also accepted. Merged into general_meta_data_raw for storage. If both are sent, keys are merged; general_meta_data_raw keys win on collision.
Show child attributes
Show child attributes
Use to store any extra metadata payload as a JSON object
Multi-channel recording URL (separate speaker channels), if available.
1024Supplying this opts the call into receiving a presigned upload target (recording_upload in the response) so you can upload the call's audio directly to Tuner's storage. Provide the file extension without a leading dot (e.g. 'wav', 'mp3'). Omit this field entirely if you are not uploading audio.
Whether the audio being uploaded has the caller and the agent on separate channels rather than mixed into a single channel. Only applies to audio uploaded via recording_file_extension. Omit this field if the recording is a mono mix -- it is treated as a mono mix by default.
The 0-based index of the channel carrying the caller's voice, for audio uploaded via recording_file_extension. Defaults to 0 and is only meaningful when recording_s3_multi_channel is true.
x >= 0Response
Successful Response
Response schema for public call creation.
Internal Tuner call ID
Echo of the persisted provider call ID (sip_call_id when provided, else call_id).
Whether the call was newly created (false means it already existed)
Present only when the request set recording_file_extension and the upload target could be prepared. Null if the extension was omitted, if the call already had a recording uploaded, or if preparing the target failed after the call was otherwise saved successfully.
Show child attributes
Show child attributes