Create agent
curl --request POST \
--url https://api.nixflex.com/v1/agentsimport requests
url = "https://api.nixflex.com/v1/agents"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.nixflex.com/v1/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.nixflex.com/v1/agents",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.nixflex.com/v1/agents"
req, _ := http.NewRequest("POST", url, nil)
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.nixflex.com/v1/agents")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nixflex.com/v1/agents")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyAgents
Create agent
POST /v1/agents
POST
/
v1
/
agents
Create agent
curl --request POST \
--url https://api.nixflex.com/v1/agentsimport requests
url = "https://api.nixflex.com/v1/agents"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.nixflex.com/v1/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.nixflex.com/v1/agents",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.nixflex.com/v1/agents"
req, _ := http.NewRequest("POST", url, nil)
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.nixflex.com/v1/agents")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nixflex.com/v1/agents")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyCreates a new AI agent. The agent immediately becomes available to attach to phone numbers and use for outbound calls.
Save the
The response never includes
Request
curl -X POST https://api.nixflex.com/v1/agents \
-H "Authorization: Bearer KEY_ID:KEY_SECRET" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Dental Receptionist",
"system_prompt": "You are the friendly front-desk assistant at Acme Dental in Croydon...",
"welcome_message": "Hello, Acme Dental, how can I help?",
"voice_id": "Ashley",
"language": "multi",
"transfer_number": "+442087601234",
"webhook_url": "https://api.acmedental.com/nixflex/calls"
}'
Body parameters
Onlyname is recommended in practice — every other field has a sensible default. You can create a working agent with a one-line payload.
Core
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
name | string | No | "Untitled Agent" | Display name (max 100 chars) |
system_prompt | string | No | friendly assistant | The AI’s instructions (max 16000 chars, about 4000 tokens) |
welcome_message | string | No | "Hello! How can I help you today?" | First line spoken on inbound calls |
voice_id | string | No | "Ashley" | Voice name. Browse voices in the dashboard |
language | string | No | "multi" | Default language. multi follows the caller across English, Spanish, French, German, Italian, Portuguese, Dutch, Hindi, Russian and Japanese. Arabic, Hebrew, Korean, Chinese and Polish need their own code. See Languages |
is_active | bool | No | true | Set false to disable without deleting |
Behaviour
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
temperature | number | No | 0.3 | AI temperature, 0-1 |
response_length | enum | No | "short" | short, medium, long |
ai_speaks_first | bool | No | true | Agent greets caller immediately |
dynamic_greeting | bool | No | false | AI improvises greeting per call instead of static welcome |
interruption_sensitivity | int | No | 50 | 0-100. Lower = harder to interrupt |
response_eagerness | int | No | 200 | How long the agent waits after the caller stops speaking, in milliseconds. Range 0-1000. Lower is snappier; 0 replies the moment the words are final. Shown as Response Delay in the dashboard |
boosted_keywords | string | No | null | Comma-separated words your callers say that speech recognition might mishear - staff names, treatments, products, place names. Up to 50. Example: Dr Patel, hygienist, root canal, Meadow Lane |
pickup_delay | int | No | 10 | Seconds the agent waits after pickup before speaking. Range 5–30. |
Call controls
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
max_call_duration_seconds | int | No | 600 | Hard cap on call length. Range 60–1800 (1–30 min). See End call. |
silence_hangup_seconds | int | No | 30 | Hang up if caller silent this long. Range 5–45. See End call. |
record_call | bool | No | true | Save call audio to Supabase Storage. Recordings are deleted after 90 days, and a number can override this. See Call recording. |
recording_source | string | No | "provider" | Who records when record_call is on. "provider" = your carrier records (whole call, carrier recording charges apply). "nixflex" = the voice engine records the conversation itself at no extra cost (a transfer to a person is not included). Anything else is rejected with invalid_recording_source. See Call recording. |
amd_enabled | bool | No | false | Ask the carrier to detect an answering machine and hang up about 4 seconds in. Costs extra per answered call on your own carrier bill. With it OFF the agent detects voicemail from the first thing it hears and can leave a message, so ON means a fast hangup and NO message. See Voicemail detection. |
dtmf_enabled | bool or null | No | null | Let callers type digits on their phone keypad instead of saying them. null means not set, and a number can override it. See Keypad input. |
require_booking_confirmation | bool | No | false | The engine reads the appointment back and waits for a clear yes before any calendar create, reschedule or cancel. Numbers can override it. See Booking confirmation. |
webhook_url | string | No | null | Where to POST post-call data |
Functions (tools the agent can call mid-conversation)
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
func_end_call | bool | No | true | Agent can end the call cleanly |
transfer_whisper | string | No | null | Warm transfer briefing text. If empty, the AI auto-generates from the conversation. |
func_send_sms | bool | No | false | Not enforced. Accepted and returned, but the engine does not read it. Use incall_sms_enabled to control texting during a call. |
incall_sms_enabled | bool | No | false | Lets the agent text the caller during a call, and sends booking confirmations by text. With it off, no text is sent and the agent confirms details out loud. Agents created before this setting existed were switched on. See In-call SMS. |
func_cold_transfer | bool | No | false | Not enforced. Same as above - accepted, returned, and not read. Transfer is controlled by your prompt and by transfer_number. |
transfer_type | enum | No | "cold" | cold or warm. Applies to inbound, outbound, and batch calls made by this agent. See Transfer. |
transfer_number | string | No | null | Default destination for transfers |
How to stop the agent texting or transferring. Texting is controlled by
incall_sms_enabled: with it off no text is sent, whatever the prompt says. Transfers
are controlled by your prompt - the engine tells the model to transfer only if the
developer prompt asks it to, so a prompt that never mentions transferring produces an
agent that never transfers. func_send_sms and func_cold_transfer are kept because
removing a field developers may already send would break them silently, but they have
no effect.A prompt instruction is reliable but not absolute - a language model can still
ignore one. If you need a hard guarantee that a number never texts or never
transfers, do not rely on the prompt alone. Get in touch: a per-number switch is on
the roadmap and is worth building against a real requirement rather than a guess.
Other
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
voice_speed | number | No | 0.85 | Ignored. Accepted and returned for backwards compatibility, but nothing in the engine reads it. Use speaking_rate below. |
speaking_rate | number or null | No | null | How fast the agent talks. 1 is normal, 0.5 is half speed, 1.5 is half again as fast. A value outside that range is clamped to the nearest limit rather than rejected. null means normal speed, which is not the same as sending 1. A number can override this. See Voices. |
greet_by_name | bool | No | true | When a returning caller is recognised, greet them by the name on file (for example, Hi John). Set false for a neutral greeting. |
fallback_message | string | No | ”I am sorry, could you say that again?” | Said when transcription fails |
phone_number | string | No | null | Legacy. Numbers are now managed via /phone-numbers |
Response
201 Created:
{
"id": "1083c0db-699e-49ee-aa6c-aab29e2d87cf",
"agent_id": "agent_125207e452f8714a",
"api_key_id": "nxf_a1b2c3d4...",
"name": "Acme Dental Receptionist",
"system_prompt": "You are the friendly front-desk assistant...",
"welcome_message": "Hello! How can I help you today?",
"voice_id": "Ashley",
"language": "multi",
"temperature": 0.3,
"response_length": "short",
"ai_speaks_first": true,
"dynamic_greeting": false,
"interruption_sensitivity": 50,
"pickup_delay": 10,
"max_call_duration_seconds": 300,
"silence_hangup_seconds": 10,
"record_call": true,
"recording_source": "provider",
"func_end_call": true,
"transfer_whisper": null,
"func_send_sms": false,
"incall_sms_enabled": false,
"transfer_type": "cold",
"transfer_number": null,
"webhook_url": null,
"phone_number": null,
"voice_speed": 0.85,
"speaking_rate": null,
"dtmf_enabled": null,
"require_booking_confirmation": false,
"amd_enabled": false,
"greet_by_name": true,
"transfer_whisper": null,
"fallback_message": "I am sorry, could you say that again?",
"is_active": true,
"created_at": "2026-05-24T01:48:10Z",
"updated_at": "2026-05-24T01:48:10Z"
}
agent_id — you’ll use it for every subsequent operation.
Next step
Attach a phone number, on Twilio or Telnyx, so the agent can make and receive calls. See Import phone number.Errors
| Code | Cause |
|---|---|
prompt_too_long | system_prompt exceeds 16000 characters |
invalid_voice_id | Voice not in supported list |
invalid_language | Language code not supported |
invalid_request | Missing required field or bad format |
deprecated_field | twilio_account_sid or twilio_auth_token was sent. Agents do not hold carrier credentials - import the number with POST /v1/phone-numbers instead. |
twilio_auth_token.
See Errors for handling patterns.