curl --request POST \
--url https://api.instaview.sk/agents \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"composerSessionId": "9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90",
"name": "Senior Developer Phone Screen",
"type": "ONLINE",
"focus": "SCREENING",
"language": "EN",
"duration": 30,
"questions": [
"Tell me about a challenging project you worked on"
],
"instructions": "Focus on communication skills and team fit",
"companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
"metadata": {
"department": "Sales",
"internalId": "AGENT-001"
},
"cefrLevel": "B1",
"backgroundSound": "OFFICE",
"contextConfig": {
"role": "an account executive for Acme",
"communicationStyle": "concise and direct",
"callToAction": "book a 30-minute demo",
"useContactContext": true
},
"analyticsConfig": {
"extractionTargets": [
{
"label": "Budget confirmed",
"type": "bool",
"key": "budget_confirmed",
"enumValues": [
"hot",
"warm",
"cold"
],
"ideal": "A confirmed budget of at least 10k",
"importance": "PREFERRED",
"weight": 40
}
],
"scoringCriteria": [
{
"label": "Handled objections",
"description": "Acknowledged the objection and answered it with a concrete example",
"key": "handled_objections",
"importance": "PREFERRED",
"weight": 40
}
],
"outcomes": [
{
"label": "Meeting booked",
"description": "The contact agreed to a specific date and time",
"key": "meeting_booked"
}
],
"outputTags": [
{
"label": "Needs follow-up",
"key": "needs_followup",
"description": "The contact asked to be called back"
}
],
"capture": {
"recording": true,
"transcript": true,
"summary": true,
"qa": true,
"evaluation": true,
"sentiment": true
}
},
"callConfig": {},
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
}
}
'import requests
url = "https://api.instaview.sk/agents"
payload = {
"composerSessionId": "9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90",
"name": "Senior Developer Phone Screen",
"type": "ONLINE",
"focus": "SCREENING",
"language": "EN",
"duration": 30,
"questions": ["Tell me about a challenging project you worked on"],
"instructions": "Focus on communication skills and team fit",
"companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
"metadata": {
"department": "Sales",
"internalId": "AGENT-001"
},
"cefrLevel": "B1",
"backgroundSound": "OFFICE",
"contextConfig": {
"role": "an account executive for Acme",
"communicationStyle": "concise and direct",
"callToAction": "book a 30-minute demo",
"useContactContext": True
},
"analyticsConfig": {
"extractionTargets": [
{
"label": "Budget confirmed",
"type": "bool",
"key": "budget_confirmed",
"enumValues": ["hot", "warm", "cold"],
"ideal": "A confirmed budget of at least 10k",
"importance": "PREFERRED",
"weight": 40
}
],
"scoringCriteria": [
{
"label": "Handled objections",
"description": "Acknowledged the objection and answered it with a concrete example",
"key": "handled_objections",
"importance": "PREFERRED",
"weight": 40
}
],
"outcomes": [
{
"label": "Meeting booked",
"description": "The contact agreed to a specific date and time",
"key": "meeting_booked"
}
],
"outputTags": [
{
"label": "Needs follow-up",
"key": "needs_followup",
"description": "The contact asked to be called back"
}
],
"capture": {
"recording": True,
"transcript": True,
"summary": True,
"qa": True,
"evaluation": True,
"sentiment": True
}
},
"callConfig": {},
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
}
}
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({
composerSessionId: '9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90',
name: 'Senior Developer Phone Screen',
type: 'ONLINE',
focus: 'SCREENING',
language: 'EN',
duration: 30,
questions: ['Tell me about a challenging project you worked on'],
instructions: 'Focus on communication skills and team fit',
companyPhoneNumberId: '123e4567-e89b-12d3-a456-426614174000',
metadata: {department: 'Sales', internalId: 'AGENT-001'},
cefrLevel: 'B1',
backgroundSound: 'OFFICE',
contextConfig: {
role: 'an account executive for Acme',
communicationStyle: 'concise and direct',
callToAction: 'book a 30-minute demo',
useContactContext: true
},
analyticsConfig: {
extractionTargets: [
{
label: 'Budget confirmed',
type: 'bool',
key: 'budget_confirmed',
enumValues: ['hot', 'warm', 'cold'],
ideal: 'A confirmed budget of at least 10k',
importance: 'PREFERRED',
weight: 40
}
],
scoringCriteria: [
{
label: 'Handled objections',
description: 'Acknowledged the objection and answered it with a concrete example',
key: 'handled_objections',
importance: 'PREFERRED',
weight: 40
}
],
outcomes: [
{
label: 'Meeting booked',
description: 'The contact agreed to a specific date and time',
key: 'meeting_booked'
}
],
outputTags: [
{
label: 'Needs follow-up',
key: 'needs_followup',
description: 'The contact asked to be called back'
}
],
capture: {
recording: true,
transcript: true,
summary: true,
qa: true,
evaluation: true,
sentiment: true
}
},
callConfig: {},
overrides: {
companyName: 'Acme Manufacturing',
companyDescription: 'Acme makes industrial fasteners and employs 400 people across Slovakia.'
}
})
};
fetch('https://api.instaview.sk/agents', 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.instaview.sk/agents",
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([
'composerSessionId' => '9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90',
'name' => 'Senior Developer Phone Screen',
'type' => 'ONLINE',
'focus' => 'SCREENING',
'language' => 'EN',
'duration' => 30,
'questions' => [
'Tell me about a challenging project you worked on'
],
'instructions' => 'Focus on communication skills and team fit',
'companyPhoneNumberId' => '123e4567-e89b-12d3-a456-426614174000',
'metadata' => [
'department' => 'Sales',
'internalId' => 'AGENT-001'
],
'cefrLevel' => 'B1',
'backgroundSound' => 'OFFICE',
'contextConfig' => [
'role' => 'an account executive for Acme',
'communicationStyle' => 'concise and direct',
'callToAction' => 'book a 30-minute demo',
'useContactContext' => true
],
'analyticsConfig' => [
'extractionTargets' => [
[
'label' => 'Budget confirmed',
'type' => 'bool',
'key' => 'budget_confirmed',
'enumValues' => [
'hot',
'warm',
'cold'
],
'ideal' => 'A confirmed budget of at least 10k',
'importance' => 'PREFERRED',
'weight' => 40
]
],
'scoringCriteria' => [
[
'label' => 'Handled objections',
'description' => 'Acknowledged the objection and answered it with a concrete example',
'key' => 'handled_objections',
'importance' => 'PREFERRED',
'weight' => 40
]
],
'outcomes' => [
[
'label' => 'Meeting booked',
'description' => 'The contact agreed to a specific date and time',
'key' => 'meeting_booked'
]
],
'outputTags' => [
[
'label' => 'Needs follow-up',
'key' => 'needs_followup',
'description' => 'The contact asked to be called back'
]
],
'capture' => [
'recording' => true,
'transcript' => true,
'summary' => true,
'qa' => true,
'evaluation' => true,
'sentiment' => true
]
],
'callConfig' => [
],
'overrides' => [
'companyName' => 'Acme Manufacturing',
'companyDescription' => 'Acme makes industrial fasteners and employs 400 people across Slovakia.'
]
]),
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.instaview.sk/agents"
payload := strings.NewReader("{\n \"composerSessionId\": \"9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90\",\n \"name\": \"Senior Developer Phone Screen\",\n \"type\": \"ONLINE\",\n \"focus\": \"SCREENING\",\n \"language\": \"EN\",\n \"duration\": 30,\n \"questions\": [\n \"Tell me about a challenging project you worked on\"\n ],\n \"instructions\": \"Focus on communication skills and team fit\",\n \"companyPhoneNumberId\": \"123e4567-e89b-12d3-a456-426614174000\",\n \"metadata\": {\n \"department\": \"Sales\",\n \"internalId\": \"AGENT-001\"\n },\n \"cefrLevel\": \"B1\",\n \"backgroundSound\": \"OFFICE\",\n \"contextConfig\": {\n \"role\": \"an account executive for Acme\",\n \"communicationStyle\": \"concise and direct\",\n \"callToAction\": \"book a 30-minute demo\",\n \"useContactContext\": true\n },\n \"analyticsConfig\": {\n \"extractionTargets\": [\n {\n \"label\": \"Budget confirmed\",\n \"type\": \"bool\",\n \"key\": \"budget_confirmed\",\n \"enumValues\": [\n \"hot\",\n \"warm\",\n \"cold\"\n ],\n \"ideal\": \"A confirmed budget of at least 10k\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"scoringCriteria\": [\n {\n \"label\": \"Handled objections\",\n \"description\": \"Acknowledged the objection and answered it with a concrete example\",\n \"key\": \"handled_objections\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"outcomes\": [\n {\n \"label\": \"Meeting booked\",\n \"description\": \"The contact agreed to a specific date and time\",\n \"key\": \"meeting_booked\"\n }\n ],\n \"outputTags\": [\n {\n \"label\": \"Needs follow-up\",\n \"key\": \"needs_followup\",\n \"description\": \"The contact asked to be called back\"\n }\n ],\n \"capture\": {\n \"recording\": true,\n \"transcript\": true,\n \"summary\": true,\n \"qa\": true,\n \"evaluation\": true,\n \"sentiment\": true\n }\n },\n \"callConfig\": {},\n \"overrides\": {\n \"companyName\": \"Acme Manufacturing\",\n \"companyDescription\": \"Acme makes industrial fasteners and employs 400 people across Slovakia.\"\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.instaview.sk/agents")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"composerSessionId\": \"9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90\",\n \"name\": \"Senior Developer Phone Screen\",\n \"type\": \"ONLINE\",\n \"focus\": \"SCREENING\",\n \"language\": \"EN\",\n \"duration\": 30,\n \"questions\": [\n \"Tell me about a challenging project you worked on\"\n ],\n \"instructions\": \"Focus on communication skills and team fit\",\n \"companyPhoneNumberId\": \"123e4567-e89b-12d3-a456-426614174000\",\n \"metadata\": {\n \"department\": \"Sales\",\n \"internalId\": \"AGENT-001\"\n },\n \"cefrLevel\": \"B1\",\n \"backgroundSound\": \"OFFICE\",\n \"contextConfig\": {\n \"role\": \"an account executive for Acme\",\n \"communicationStyle\": \"concise and direct\",\n \"callToAction\": \"book a 30-minute demo\",\n \"useContactContext\": true\n },\n \"analyticsConfig\": {\n \"extractionTargets\": [\n {\n \"label\": \"Budget confirmed\",\n \"type\": \"bool\",\n \"key\": \"budget_confirmed\",\n \"enumValues\": [\n \"hot\",\n \"warm\",\n \"cold\"\n ],\n \"ideal\": \"A confirmed budget of at least 10k\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"scoringCriteria\": [\n {\n \"label\": \"Handled objections\",\n \"description\": \"Acknowledged the objection and answered it with a concrete example\",\n \"key\": \"handled_objections\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"outcomes\": [\n {\n \"label\": \"Meeting booked\",\n \"description\": \"The contact agreed to a specific date and time\",\n \"key\": \"meeting_booked\"\n }\n ],\n \"outputTags\": [\n {\n \"label\": \"Needs follow-up\",\n \"key\": \"needs_followup\",\n \"description\": \"The contact asked to be called back\"\n }\n ],\n \"capture\": {\n \"recording\": true,\n \"transcript\": true,\n \"summary\": true,\n \"qa\": true,\n \"evaluation\": true,\n \"sentiment\": true\n }\n },\n \"callConfig\": {},\n \"overrides\": {\n \"companyName\": \"Acme Manufacturing\",\n \"companyDescription\": \"Acme makes industrial fasteners and employs 400 people across Slovakia.\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.instaview.sk/agents")
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 \"composerSessionId\": \"9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90\",\n \"name\": \"Senior Developer Phone Screen\",\n \"type\": \"ONLINE\",\n \"focus\": \"SCREENING\",\n \"language\": \"EN\",\n \"duration\": 30,\n \"questions\": [\n \"Tell me about a challenging project you worked on\"\n ],\n \"instructions\": \"Focus on communication skills and team fit\",\n \"companyPhoneNumberId\": \"123e4567-e89b-12d3-a456-426614174000\",\n \"metadata\": {\n \"department\": \"Sales\",\n \"internalId\": \"AGENT-001\"\n },\n \"cefrLevel\": \"B1\",\n \"backgroundSound\": \"OFFICE\",\n \"contextConfig\": {\n \"role\": \"an account executive for Acme\",\n \"communicationStyle\": \"concise and direct\",\n \"callToAction\": \"book a 30-minute demo\",\n \"useContactContext\": true\n },\n \"analyticsConfig\": {\n \"extractionTargets\": [\n {\n \"label\": \"Budget confirmed\",\n \"type\": \"bool\",\n \"key\": \"budget_confirmed\",\n \"enumValues\": [\n \"hot\",\n \"warm\",\n \"cold\"\n ],\n \"ideal\": \"A confirmed budget of at least 10k\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"scoringCriteria\": [\n {\n \"label\": \"Handled objections\",\n \"description\": \"Acknowledged the objection and answered it with a concrete example\",\n \"key\": \"handled_objections\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"outcomes\": [\n {\n \"label\": \"Meeting booked\",\n \"description\": \"The contact agreed to a specific date and time\",\n \"key\": \"meeting_booked\"\n }\n ],\n \"outputTags\": [\n {\n \"label\": \"Needs follow-up\",\n \"key\": \"needs_followup\",\n \"description\": \"The contact asked to be called back\"\n }\n ],\n \"capture\": {\n \"recording\": true,\n \"transcript\": true,\n \"summary\": true,\n \"qa\": true,\n \"evaluation\": true,\n \"sentiment\": true\n }\n },\n \"callConfig\": {},\n \"overrides\": {\n \"companyName\": \"Acme Manufacturing\",\n \"companyDescription\": \"Acme makes industrial fasteners and employs 400 people across Slovakia.\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Frontend Developer Interview",
"type": "ONLINE",
"focus": "SCREENING",
"language": "EN",
"duration": 30,
"createdAt": "2025-11-20T10:30:00Z",
"updatedAt": "2025-11-20T10:30:00Z",
"questions": [
"What is your experience with React?"
],
"instructions": "Focus on technical skills and previous project experience",
"voiceId": "ALEX",
"companyId": "123e4567-e89b-12d3-a456-426614174000",
"metadata": {
"department": "Sales"
},
"cefrLevel": "B1",
"backgroundSound": "OFFICE",
"flow": {
"firstMessage": {
"type": "first_message",
"text": "Hi {{contact.firstName}}, do you have two minutes?",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "Qualify budget"
},
"sections": [
{
"type": "sequential",
"prompt": "Introduce yourself and explain why you are calling.",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "Qualify budget"
}
],
"lastMessage": {
"type": "last_message",
"text": "Thanks for your time — have a great day!",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "Qualify budget"
},
"schemaVersion": "1.0.0"
},
"guardrails": {
"rules": [
"Never quote a price",
"Never promise a delivery date"
]
},
"contextConfig": {
"role": "an account executive for Acme",
"communicationStyle": "concise and direct",
"callToAction": "book a 30-minute demo",
"useContactContext": true
},
"analyticsConfig": {
"extractionTargets": [
{
"label": "Budget confirmed",
"type": "bool",
"key": "budget_confirmed",
"enumValues": [
"hot",
"warm",
"cold"
],
"ideal": "A confirmed budget of at least 10k",
"importance": "PREFERRED",
"weight": 40
}
],
"scoringCriteria": [
{
"label": "Handled objections",
"description": "Acknowledged the objection and answered it with a concrete example",
"key": "handled_objections",
"importance": "PREFERRED",
"weight": 40
}
],
"outcomes": [
{
"label": "Meeting booked",
"description": "The contact agreed to a specific date and time",
"key": "meeting_booked"
}
],
"outputTags": [
{
"label": "Needs follow-up",
"key": "needs_followup",
"description": "The contact asked to be called back"
}
],
"capture": {
"recording": true,
"transcript": true,
"summary": true,
"qa": true,
"evaluation": true,
"sentiment": true
}
},
"callConfig": {
"retryPolicy": {
"maxAttempts": 3
},
"callWindow": {
"mode": "custom",
"days": [
"mon",
"tue",
"wed",
"thu",
"fri"
],
"start": "09:00",
"end": "18:00",
"timezoneAnchor": {
"mode": "contact",
"timezone": "Europe/Bratislava",
"fallbackTimezone": "Europe/Bratislava"
}
}
},
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
}
}Create Agent
Creates a new agent scoped to the API key’s company. Send a flow (with optional guardrails and contextConfig) to create a custom agent — its focus is then derived and must not be sent; otherwise pick a template focus.
curl --request POST \
--url https://api.instaview.sk/agents \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"composerSessionId": "9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90",
"name": "Senior Developer Phone Screen",
"type": "ONLINE",
"focus": "SCREENING",
"language": "EN",
"duration": 30,
"questions": [
"Tell me about a challenging project you worked on"
],
"instructions": "Focus on communication skills and team fit",
"companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
"metadata": {
"department": "Sales",
"internalId": "AGENT-001"
},
"cefrLevel": "B1",
"backgroundSound": "OFFICE",
"contextConfig": {
"role": "an account executive for Acme",
"communicationStyle": "concise and direct",
"callToAction": "book a 30-minute demo",
"useContactContext": true
},
"analyticsConfig": {
"extractionTargets": [
{
"label": "Budget confirmed",
"type": "bool",
"key": "budget_confirmed",
"enumValues": [
"hot",
"warm",
"cold"
],
"ideal": "A confirmed budget of at least 10k",
"importance": "PREFERRED",
"weight": 40
}
],
"scoringCriteria": [
{
"label": "Handled objections",
"description": "Acknowledged the objection and answered it with a concrete example",
"key": "handled_objections",
"importance": "PREFERRED",
"weight": 40
}
],
"outcomes": [
{
"label": "Meeting booked",
"description": "The contact agreed to a specific date and time",
"key": "meeting_booked"
}
],
"outputTags": [
{
"label": "Needs follow-up",
"key": "needs_followup",
"description": "The contact asked to be called back"
}
],
"capture": {
"recording": true,
"transcript": true,
"summary": true,
"qa": true,
"evaluation": true,
"sentiment": true
}
},
"callConfig": {},
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
}
}
'import requests
url = "https://api.instaview.sk/agents"
payload = {
"composerSessionId": "9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90",
"name": "Senior Developer Phone Screen",
"type": "ONLINE",
"focus": "SCREENING",
"language": "EN",
"duration": 30,
"questions": ["Tell me about a challenging project you worked on"],
"instructions": "Focus on communication skills and team fit",
"companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
"metadata": {
"department": "Sales",
"internalId": "AGENT-001"
},
"cefrLevel": "B1",
"backgroundSound": "OFFICE",
"contextConfig": {
"role": "an account executive for Acme",
"communicationStyle": "concise and direct",
"callToAction": "book a 30-minute demo",
"useContactContext": True
},
"analyticsConfig": {
"extractionTargets": [
{
"label": "Budget confirmed",
"type": "bool",
"key": "budget_confirmed",
"enumValues": ["hot", "warm", "cold"],
"ideal": "A confirmed budget of at least 10k",
"importance": "PREFERRED",
"weight": 40
}
],
"scoringCriteria": [
{
"label": "Handled objections",
"description": "Acknowledged the objection and answered it with a concrete example",
"key": "handled_objections",
"importance": "PREFERRED",
"weight": 40
}
],
"outcomes": [
{
"label": "Meeting booked",
"description": "The contact agreed to a specific date and time",
"key": "meeting_booked"
}
],
"outputTags": [
{
"label": "Needs follow-up",
"key": "needs_followup",
"description": "The contact asked to be called back"
}
],
"capture": {
"recording": True,
"transcript": True,
"summary": True,
"qa": True,
"evaluation": True,
"sentiment": True
}
},
"callConfig": {},
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
}
}
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({
composerSessionId: '9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90',
name: 'Senior Developer Phone Screen',
type: 'ONLINE',
focus: 'SCREENING',
language: 'EN',
duration: 30,
questions: ['Tell me about a challenging project you worked on'],
instructions: 'Focus on communication skills and team fit',
companyPhoneNumberId: '123e4567-e89b-12d3-a456-426614174000',
metadata: {department: 'Sales', internalId: 'AGENT-001'},
cefrLevel: 'B1',
backgroundSound: 'OFFICE',
contextConfig: {
role: 'an account executive for Acme',
communicationStyle: 'concise and direct',
callToAction: 'book a 30-minute demo',
useContactContext: true
},
analyticsConfig: {
extractionTargets: [
{
label: 'Budget confirmed',
type: 'bool',
key: 'budget_confirmed',
enumValues: ['hot', 'warm', 'cold'],
ideal: 'A confirmed budget of at least 10k',
importance: 'PREFERRED',
weight: 40
}
],
scoringCriteria: [
{
label: 'Handled objections',
description: 'Acknowledged the objection and answered it with a concrete example',
key: 'handled_objections',
importance: 'PREFERRED',
weight: 40
}
],
outcomes: [
{
label: 'Meeting booked',
description: 'The contact agreed to a specific date and time',
key: 'meeting_booked'
}
],
outputTags: [
{
label: 'Needs follow-up',
key: 'needs_followup',
description: 'The contact asked to be called back'
}
],
capture: {
recording: true,
transcript: true,
summary: true,
qa: true,
evaluation: true,
sentiment: true
}
},
callConfig: {},
overrides: {
companyName: 'Acme Manufacturing',
companyDescription: 'Acme makes industrial fasteners and employs 400 people across Slovakia.'
}
})
};
fetch('https://api.instaview.sk/agents', 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.instaview.sk/agents",
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([
'composerSessionId' => '9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90',
'name' => 'Senior Developer Phone Screen',
'type' => 'ONLINE',
'focus' => 'SCREENING',
'language' => 'EN',
'duration' => 30,
'questions' => [
'Tell me about a challenging project you worked on'
],
'instructions' => 'Focus on communication skills and team fit',
'companyPhoneNumberId' => '123e4567-e89b-12d3-a456-426614174000',
'metadata' => [
'department' => 'Sales',
'internalId' => 'AGENT-001'
],
'cefrLevel' => 'B1',
'backgroundSound' => 'OFFICE',
'contextConfig' => [
'role' => 'an account executive for Acme',
'communicationStyle' => 'concise and direct',
'callToAction' => 'book a 30-minute demo',
'useContactContext' => true
],
'analyticsConfig' => [
'extractionTargets' => [
[
'label' => 'Budget confirmed',
'type' => 'bool',
'key' => 'budget_confirmed',
'enumValues' => [
'hot',
'warm',
'cold'
],
'ideal' => 'A confirmed budget of at least 10k',
'importance' => 'PREFERRED',
'weight' => 40
]
],
'scoringCriteria' => [
[
'label' => 'Handled objections',
'description' => 'Acknowledged the objection and answered it with a concrete example',
'key' => 'handled_objections',
'importance' => 'PREFERRED',
'weight' => 40
]
],
'outcomes' => [
[
'label' => 'Meeting booked',
'description' => 'The contact agreed to a specific date and time',
'key' => 'meeting_booked'
]
],
'outputTags' => [
[
'label' => 'Needs follow-up',
'key' => 'needs_followup',
'description' => 'The contact asked to be called back'
]
],
'capture' => [
'recording' => true,
'transcript' => true,
'summary' => true,
'qa' => true,
'evaluation' => true,
'sentiment' => true
]
],
'callConfig' => [
],
'overrides' => [
'companyName' => 'Acme Manufacturing',
'companyDescription' => 'Acme makes industrial fasteners and employs 400 people across Slovakia.'
]
]),
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.instaview.sk/agents"
payload := strings.NewReader("{\n \"composerSessionId\": \"9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90\",\n \"name\": \"Senior Developer Phone Screen\",\n \"type\": \"ONLINE\",\n \"focus\": \"SCREENING\",\n \"language\": \"EN\",\n \"duration\": 30,\n \"questions\": [\n \"Tell me about a challenging project you worked on\"\n ],\n \"instructions\": \"Focus on communication skills and team fit\",\n \"companyPhoneNumberId\": \"123e4567-e89b-12d3-a456-426614174000\",\n \"metadata\": {\n \"department\": \"Sales\",\n \"internalId\": \"AGENT-001\"\n },\n \"cefrLevel\": \"B1\",\n \"backgroundSound\": \"OFFICE\",\n \"contextConfig\": {\n \"role\": \"an account executive for Acme\",\n \"communicationStyle\": \"concise and direct\",\n \"callToAction\": \"book a 30-minute demo\",\n \"useContactContext\": true\n },\n \"analyticsConfig\": {\n \"extractionTargets\": [\n {\n \"label\": \"Budget confirmed\",\n \"type\": \"bool\",\n \"key\": \"budget_confirmed\",\n \"enumValues\": [\n \"hot\",\n \"warm\",\n \"cold\"\n ],\n \"ideal\": \"A confirmed budget of at least 10k\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"scoringCriteria\": [\n {\n \"label\": \"Handled objections\",\n \"description\": \"Acknowledged the objection and answered it with a concrete example\",\n \"key\": \"handled_objections\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"outcomes\": [\n {\n \"label\": \"Meeting booked\",\n \"description\": \"The contact agreed to a specific date and time\",\n \"key\": \"meeting_booked\"\n }\n ],\n \"outputTags\": [\n {\n \"label\": \"Needs follow-up\",\n \"key\": \"needs_followup\",\n \"description\": \"The contact asked to be called back\"\n }\n ],\n \"capture\": {\n \"recording\": true,\n \"transcript\": true,\n \"summary\": true,\n \"qa\": true,\n \"evaluation\": true,\n \"sentiment\": true\n }\n },\n \"callConfig\": {},\n \"overrides\": {\n \"companyName\": \"Acme Manufacturing\",\n \"companyDescription\": \"Acme makes industrial fasteners and employs 400 people across Slovakia.\"\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.instaview.sk/agents")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"composerSessionId\": \"9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90\",\n \"name\": \"Senior Developer Phone Screen\",\n \"type\": \"ONLINE\",\n \"focus\": \"SCREENING\",\n \"language\": \"EN\",\n \"duration\": 30,\n \"questions\": [\n \"Tell me about a challenging project you worked on\"\n ],\n \"instructions\": \"Focus on communication skills and team fit\",\n \"companyPhoneNumberId\": \"123e4567-e89b-12d3-a456-426614174000\",\n \"metadata\": {\n \"department\": \"Sales\",\n \"internalId\": \"AGENT-001\"\n },\n \"cefrLevel\": \"B1\",\n \"backgroundSound\": \"OFFICE\",\n \"contextConfig\": {\n \"role\": \"an account executive for Acme\",\n \"communicationStyle\": \"concise and direct\",\n \"callToAction\": \"book a 30-minute demo\",\n \"useContactContext\": true\n },\n \"analyticsConfig\": {\n \"extractionTargets\": [\n {\n \"label\": \"Budget confirmed\",\n \"type\": \"bool\",\n \"key\": \"budget_confirmed\",\n \"enumValues\": [\n \"hot\",\n \"warm\",\n \"cold\"\n ],\n \"ideal\": \"A confirmed budget of at least 10k\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"scoringCriteria\": [\n {\n \"label\": \"Handled objections\",\n \"description\": \"Acknowledged the objection and answered it with a concrete example\",\n \"key\": \"handled_objections\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"outcomes\": [\n {\n \"label\": \"Meeting booked\",\n \"description\": \"The contact agreed to a specific date and time\",\n \"key\": \"meeting_booked\"\n }\n ],\n \"outputTags\": [\n {\n \"label\": \"Needs follow-up\",\n \"key\": \"needs_followup\",\n \"description\": \"The contact asked to be called back\"\n }\n ],\n \"capture\": {\n \"recording\": true,\n \"transcript\": true,\n \"summary\": true,\n \"qa\": true,\n \"evaluation\": true,\n \"sentiment\": true\n }\n },\n \"callConfig\": {},\n \"overrides\": {\n \"companyName\": \"Acme Manufacturing\",\n \"companyDescription\": \"Acme makes industrial fasteners and employs 400 people across Slovakia.\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.instaview.sk/agents")
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 \"composerSessionId\": \"9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90\",\n \"name\": \"Senior Developer Phone Screen\",\n \"type\": \"ONLINE\",\n \"focus\": \"SCREENING\",\n \"language\": \"EN\",\n \"duration\": 30,\n \"questions\": [\n \"Tell me about a challenging project you worked on\"\n ],\n \"instructions\": \"Focus on communication skills and team fit\",\n \"companyPhoneNumberId\": \"123e4567-e89b-12d3-a456-426614174000\",\n \"metadata\": {\n \"department\": \"Sales\",\n \"internalId\": \"AGENT-001\"\n },\n \"cefrLevel\": \"B1\",\n \"backgroundSound\": \"OFFICE\",\n \"contextConfig\": {\n \"role\": \"an account executive for Acme\",\n \"communicationStyle\": \"concise and direct\",\n \"callToAction\": \"book a 30-minute demo\",\n \"useContactContext\": true\n },\n \"analyticsConfig\": {\n \"extractionTargets\": [\n {\n \"label\": \"Budget confirmed\",\n \"type\": \"bool\",\n \"key\": \"budget_confirmed\",\n \"enumValues\": [\n \"hot\",\n \"warm\",\n \"cold\"\n ],\n \"ideal\": \"A confirmed budget of at least 10k\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"scoringCriteria\": [\n {\n \"label\": \"Handled objections\",\n \"description\": \"Acknowledged the objection and answered it with a concrete example\",\n \"key\": \"handled_objections\",\n \"importance\": \"PREFERRED\",\n \"weight\": 40\n }\n ],\n \"outcomes\": [\n {\n \"label\": \"Meeting booked\",\n \"description\": \"The contact agreed to a specific date and time\",\n \"key\": \"meeting_booked\"\n }\n ],\n \"outputTags\": [\n {\n \"label\": \"Needs follow-up\",\n \"key\": \"needs_followup\",\n \"description\": \"The contact asked to be called back\"\n }\n ],\n \"capture\": {\n \"recording\": true,\n \"transcript\": true,\n \"summary\": true,\n \"qa\": true,\n \"evaluation\": true,\n \"sentiment\": true\n }\n },\n \"callConfig\": {},\n \"overrides\": {\n \"companyName\": \"Acme Manufacturing\",\n \"companyDescription\": \"Acme makes industrial fasteners and employs 400 people across Slovakia.\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Frontend Developer Interview",
"type": "ONLINE",
"focus": "SCREENING",
"language": "EN",
"duration": 30,
"createdAt": "2025-11-20T10:30:00Z",
"updatedAt": "2025-11-20T10:30:00Z",
"questions": [
"What is your experience with React?"
],
"instructions": "Focus on technical skills and previous project experience",
"voiceId": "ALEX",
"companyId": "123e4567-e89b-12d3-a456-426614174000",
"metadata": {
"department": "Sales"
},
"cefrLevel": "B1",
"backgroundSound": "OFFICE",
"flow": {
"firstMessage": {
"type": "first_message",
"text": "Hi {{contact.firstName}}, do you have two minutes?",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "Qualify budget"
},
"sections": [
{
"type": "sequential",
"prompt": "Introduce yourself and explain why you are calling.",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "Qualify budget"
}
],
"lastMessage": {
"type": "last_message",
"text": "Thanks for your time — have a great day!",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "Qualify budget"
},
"schemaVersion": "1.0.0"
},
"guardrails": {
"rules": [
"Never quote a price",
"Never promise a delivery date"
]
},
"contextConfig": {
"role": "an account executive for Acme",
"communicationStyle": "concise and direct",
"callToAction": "book a 30-minute demo",
"useContactContext": true
},
"analyticsConfig": {
"extractionTargets": [
{
"label": "Budget confirmed",
"type": "bool",
"key": "budget_confirmed",
"enumValues": [
"hot",
"warm",
"cold"
],
"ideal": "A confirmed budget of at least 10k",
"importance": "PREFERRED",
"weight": 40
}
],
"scoringCriteria": [
{
"label": "Handled objections",
"description": "Acknowledged the objection and answered it with a concrete example",
"key": "handled_objections",
"importance": "PREFERRED",
"weight": 40
}
],
"outcomes": [
{
"label": "Meeting booked",
"description": "The contact agreed to a specific date and time",
"key": "meeting_booked"
}
],
"outputTags": [
{
"label": "Needs follow-up",
"key": "needs_followup",
"description": "The contact asked to be called back"
}
],
"capture": {
"recording": true,
"transcript": true,
"summary": true,
"qa": true,
"evaluation": true,
"sentiment": true
}
},
"callConfig": {
"retryPolicy": {
"maxAttempts": 3
},
"callWindow": {
"mode": "custom",
"days": [
"mon",
"tue",
"wed",
"thu",
"fri"
],
"start": "09:00",
"end": "18:00",
"timezoneAnchor": {
"mode": "contact",
"timezone": "Europe/Bratislava",
"fallbackTimezone": "Europe/Bratislava"
}
}
},
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
}
}Overview
An agent conducts the conversation with your contact. Give it a voice, afocus (or a custom flow of your own), the questions it should ask and how to judge the answers. One agent can run any number of conversations.
Use Cases
- Technical Screening: Create agents for technical skill assessments
- Behavioural screens: Configure agents for soft skills evaluation
- Culture Fit Assessment: Set up agents to evaluate cultural alignment
- Initial Screening: Create quick screening agents for high-volume applications
Basic Agent Creation
{
"name": "Technical Screening Agent",
"type": "ONLINE",
"focus": "SCREENING",
"language": "EN",
"duration": 30,
"questions": [
"Tell me about your React experience",
"Explain microservices architecture"
]
}
Comprehensive Agent Configuration
Note: The duration field is specified in minutes (maximum 180 minutes).
{
"name": "Senior Engineer Technical Interview",
"type": "ONLINE",
"focus": "SCREENING",
"language": "EN",
"duration": 30,
"questions": [
"Describe your experience with system design",
"Explain how you would scale a web application",
"Tell me about a challenging technical problem you solved"
],
"instructions": "Focus on technical depth and accuracy, problem-solving approach, and communication clarity"
}
Phone Agents
When creating an agent withtype: "PHONE", you must provide a valid companyPhoneNumberId. This ID corresponds to a phone number assigned to your company that the agent will use for calls.
{
"name": "Phone Screening Agent",
"type": "PHONE",
"focus": "SCREENING",
"language": "EN",
"duration": 15,
"companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
"questions": [
"Are you available for a 30-minute call next week?",
"What is your expected salary range?"
]
}
Background Sound
UsebackgroundSound to control the ambient noise played to the contact during calls.
| Value | Description |
|---|---|
OFFICE | Subtle office ambient noise (default) |
OFF | Complete silence |
{
"name": "Phone Screening Agent",
"type": "PHONE",
"focus": "SCREENING",
"language": "EN",
"duration": 15,
"companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
"backgroundSound": "OFFICE",
"questions": [
"Are you available for a 30-minute call next week?"
]
}
Voice Options
- ALEX (Male)
- PETER (Male)
- MIRIAM (Female)
- SUE (Female)
- VIERA (Female)
- CASANDRA (Female)
- SILVIA (Female)
- MICHAEL (Male)
- LUKE (Male)
- EMMA (Female)
- SARAH (Female)
- EVA (Female)
Agent Focus
focus sets what kind of call the agent runs. Four are supported, all of them hiring-shaped; for anything else send a flow instead and the agent becomes a custom one with no focus at all:
- GENERIC: job-optional. The conversation is not about a particular job, so no job assignment is needed — talent-pool building, general outreach, a first call before anyone is matched to a role.
- SCREENING: a hiring screen, evaluating the contact against a job’s requirements.
- OUTREACH: a first call to gauge interest and re-engage people already in your database.
- LANGUAGE_TEST: language proficiency, scored against CEFR.
Example with Focus
{
"name": "Talent Pool Agent",
"type": "ONLINE",
"focus": "GENERIC",
"language": "EN",
"duration": 30,
"questions": [
"Tell me about your career goals",
"What type of opportunities are you looking for?"
]
}
focus: "GENERIC" does not need a job, and
the contact may hold any number of job assignments — they are simply not used. You may
still attach a job explicitly if you want the conversation recorded against one. Custom agents
(created with a flow) are jobless rather than job-optional and reject an attached job
outright. See the Create Conversation
documentation for more details.Speaking for Another Company
By default an agent introduces itself as the company your API key belongs to. If you call on behalf of your own customers,overrides lets each agent speak as one of them instead:
{
"name": "Acme Warehouse Screening",
"type": "PHONE",
"focus": "SCREENING",
"language": "EN",
"duration": 15,
"companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
}
}
companyName on its own
leaves your own company’s description in place — the agent introduces itself as Acme and
then describes you. If your company profile has a description, override both.Creating from a Composer Session
If you would rather describe the agent than write aflow, design it first and create it from the session you get back:
{ "composerSessionId": "9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90" }
{ "composerSessionId": "…", "name": "Backend Screen v2" } — or post the preview’s agent object yourself, with the session id attached, if you edited it locally first. Anything you send wins over the preview.
While composerSessionId is present, name, type, language and duration are optional: the session already has them.
Custom Agents
Instead of picking afocus and a list of questions, you can design the whole conversation yourself by sending a flow. An agent created with a flow is a custom agent: it runs the conversation you designed rather than one of the built-in templates, which is what makes it usable outside hiring — sales outreach, support callbacks, operations checks.
A flow is a firstMessage, one or more sections, and a lastMessage. sections is the body of the conversation: every step you can add on the builder canvas is one entry in that array, and its type decides the rest of its shape.
| Step in the visual builder | type | Purpose |
|---|---|---|
| Topic / agenda | sequential | A topic to cover, written as a free-text prompt |
| Question set | looping | A list of questions, each with an optional idealAnswer to score it against |
| Conditional route | conditional | branches, each with a label, a condition and its own nested blocks |
focus with a flow. An agent that carries a flow is custom by
definition, so its focus is derived — sending both is rejected.schemaVersion are assigned by InstaView. Do not send id,
defaultBranchId or schemaVersion anywhere in the flow; a request that does is
rejected. To give a conditional a fallthrough route, set defaultBranch to the
label of the branch it should fall through to. A flow read back from the API
contains the assigned ids and version, so strip all three before sending it again —
everything you authored, defaultBranch included, comes back as you wrote it, so a
stripped flow re-creates the same conversation.flow:
guardrails—{ "rules": [...] }, things the agent must always or never do (max 50).contextConfig— who the agent is (role,communicationStyle), what the call is for (callToAction), and whether the agent is told what you know about the person it is calling (useContactContext).callConfig— how persistently the agent calls, and when. See Retries and calling hours.
communicationStyle is one of a fixed set — professional, friendly, warm and empathetic, assertive, concise and direct, enthusiastic, casual — the same list the visual builder offers, so an agent created over the API stays editable there.
overrides.{
"name": "Outbound Discovery Call",
"type": "PHONE",
"language": "EN",
"duration": 10,
"companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
"flow": {
"firstMessage": { "type": "first_message", "text": "Hi {{contact.first_name}}, do you have two minutes?" },
"sections": [
{ "type": "sequential", "label": "Intro", "prompt": "Introduce yourself and why you are calling." },
{
"type": "looping",
"questions": [
{ "question": "What are you using today?", "idealAnswer": "Names a competing tool" },
{ "question": "What is your timeline?", "idealAnswer": "Within this quarter" }
]
},
{
"type": "conditional",
"defaultBranch": "Not now",
"branches": [
{
"label": "Interested",
"condition": { "type": "intent", "description": "wants to see a demo" },
"blocks": [{ "type": "sequential", "prompt": "Offer two slots this week and confirm one." }]
},
{
"label": "Not now",
"condition": { "type": "intent", "description": "declines or asks to be contacted later" },
"blocks": [{ "type": "sequential", "prompt": "Ask when to follow up and thank them." }]
}
]
}
],
"lastMessage": { "type": "last_message", "text": "Thanks for your time — have a great day!" }
},
"guardrails": { "rules": ["Never quote a price", "Never promise a delivery date"] },
"contextConfig": {
"role": "an account executive for Acme",
"communicationStyle": "concise and direct",
"callToAction": "book a 30-minute demo",
"useContactContext": true
}
}
Telling the agent about the person it is calling
contextConfig.useContactContext gives the agent a short summary of what you hold about each
contact, built per call — so one agent serves a whole list and each call is told about the
person actually on the line.
"contextConfig": { "role": "an account executive for Acme", "useContactContext": true }
// 1. Define a field
POST /contact-fields
{ "key": "plan_name", "label": "Plan", "dataType": "string" }
// 2. Store a value for a contact
PATCH /contacts/{id}
{ "fields": { "plan_name": "Growth" } }
// 3. Turn it on for the agent
PATCH /agents/{id}
{ "contextConfig": { "useContactContext": true } }
isPii reach neither half. They are excluded from the prompt and from the
document, which is what keeps email and phone off every call without anyone deciding. To
let one through, set allowPiiInContext on that field and the value joins both. There are
cases where that is the point — an amount owed on a collections call — and cases where it
is a liability. Nothing turns it on for you.Section types
Everything the visual builder can put in a conversation is expressed insidesections — the API is not a reduced version of the builder. A section is an object with a type, and type selects which other fields it carries. In the schema reference on the right this is a oneOf on the sections items, which renders collapsed, so the four shapes are written out here in full.
label is optional on every section and is only a name for the step; it is what the builder shows on the canvas. id is assigned by InstaView — never send one.
sequential — a topic to cover
A step written as a free-text instruction, for when you want the agent to cover something in its own words rather than ask a fixed question. Supports {{contact.*}} variables.
{
"type": "sequential",
"label": "Intro",
"prompt": "Introduce yourself, say you are calling about their trial, and ask if now is a good time."
}
looping — a set of questions
A list of questions the agent works through. One block can hold several questions; use separate blocks when you want them in different places in the conversation.
question is the only required field. idealAnswer is what a good answer looks like, and it is optional: a question without one is still asked, just never scored. That is how you write a question set with no right answers, such as an internal survey or a satisfaction check.
importance and weight are how a question joins the agent’s match score: set either one to score it (REQUIRED gates the score, PREFERRED contributes by weight), and a question with neither is asked but not scored. They sit on the question itself rather than in analyticsConfig because a question is addressed by an id InstaView assigns, which you cannot know while writing the flow.
{
"type": "looping",
"label": "Qualify",
"questions": [
{ "question": "What are you using today?", "idealAnswer": "Names a competing tool" },
{
"question": "What is your timeline?",
"idealAnswer": "Within this quarter",
"importance": "REQUIRED",
"weight": 40
}
]
}
conditional — take a different route
Splits the conversation. The agent evaluates the branches in order and follows exactly one; blocks is the route it then works through.
blocks holds sections of any type, including another conditional, which is how you build a decision tree. condition is usually { "type": "intent", "description": "..." } — a plain-language intent the agent reads off the conversation — and may instead be an expression for a deterministic test on an extracted field. defaultBranch is the fallthrough taken when no condition matches, and it addresses the branch by its label, because branch ids are assigned by InstaView.
The condition is what the agent routes on, so it has to be one it can read. Every entry in branches must be an object to begin with (CONDITIONAL_BRANCH_NOT_AN_OBJECT), and every branch needs a condition of one of those two shapes: a missing or non-object condition is a 422 (CONDITIONAL_CONDITION_MISSING), a type that is neither intent nor expression is CONDITIONAL_CONDITION_TYPE_UNKNOWN, and a condition of a known type missing what that type needs — an intent without a description, an expression without a field, with an operator outside the documented set, or with no value for an operator other than EXISTS — is CONDITIONAL_CONDITION_INVALID. The path names the branch, e.g. sections[0].branches[1].condition. The condition on the branch you nominate as defaultBranch is checked like any other: it is not read while that branch is the fallthrough, but moving defaultBranch elsewhere later would put it back in charge of a route.
{
"type": "conditional",
"label": "Interest check",
"defaultBranch": "Not now",
"branches": [
{
"label": "Interested",
"condition": { "type": "intent", "description": "wants to see a demo" },
"blocks": [
{ "type": "sequential", "prompt": "Offer two slots this week and confirm one." },
{
"type": "looping",
"questions": [
{ "question": "Who else should join the demo?", "idealAnswer": "Names a decision maker" }
]
}
]
},
{
"label": "Not now",
"condition": { "type": "intent", "description": "declines or asks to be contacted later" },
"blocks": [{ "type": "sequential", "prompt": "Ask when to follow up and thank them." }]
}
]
}
human_handoff — hand the call to a person
Ends the agent’s part of the call and transfers it to a phone number. phoneNumber is required and must be E.164 (+, country code, no spaces or dashes); a number the dialler could not use is rejected at design time rather than at the moment of transfer.
message is what the agent says immediately before transferring, and it is optional — omit it and InstaView supplies a neutral line in the call’s language. That default says only that a transfer is happening: the block knows a number and nothing else, so it cannot claim who picks up. Send a message when you do know. It supports {{contact.*}} variables like any other text in a flow. Sending message as an empty string is rejected rather than treated as absent, so clearing the field cannot silently give you the default back.
{
"type": "human_handoff",
"label": "Sales",
"phoneNumber": "+421900123456",
"message": "I'll put you through to Martin on our sales team now, one moment."
}
human_handoff ever runs, including your lastMessage. The conversation
settles as completed with the call recorded as forwarded, and the transcript covers your
agent’s part of the call only — what the two people then say to each other is not ours to
record.Because such a step could never run, a handoff must be the last block in its own list,
and a sibling after it is rejected with HUMAN_HANDOFF_NOT_LAST. That is scoped to
immediate siblings: a handoff ending one branch of a conditional says nothing about the
sections after that conditional, which the other branches still reach.ONLINE agent has no call to transfer, so a flow carrying a
handoff is rejected with a 422 (HUMAN_HANDOFF_NOT_PHONE) rather than creating an
agent with a step that could never fire.conditional branch, which is the useful shape: route on intent, then transfer to the number that fits. Two branches transferring to the same number are one destination, not two — handoffs are deduplicated by number.
label on every handoff, and they must
differ. The agent is offered all reachable destinations at once and chooses between them
by label — the number is deliberately never in its prompt — so two destinations described
alike would make the choice a coin flip that lands a caller on the wrong team. Missing
labels are HUMAN_HANDOFF_LABEL_REQUIRED and a collision is
HUMAN_HANDOFF_LABEL_DUPLICATE. A single-destination flow needs no label: there is nothing
to tell apart. Two blocks pointing at the same number are one destination, so they may
share a label, or go without one.conditional the agent routes on while it still has the call,
not a property of the handoff.Limits
| What | Limit |
|---|---|
| Sections in a flow | 1–100 |
Questions in a looping block | 1–50 |
Branches on a conditional | 2–5 |
| Sections in one branch | up to 50 |
| Nesting depth of conditionals | 3 |
422.
type is simply an unknown block: it comes back as UNKNOWN_BLOCK_TYPE
in the errors array, alongside every other fault in the document.A type may still be added to the schema before it works, and while it is in that state
sending one is rejected with a 422 naming the block and the types you may use instead.
That list is generated from what is actually built, so it is the authoritative answer to
what a section may be at any given moment.Flow Validation Errors
The flow is validated when you create the agent, using the same rules as the visual builder — an invalid flow is rejected with422, rather than failing later when a call is placed.
The rejection carries an errors array with every problem found in the document, so fixing a flow does not take one request per fault. Each entry has a machine-readable code and the path of the offending node in the flow you sent, which is what to anchor an editor or an error list to.
{
"statusCode": 422,
"message": "Invalid conversation flow.",
"errors": [
{
"code": "UNKNOWN_BLOCK_TYPE",
"message": "Unknown block type: teleport.",
"path": "sections[2].branches[0].blocks[1]"
},
{
"code": "SEQUENTIAL_PROMPT_EMPTY",
"message": "Sequential block prompt must not be empty.",
"path": "sections[0]"
}
],
"traceId": "6a707aee000000000c1e285eefed9980"
}
message for the rest. The set of
codes grows as the flow schema does, and a new one is added without a major version.path is the anchor, and the only one. Block ids are assigned by InstaView when a
flow is stored, so a flow that was just rejected has none to report — errors address
the document you sent, by position.422 on this route is a flow-validation failure — one of the size limits above, a block type that is not available yet, or a companyPhoneNumberId that is not yours, is also a 422. Those carry a message and no errors array, so treat errors as optional:
{
"statusCode": 422,
"message": "Branch blocks at sections[2].branches[0] exceeds the maximum of 50 (received 51).",
"traceId": "6a707aee000000000c1e285eefed9980"
}
422 shape is returned by Update Agent and by an inline agent on Create Conversation.
Analytics
analyticsConfig says what should come back after every call. Without it a custom agent places a call and returns a transcript; with it you get structured data your own systems can act on. Like guardrails and contextConfig, it is accepted only alongside a flow.
| Field | What it does |
|---|---|
extractionTargets | The values to pull out of each call. A target with an ideal also counts toward the match score. |
scoringCriteria | Holistic judgements over the whole call — “handled objections”, “built rapport”. |
outcomes | Did the call achieve what it was for? Decided met / not met per call. |
outputTags | Labels the AI may assign to a call. |
capture | Which qualitative artefacts to produce (summary, Q&A, evaluation, sentiment, recording, transcript). All default to true. |
{
// …name, type, language, duration, flow as above…
"analyticsConfig": {
"extractionTargets": [
{
"key": "budget_confirmed",
"label": "Budget confirmed",
"type": "bool",
"ideal": "A confirmed budget of at least 10k",
"importance": "REQUIRED",
"weight": 50
},
{ "label": "Current tool", "type": "string" }
],
"scoringCriteria": [
{
"label": "Handled objections",
"description": "Acknowledged the objection and answered it with a concrete example",
"weight": 20
}
],
"outcomes": [
{ "label": "Meeting booked", "description": "The contact agreed to a specific date and time" }
],
"outputTags": [{ "label": "Needs follow-up", "description": "The contact asked to be called back" }],
"capture": { "sentiment": false }
}
}
Keys are yours
Every item has akey — the name its results come back under. Set it if your integration reads results by name. A key you choose is stable; a derived one is not:
- Omit
keyand InstaView derives a slug oflabel(Budget confirmed→budget_confirmed). Convenient, but renaming the label later silently moves the results to a new key, and your consumer breaks with a200. Two labels that slug to the same thing get a numeric suffix —BudgetandBudget?becomebudgetandbudget_2, in the order you listed them. - Send
keyand it is used verbatim, whatever you do to the label afterwards. Letters, digits and underscores, up to 64 characters, unique within its list — a duplicate you sent is rejected with400rather than quietly renamed, and__proto__,constructorandprototypeare refused because they cannot be used as field names in the results.
Scoring a flow question
Questions join the match score inline, on the question itself — not throughanalyticsConfig:
{
"type": "looping",
"questions": [
{ "question": "What are you using today?", "idealAnswer": "Names a competing tool", "importance": "REQUIRED", "weight": 30 },
{ "question": "What is your timeline?", "idealAnswer": "Within this quarter" },
{ "question": "How has the rollout felt so far?" }
]
}
idealAnswer but no importance or weight, so it stays out of the score — nothing is scored that you did not ask for. The third has no idealAnswer at all, so it cannot be scored even if you set importance on it.
50 / 30 / 20 and 5 / 3 / 2 score identically. Results report each item’s share as a percentage.
The results arrive as analytics on the conversation (Get Conversation) and on the analysis.completed webhook.
Retries and calling hours
callConfig answers two questions: how many times a contact who does not answer is called, and when the agent is allowed to dial.
| Field | What it does |
|---|---|
retryPolicy.maxAttempts | Attempts per contact, counting the first, 1–5. Reschedules the contact asks for come out of this budget; a network failure that never reached them does not. |
callWindow.days | Days the agent may call on, from mon … sun. |
callWindow.start / callWindow.end | Local hours the agent may call between, "HH:mm" on a 24-hour clock. end is exclusive and must be later in the day than start. |
callWindow.timezoneAnchor | Whose clock start and end are on. This is the field that decides what the hours actually mean. |
callConfig and a new agent calls Mon–Fri, 09:00–18:00, in each contact’s own timezone, three attempts each.
Whose 09:00?
timezoneAnchor.mode is either contact or fixed.
With contact, the contact’s timezone is detected from their phone number, down to the area code — not from their country. On one list, a +1 212 number is called at 09:00 in New York, a +1 310 number at 09:00 in Los Angeles, and a +1 602 number at 09:00 in Phoenix, which does not observe daylight saving at all. The same holds inside any country that spans zones: +7 4212 is Vladivostok rather than Moscow, +55 92 is Manaus rather than São Paulo, +52 664 is Tijuana rather than Mexico City.
{
// …name, type, language, duration, flow as above…
"callConfig": {
"retryPolicy": { "maxAttempts": 3 },
"callWindow": {
"days": ["mon", "tue", "wed", "thu", "fri"],
"start": "09:00",
"end": "18:00",
"timezoneAnchor": { "mode": "contact" }
}
}
}
fixed, every contact is called on one named IANA zone, wherever they are — the right choice when the hours belong to your own operation rather than to the person being called.
{
"callConfig": {
"callWindow": {
"days": ["mon", "tue", "wed", "thu", "fri"],
"start": "09:00",
"end": "17:00",
"timezoneAnchor": { "mode": "fixed", "timezone": "Europe/Bratislava" }
}
}
}
422 on this request rather than a schedule that quietly never fires.
+61 8 number could be in
Adelaide or Perth, up to two hours apart, and a phone number cannot tell you which. In that
case the agent waits until the hours you set are correct in every contact’s zone rather
than picking one — so an uncertain contact is called a little later, never two hours too
early. timezoneAnchor.fallbackTimezone (default Europe/Bratislava) covers the rarer case
where a number resolves to no timezone at all.09:00–10:00 cannot be true in both Adelaide and Perth at once. When that happens the
contact is called anyway rather than left uncalled indefinitely, and the call is recorded as
having gone out outside the window. Widening the window, or pinning the anchor to fixed, is
how you avoid it.scheduleTime goes out, and every retry after a call that did not
connect. Pass a scheduleTime on POST /conversations, or a time on either call-attempt
route, and the call is placed then even if the window is shut, because you have told us
something the window cannot know. If you would rather your window always won, keep sending
times inside it: an appointment your contact agreed to is usually the case where you want the
override, and a bulk import is usually the case where you want to omit scheduleTime and let
the window place the call.Agents created before calling windows existed
An agent from before this was configurable reports acallWindow.mode of business_hours and no other window fields:
{
"callConfig": {
"retryPolicy": { "maxAttempts": 3 },
"callWindow": { "mode": "business_hours" }
}
}
callWindow is how such an agent is moved onto a real one.
Contact Variables
Any text in a flow — messages, prompts, questions — may contain{{contact.<key>}} placeholders. They are not filled in when you create the agent: the agent is compiled once and the placeholders are resolved per call, so one agent serves every person you call.
Seven keys are always available. The first four come from the contact on the conversation; the rest come from your company profile and the agent itself:
| Key | Value |
|---|---|
{{contact.first_name}} | The contact’s first name |
{{contact.last_name}} | The contact’s last name |
{{contact.email}} | The contact’s email |
{{contact.phone}} | The contact’s phone number |
{{contact.company_name}} | Your company’s name |
{{contact.company_description}} | The description on your company profile |
{{contact.agent_name}} | The voice agent’s own name |
fields when you create the contact, then reference them by key:
POST /contacts
{
"firstName": "Jana",
"lastName": "Novák",
"phoneNumber": "+421900123456",
"fields": { "order_number": "AB-99", "renewal_date": "12 September" }
}
// …then, in the flow:
{ "type": "sequential", "prompt": "Confirm order {{contact.order_number}} renews on {{contact.renewal_date}}." }
a-z, 0-9 and _, and each one has to be a field in your company’s catalog —
read GET /contact-fields for the ones
you have, or pass ?createMissingFields=true on the contact write to have a new key defined
for you. A key with no value resolves to an empty string rather than being spoken aloud, so a
missing variable degrades quietly — but write prompts that still read correctly without it.
The seven system keys above are reserved: sending one in fields is a 422 naming the key,
not a write that quietly does nothing. first_name, last_name, email and phone are set
through their own properties on the contact; the other three are resolved by the platform and
cannot hold a per-contact value at all.Company Scoping
companyId query parameter.Related Resources
Agents Resource Guide
Conversations Resource Guide
API Reference
Authorizations
API key for authentication using Bearer scheme
Query Parameters
Required for ATS API keys to specify which company to access. Ignored for standard company API keys.
Body
- Option 1
- Option 2
Create this agent from a composer session (POST /agents/composer). Send it alone to build exactly what the preview showed, or alongside your own fields to override parts of it — anything you send wins. The session's conversation is attached to the new agent. While it is present, name, type, language and duration are optional: the session already has them.
"9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90"
Agent name
2 - 100"Senior Developer Phone Screen"
Type of the agent
UNDEFINED, ONLINE, PHONE "ONLINE"
Focus of the agent. GENERIC: job-optional, for a conversation that is not about a particular job. SCREENING: a hiring screen against a job's requirements. OUTREACH: a first call to gauge interest. LANGUAGE_TEST: language proficiency. Required unless a conversation flow is provided: an agent with a flow is a custom agent, whose focus is derived rather than selected. Sending both is rejected.
GENERIC, SCREENING, OUTREACH, LANGUAGE_TEST "SCREENING"
Language of the conversation
UNDEFINED, EN, JA, ZH, DE, HI, FR, KO, PT, IT, ES, ID, NL, TR, FIL, PL, SV, BG, RO, AR, CS, EL, FI, HR, MS, SK, DA, TA, UK, RU, HU, NO, VI "EN"
Duration of the conversation in minutes
1 <= x <= 18030
List of questions for the conversation
[
"Tell me about a challenging project you worked on"
]
Additional instructions for the conversation
"Focus on communication skills and team fit"
Voice ID the agent speaks with
ALEX, PETER, MIRIAM, SUE, VIERA, CASANDRA, SILVIA, MICHAEL, LUKE, EMMA, SARAH, EVA ID of the company phone number assignment to use for calls from this agent (CompanyPhoneNumber.id)
"123e4567-e89b-12d3-a456-426614174000"
Custom metadata for the agent (max 10KB, 5 levels deep, 50 keys)
{
"department": "Sales",
"internalId": "AGENT-001"
}
CEFR level for language test agents
A1, A2, B1, B2, C1, C2 "B1"
Ambient background sound during calls (OFFICE or OFF). Defaults to OFFICE when omitted.
OFF, OFFICE "OFFICE"
Conversation flow graph. Providing it makes this a custom agent, so focus must be omitted. guardrails and contextConfig are accepted only alongside a flow. Validated on write: an invalid flow is rejected with 422 rather than failing when a call is placed.
Show child attributes
Show child attributes
Rules the agent must obey during the call. Accepted only alongside a flow — sending it for an agent that will not be custom is rejected.
Show child attributes
Show child attributes
Who the agent is and what the call is about. Accepted only alongside a flow — sending it for an agent that will not be custom is rejected.
Show child attributes
Show child attributes
What to extract, score, decide and label after every call. Accepted only alongside a flow — sending it for an agent that will not be custom is rejected. Per-question scoring is set inline on the flow's looping questions, not here.
Show child attributes
Show child attributes
How persistently and when the agent calls: how many attempts a contact who does not answer gets, and the days, local hours and timezone the agent may dial in. Accepted only alongside a flow. Omitted, a new agent calls Mon–Fri 09:00–18:00 in each contact's own timezone.
Show child attributes
Show child attributes
Who this agent says it is on a call. By default it introduces itself as the company your API key belongs to; send this to have it speak for one of your own customers instead. Unlike guardrails and contextConfig, this is accepted with or without a flow.
Show child attributes
Show child attributes
Response
Agent ID
"123e4567-e89b-12d3-a456-426614174000"
Agent name
"Frontend Developer Interview"
Type of the agent
UNDEFINED, ONLINE, PHONE "ONLINE"
Focus of the agent. GENERIC: job-optional, for a conversation that is not about a particular job. SCREENING: a hiring screen against a job's requirements. OUTREACH: a first call to gauge interest. LANGUAGE_TEST: language proficiency.
GENERIC, SCREENING, OUTREACH, LANGUAGE_TEST "SCREENING"
Language of the conversation
UNDEFINED, EN, JA, ZH, DE, HI, FR, KO, PT, IT, ES, ID, NL, TR, FIL, PL, SV, BG, RO, AR, CS, EL, FI, HR, MS, SK, DA, TA, UK, RU, HU, NO, VI "EN"
Duration of the conversation in minutes
30
Agent creation timestamp (UTC)
"2025-11-20T10:30:00Z"
Agent last update timestamp (UTC)
"2025-11-20T10:30:00Z"
List of questions for the conversation
["What is your experience with React?"]
Additional instructions for the conversation
"Focus on technical skills and previous project experience"
Voice ID the agent speaks with
ALEX, PETER, MIRIAM, SUE, VIERA, CASANDRA, SILVIA, MICHAEL, LUKE, EMMA, SARAH, EVA Company ID that owns the agent
"123e4567-e89b-12d3-a456-426614174000"
Custom metadata
{ "department": "Sales" }
CEFR level for language test agents
A1, A2, B1, B2, C1, C2 "B1"
Ambient background sound during calls (OFFICE or OFF). Null means no override is set and the default applies.
OFF, OFFICE "OFFICE"
Conversation flow graph, as designed. Null on a template agent.
Show child attributes
Show child attributes
Rules the agent must obey during the call. Custom agents only; null on a template agent.
Show child attributes
Show child attributes
Who the agent is and what the call is about. Custom agents only; null on a template agent.
Show child attributes
Show child attributes
What the agent extracts, scores, decides and labels after every call. Custom agents only — null on a template agent. Per-question scoring is folded back onto the flow's looping questions rather than returned as an id-keyed map — the same form the write accepts.
Show child attributes
Show child attributes
How persistently and when the agent calls. Custom agents only. An agent created before calling windows were configurable reports a callWindow.mode of business_hours.
Show child attributes
Show child attributes
Who this agent says it is on a call, when that is not the company your API key belongs to. Null when it speaks as your own company.
Show child attributes
Show child attributes