curl --request POST \
--url https://app.thinnest.ai/api/v1/agents \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"name": "Skyline Sales",
"instructions": "You call people who enquired about a flat at Sky Towers, Baner. Find out their budget, preferred size and when they can visit the site.",
"greeting": "Namaste, I'm calling from Skyline Homes about your enquiry for Sky Towers.",
"businessDescription": "Skyline Homes builds 2 and 3 BHK apartments in Pune.",
"model": "prana-voice",
"language": "Hindi",
"escalation": {
"onRequest": true
},
"voice": {
"voice": "priya",
"summariseCalls": true,
"recordCalls": true,
"maxCallSeconds": 300
},
"collectFields": [
{
"name": "budget",
"type": "number",
"description": "Budget in rupees"
},
{
"name": "interest",
"choices": [
"Hot",
"Warm",
"Cold"
]
}
]
}
EOFconst options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Skyline Sales',
instructions: 'You call people who enquired about a flat at Sky Towers, Baner. Find out their budget, preferred size and when they can visit the site.',
greeting: 'Namaste, I\'m calling from Skyline Homes about your enquiry for Sky Towers.',
businessDescription: 'Skyline Homes builds 2 and 3 BHK apartments in Pune.',
model: 'prana-voice',
language: 'Hindi',
escalation: {onRequest: true},
voice: {voice: 'priya', summariseCalls: true, recordCalls: true, maxCallSeconds: 300},
collectFields: [
{name: 'budget', type: 'number', description: 'Budget in rupees'},
{name: 'interest', choices: ['Hot', 'Warm', 'Cold']}
]
})
};
fetch('https://app.thinnest.ai/api/v1/agents', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.thinnest.ai/api/v1/agents"
payload = {
"name": "Skyline Sales",
"instructions": "You call people who enquired about a flat at Sky Towers, Baner. Find out their budget, preferred size and when they can visit the site.",
"greeting": "Namaste, I'm calling from Skyline Homes about your enquiry for Sky Towers.",
"businessDescription": "Skyline Homes builds 2 and 3 BHK apartments in Pune.",
"model": "prana-voice",
"language": "Hindi",
"escalation": { "onRequest": True },
"voice": {
"voice": "priya",
"summariseCalls": True,
"recordCalls": True,
"maxCallSeconds": 300
},
"collectFields": [
{
"name": "budget",
"type": "number",
"description": "Budget in rupees"
},
{
"name": "interest",
"choices": ["Hot", "Warm", "Cold"]
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "ag_5c4a5f93-2b1e-4d7a-9f60-8e2d1c3b4a71",
"name": "Skyline Sales",
"instructions": "You call people who enquired about a flat at Sky Towers, Baner. Find out their budget, preferred size and when they can visit the site.",
"greeting": "Namaste, I'm calling from Skyline Homes about your enquiry for Sky Towers.",
"businessDescription": "Skyline Homes builds 2 and 3 BHK apartments in Pune.",
"model": "prana-voice",
"temperature": 0.3,
"maxReplyTokens": 300,
"language": "Hindi",
"secondLanguage": null,
"escalation": {
"onNoAnswer": false,
"onRequest": true
},
"captureLeads": true,
"scheduleCallbacks": false,
"steps": [],
"widget": {
"theme": "classic",
"accent": null,
"height": 806,
"welcomeScreen": true,
"welcomeCollectLeads": true
},
"voice": {
"answersCalls": true,
"surfaces": [
"web",
"whatsapp"
],
"voice": "priya",
"phoneNumber": null,
"language": null,
"summariseCalls": true,
"detectMachines": false,
"recordCalls": true,
"maxCallSeconds": 300,
"ringSeconds": 30,
"pastConversations": "quiet",
"unavailableMessage": null,
"unavailableMessageNote": null,
"callStartUrl": null,
"thinking": true,
"thinkingLines": [],
"thinkingDelayMs": 900,
"thinkingRepeatMs": 2500,
"thinkingAtTurnEnd": false,
"turnSilenceSeconds": null,
"turnDetection": null,
"reaskAfterSeconds": null,
"recordDoNotCall": true,
"interruptWords": 3,
"neverInterrupt": false,
"holdShortSpeech": true,
"greetingUninterruptible": false,
"ambience": null,
"ambienceVolume": 0.15,
"endCallOnFinish": false,
"nudgeAfterSeconds": null,
"nudges": 1,
"nudgePhrase": null,
"endAfterSilenceSeconds": null,
"endPhrases": [],
"callInstructions": null
},
"byok": "workspace",
"collectFields": [
{
"name": "budget",
"type": "number",
"description": "Budget in rupees",
"choices": null
},
{
"name": "interest",
"type": "text",
"description": null,
"choices": [
"Hot",
"Warm",
"Cold"
]
}
],
"webKey": "pk_9fQ2xLm7Rt4vWb8KcN3hYd6sJ1pZ",
"createdAt": "2026-10-06T08:12:44.118Z"
}Create Agent
Makes an agent exactly as the console does: a starter persona when you send no instructions, a website widget key, and (where your deployment has voice) a voice channel that answers on the web and WhatsApp. Only name is required. The plan’s agent allowance, its model list and its voice tiers apply; a refused voice undoes the whole create. A build key may do this.
curl --request POST \
--url https://app.thinnest.ai/api/v1/agents \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"name": "Skyline Sales",
"instructions": "You call people who enquired about a flat at Sky Towers, Baner. Find out their budget, preferred size and when they can visit the site.",
"greeting": "Namaste, I'm calling from Skyline Homes about your enquiry for Sky Towers.",
"businessDescription": "Skyline Homes builds 2 and 3 BHK apartments in Pune.",
"model": "prana-voice",
"language": "Hindi",
"escalation": {
"onRequest": true
},
"voice": {
"voice": "priya",
"summariseCalls": true,
"recordCalls": true,
"maxCallSeconds": 300
},
"collectFields": [
{
"name": "budget",
"type": "number",
"description": "Budget in rupees"
},
{
"name": "interest",
"choices": [
"Hot",
"Warm",
"Cold"
]
}
]
}
EOFconst options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Skyline Sales',
instructions: 'You call people who enquired about a flat at Sky Towers, Baner. Find out their budget, preferred size and when they can visit the site.',
greeting: 'Namaste, I\'m calling from Skyline Homes about your enquiry for Sky Towers.',
businessDescription: 'Skyline Homes builds 2 and 3 BHK apartments in Pune.',
model: 'prana-voice',
language: 'Hindi',
escalation: {onRequest: true},
voice: {voice: 'priya', summariseCalls: true, recordCalls: true, maxCallSeconds: 300},
collectFields: [
{name: 'budget', type: 'number', description: 'Budget in rupees'},
{name: 'interest', choices: ['Hot', 'Warm', 'Cold']}
]
})
};
fetch('https://app.thinnest.ai/api/v1/agents', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.thinnest.ai/api/v1/agents"
payload = {
"name": "Skyline Sales",
"instructions": "You call people who enquired about a flat at Sky Towers, Baner. Find out their budget, preferred size and when they can visit the site.",
"greeting": "Namaste, I'm calling from Skyline Homes about your enquiry for Sky Towers.",
"businessDescription": "Skyline Homes builds 2 and 3 BHK apartments in Pune.",
"model": "prana-voice",
"language": "Hindi",
"escalation": { "onRequest": True },
"voice": {
"voice": "priya",
"summariseCalls": True,
"recordCalls": True,
"maxCallSeconds": 300
},
"collectFields": [
{
"name": "budget",
"type": "number",
"description": "Budget in rupees"
},
{
"name": "interest",
"choices": ["Hot", "Warm", "Cold"]
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "ag_5c4a5f93-2b1e-4d7a-9f60-8e2d1c3b4a71",
"name": "Skyline Sales",
"instructions": "You call people who enquired about a flat at Sky Towers, Baner. Find out their budget, preferred size and when they can visit the site.",
"greeting": "Namaste, I'm calling from Skyline Homes about your enquiry for Sky Towers.",
"businessDescription": "Skyline Homes builds 2 and 3 BHK apartments in Pune.",
"model": "prana-voice",
"temperature": 0.3,
"maxReplyTokens": 300,
"language": "Hindi",
"secondLanguage": null,
"escalation": {
"onNoAnswer": false,
"onRequest": true
},
"captureLeads": true,
"scheduleCallbacks": false,
"steps": [],
"widget": {
"theme": "classic",
"accent": null,
"height": 806,
"welcomeScreen": true,
"welcomeCollectLeads": true
},
"voice": {
"answersCalls": true,
"surfaces": [
"web",
"whatsapp"
],
"voice": "priya",
"phoneNumber": null,
"language": null,
"summariseCalls": true,
"detectMachines": false,
"recordCalls": true,
"maxCallSeconds": 300,
"ringSeconds": 30,
"pastConversations": "quiet",
"unavailableMessage": null,
"unavailableMessageNote": null,
"callStartUrl": null,
"thinking": true,
"thinkingLines": [],
"thinkingDelayMs": 900,
"thinkingRepeatMs": 2500,
"thinkingAtTurnEnd": false,
"turnSilenceSeconds": null,
"turnDetection": null,
"reaskAfterSeconds": null,
"recordDoNotCall": true,
"interruptWords": 3,
"neverInterrupt": false,
"holdShortSpeech": true,
"greetingUninterruptible": false,
"ambience": null,
"ambienceVolume": 0.15,
"endCallOnFinish": false,
"nudgeAfterSeconds": null,
"nudges": 1,
"nudgePhrase": null,
"endAfterSilenceSeconds": null,
"endPhrases": [],
"callInstructions": null
},
"byok": "workspace",
"collectFields": [
{
"name": "budget",
"type": "number",
"description": "Budget in rupees",
"choices": null
},
{
"name": "interest",
"type": "text",
"description": null,
"choices": [
"Hot",
"Warm",
"Cold"
]
}
],
"webKey": "pk_9fQ2xLm7Rt4vWb8KcN3hYd6sJ1pZ",
"createdAt": "2026-10-06T08:12:44.118Z"
}Authorizations
Your API key (ta_live_…) from Settings → API keys, sent as Authorization: Bearer <key>. Keep it on a server: it can message every customer you have. A key is full, build or read-only; a request its level does not allow is refused with 403.
Headers
Developers only: the customer workspace this request acts in — its org_… id from POST /customers. Leave it out to act in your own workspace. Refused with 404 (Workspace not found.) when the id is unknown, is not one of your customers, or is not an org_… id; 410 when that customer was deleted (restore it with POST /customers/{id}/restore until it is erased); 403 when the key belongs to one customer workspace (it cannot act as another); 400 when your workspace is not a developer workspace. /customers/* and GET /customers/usage are your own workspace's and refuse the header with 400: call them without it.
"org_3fKq9TzQ1mN8vB2xR7cLpA"
Body
The agent's name, 2 to 60 characters, without hidden characters or markup.
2 - 60What the agent is and how it behaves. Left out, it gets the starter persona the console gives a blank agent. Re-sent on every reply, so every character costs on every turn.
20000The first thing it says on a call or in a chat.
200One line about what the business is. Facts belong in Knowledge.
200A model id from List Models, or null for the default (Prana [Voice]) — the same as leaving it out. An empty string is a 400. If given, it is the same list the console's one model picker offers, for chat and calls alike: it must be on your plan, quick enough to answer a call (voice: true), within the per-minute budget a call can carry, and not one of our voice-only models (they answer calls on their own and are never an agent's model). A chat-only agent is held to the same list, as in the console.
How adventurous the wording is. Clamped to 0–2.
0 <= x <= 2The longest a reply may be, in tokens, for chat and calls alike. Rounded and clamped to 100–800.
100 <= x <= 800The languages the agent speaks, by their English names: [] is auto (reply in the customer's language), one name is that language alone, and two to four make the agent expect those languages, the first being the one it falls back to when it cannot tell. On a phone call the recogniser works out the language among them. Send languages or language, not both: language sets one language and clears this list. A name the console does not offer, a repeat, or more than four is refused with a 400.
4auto to reply in the customer's language, or a language the console offers by its English name: English, Hindi, Assamese, Bengali, Bodo, Dogri, French, German, Gujarati, Indonesian, Italian, Japanese, Kannada, Kashmiri, Konkani, Korean, Maithili, Malayalam, Manipuri, Marathi, Nepali, Odia, Polish, Portuguese, Punjabi, Russian, Sanskrit, Santali, Sindhi, Spanish, Swahili, Tamil, Telugu, Thai, Turkish, Urdu or Vietnamese.
Retired. Accepted so an older integration keeps working, but ignored: the agent answers in language alone.
When the agent hands over to a person. Send either or both.
Show child attributes
Show child attributes
{ "onNoAnswer": false, "onRequest": true }
Take a name, email or phone number from an interested customer.
Allow it to book a call back when asked.
Open the website widget on a welcome screen.
Ask for the visitor's details on the welcome screen.
A conversation script, in order, replacing any there was. Blank steps are dropped.
12Show child attributes
Show child attributes
How this agent uses the workspace's own provider keys (Bring your own keys). null (or workspace) follows the workspace: its default scope applies when it brings its own keys. off never does: our voices and models at our normal pricing, whatever the workspace does, and the model is not held to the voice-only-BYOK model list. all, voice, llm or llm_voice runs this agent on that scope's keys whatever the workspace default is; refused with 409 naming the missing key unless the workspace holds verified keys for every kind that scope needs. If a key goes later, the agent falls back to the workspace's scope at the next call. Omit the field to leave it unchanged; saved BYOK model and voice choices are kept but not used while it is off. Read back as workspace when it follows the workspace.
workspace, off, all, voice, llm, llm_voice, null The website widget's look. Send any subset.
Show child attributes
Show child attributes
{
"theme": "modern",
"accent": "#0f766e",
"height": 720
}
How the agent handles calls. Send any subset. Where an agent has no voice channel yet, sending any of these creates one — switched OFF, so setting only a voice or a message never starts it taking calls; send answersCalls: true to switch it on.
Show child attributes
Show child attributes
{
"voice": "priya",
"summariseCalls": true,
"maxCallSeconds": 300,
"pastConversations": "quiet",
"thinkingLines": ["One moment, let me check."],
"interruptWords": 2,
"nudgeAfterSeconds": 10,
"nudges": 2,
"endPhrases": ["bye"]
}
The details to fill in from the transcript after every call; they arrive as fields in each call's results. A call that sends its own extract uses that instead.
30Show child attributes
Show child attributes
Response
The agent, as Get Agent returns it.
An agent as the console shows it.
The agent's id.
"ag_5c4a5f93-2b1e-4d7a-9f60-8e2d1c3b4a71"
The agent's name, 2 to 60 characters.
What the agent is and how it behaves — its standing prompt.
The first thing it says, or an empty string.
One line about the business, or an empty string.
A model id from List Models. null when the agent is on a model that has since been retired.
How adventurous the wording is.
0 <= x <= 2The longest a reply may be, in tokens — one ceiling for chat and calls.
100 <= x <= 800auto (reply in the customer's language) or the language it always replies in, e.g. Hindi. When the agent is set to speak several languages this is auto: read languages.
The languages the agent speaks, as the console shows them: [] is auto, one name is that language alone, and two to four are the languages it expects, the first being the one it falls back to.
Retired — always null. An agent answers in one language, language. Still returned so a client that reads it keeps working.
When the agent hands the conversation to a person on your team.
Show child attributes
Show child attributes
Whether it takes a name, email or phone number from an interested customer.
Whether it may book a call back when asked.
Its conversation script, in order.
Show child attributes
Show child attributes
The website chat widget's look.
Show child attributes
Show child attributes
How it handles calls. null when the agent has no voice channel (a deployment without voice).
Show child attributes
Show child attributes
How this agent uses the workspace's own provider keys (Bring your own keys). null (or workspace) follows the workspace: its default scope applies when it brings its own keys. off never does: our voices and models at our normal pricing, whatever the workspace does, and the model is not held to the voice-only-BYOK model list. all, voice, llm or llm_voice runs this agent on that scope's keys whatever the workspace default is; refused with 409 naming the missing key unless the workspace holds verified keys for every kind that scope needs. If a key goes later, the agent falls back to the workspace's scope at the next call. Omit the field to leave it unchanged; saved BYOK model and voice choices are kept but not used while it is off. Read back as workspace when it follows the workspace.
workspace, off, all, voice, llm, llm_voice The details it fills in after every call, in the shape a call's extract takes. Empty when it collects nothing.
Show child attributes
Show child attributes
The public key the website widget embeds (pk_…). It is published on your site, so it is not a secret.
When the agent was made.