curl --request POST \
--url https://api.instaview.sk/agents/composer/{sessionId}/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"message": "Also ask about relocation, and make the whole call Slovak."
}
'import requests
url = "https://api.instaview.sk/agents/composer/{sessionId}/messages"
payload = { "message": "Also ask about relocation, and make the whole call Slovak." }
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({message: 'Also ask about relocation, and make the whole call Slovak.'})
};
fetch('https://api.instaview.sk/agents/composer/{sessionId}/messages', 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/composer/{sessionId}/messages",
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([
'message' => 'Also ask about relocation, and make the whole call Slovak.'
]),
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/composer/{sessionId}/messages"
payload := strings.NewReader("{\n \"message\": \"Also ask about relocation, and make the whole call Slovak.\"\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/composer/{sessionId}/messages")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"message\": \"Also ask about relocation, and make the whole call Slovak.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.instaview.sk/agents/composer/{sessionId}/messages")
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 \"message\": \"Also ask about relocation, and make the whole call Slovak.\"\n}"
response = http.request(request)
puts response.read_body{
"sessionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"agent": {
"type": "ONLINE",
"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"
},
"name": "Senior Developer Phone Screen",
"language": "EN",
"duration": 123,
"voiceId": "<string>",
"backgroundSound": "OFFICE",
"companyPhoneNumberId": "<string>",
"metadata": {},
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
},
"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": {
"days": [
"mon",
"tue",
"wed",
"thu",
"fri"
],
"start": "09:00",
"end": "18:00",
"timezoneAnchor": {
"mode": "contact",
"timezone": "Europe/Bratislava",
"fallbackTimezone": "Europe/Bratislava"
}
}
}
},
"message": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"role": "user",
"content": "Your agent opens by introducing itself and confirming it's speaking with the right person. It then works through Go and Postgres experience…",
"createdAt": "2023-11-07T05:31:56Z",
"changes": [
"Added a relocation question",
"Set the language to Slovak"
]
},
"expiresAt": "2023-11-07T05:31:56Z"
}{
"statusCode": 422,
"message": "Invalid conversation flow.",
"errors": [
{
"code": "UNKNOWN_BLOCK_TYPE",
"message": "Unknown block type: teleport.",
"path": "sections[2].branches[0].blocks[1]"
}
],
"traceId": "6a707aee000000000c1e285eefed9980"
}Refine a Composed Agent
Applies one plain-language change to the session’s agent — “also ask about relocation”, “make it Slovak”, “drop the salary question” — and returns the updated preview. Still creates nothing.
curl --request POST \
--url https://api.instaview.sk/agents/composer/{sessionId}/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"message": "Also ask about relocation, and make the whole call Slovak."
}
'import requests
url = "https://api.instaview.sk/agents/composer/{sessionId}/messages"
payload = { "message": "Also ask about relocation, and make the whole call Slovak." }
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({message: 'Also ask about relocation, and make the whole call Slovak.'})
};
fetch('https://api.instaview.sk/agents/composer/{sessionId}/messages', 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/composer/{sessionId}/messages",
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([
'message' => 'Also ask about relocation, and make the whole call Slovak.'
]),
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/composer/{sessionId}/messages"
payload := strings.NewReader("{\n \"message\": \"Also ask about relocation, and make the whole call Slovak.\"\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/composer/{sessionId}/messages")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"message\": \"Also ask about relocation, and make the whole call Slovak.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.instaview.sk/agents/composer/{sessionId}/messages")
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 \"message\": \"Also ask about relocation, and make the whole call Slovak.\"\n}"
response = http.request(request)
puts response.read_body{
"sessionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"agent": {
"type": "ONLINE",
"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"
},
"name": "Senior Developer Phone Screen",
"language": "EN",
"duration": 123,
"voiceId": "<string>",
"backgroundSound": "OFFICE",
"companyPhoneNumberId": "<string>",
"metadata": {},
"overrides": {
"companyName": "Acme Manufacturing",
"companyDescription": "Acme makes industrial fasteners and employs 400 people across Slovakia."
},
"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": {
"days": [
"mon",
"tue",
"wed",
"thu",
"fri"
],
"start": "09:00",
"end": "18:00",
"timezoneAnchor": {
"mode": "contact",
"timezone": "Europe/Bratislava",
"fallbackTimezone": "Europe/Bratislava"
}
}
}
},
"message": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"role": "user",
"content": "Your agent opens by introducing itself and confirming it's speaking with the right person. It then works through Go and Postgres experience…",
"createdAt": "2023-11-07T05:31:56Z",
"changes": [
"Added a relocation question",
"Set the language to Slovak"
]
},
"expiresAt": "2023-11-07T05:31:56Z"
}{
"statusCode": 422,
"message": "Invalid conversation flow.",
"errors": [
{
"code": "UNKNOWN_BLOCK_TYPE",
"message": "Unknown block type: teleport.",
"path": "sections[2].branches[0].blocks[1]"
}
],
"traceId": "6a707aee000000000c1e285eefed9980"
}POST /agents/composer/9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90/messages
{ "message": "Also ask about relocation, and make the whole call Slovak." }
agent preview, and a message saying what changed.
POST /agents.You do not send the agent back
The session holds the agent, so a follow-up carries only your instruction. There is nothing to keep in sync on your side, and no way to accidentally send back a stale version of the conversation. You can refine as many times as you like within the session’s 30 days.What a message can do
Anything the visual builder can do to a custom agent — the composer and the in-app copilot are the same thing behind different doors:| You say | What changes |
|---|---|
| ”Also ask about relocation” | A question is added to the right part of the conversation |
| ”Make it Slovak” | The language, and every message and prompt rewritten in it |
| ”Drop the salary question” | That question is removed |
| ”Be more direct, less chatty” | The agent’s communication style |
| ”Score the Go question as required” | How the call is scored afterwards |
| ”Call it something shorter” | The agent’s name |
| ”Transfer strong candidates to +421 900 123 456” | A handoff step (PHONE agents only) |
name when you started the session,
it stays pinned — the composer will not quietly relabel your agent while doing something
else.A rejected change stores nothing
Every turn is validated the same way the create route validates a flow. If a change would break the conversation — emptying a required message, leaving a conditional with one branch — the turn is rejected with a422 and the session is untouched: no half-applied edit, and no record of a message that did not land. Send a different instruction and carry on.
This is also what keeps the promise that the preview is postable: the agent a session hands you has passed the create route’s checks at every step, not just at the start.
Errors
| Status | When |
|---|---|
400 | message missing, empty, or over 4,000 characters |
404 | No live session with that id belongs to your company — including one that expired |
409 | Another message changed this session while yours was being applied. Fetch the session and send it again |
422 | The change could not be applied without breaking the conversation. Nothing was stored |
429 | Composer rate limit reached (10 per minute, 120 per hour) |
503 | The model was unavailable or timed out — the session is unchanged |
404.
They are deliberately indistinguishable.Authorizations
API key for authentication using Bearer scheme
Path Parameters
The composer session id returned by POST /agents/composer.
Query Parameters
Required for ATS API keys to specify which company to access. Ignored for standard company API keys.
Body
What to change, in plain language.
4000"Also ask about relocation, and make the whole call Slovak."
Response
The updated preview and the composer's reply.
The session to send follow-up messages to, and to create the agent from.
The agent the composer would build. There is no id: this agent does not exist yet. Post this object to POST /agents to create it — it is accepted verbatim, with no ids or schemaVersion to strip first.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
When this session is deleted if you never create the agent. Sessions live 30 days.