How it works
Create the function in the dashboard
Open your agent, expand the Custom Functions panel, and add a function. You give it a name, a description (the agent reads this every turn), an HTTPS URL, and a parameter schema.
The agent sees it as a tool
On every conversation turn, the agent is aware of every active function on the agent. Based on the description you wrote, the agent decides when to call it.
Engine calls your URL
When the agent triggers a function, the engine makes an HTTP request to your URL with a JSON body containing the call context, what the agent extracted, and 14 dynamic variables.
Your endpoint replies with JSON
You return a JSON response. The engine reads the
result field (if present) and feeds it back to the agent as the tool result.What your endpoint receives
Every request from the engine looks like this:| Field | What it is |
|---|---|
name | The name of the function being called. |
args | What the agent extracted from the conversation, matching your parameter schema. |
variables | All 14 dynamic variables. Sent on every request automatically — you do not need to ask for them. |
User-Agent: Nixflex-VoiceEngine/1.0. There is no signature header yet (see Authentication below).
The 14 dynamic variables
These are always present invariables on every request. They cover everything the engine knows about the call.
| Variable | Description | Example |
|---|---|---|
caller_phone | Caller phone in E.164 format | +447386172392 |
business_phone | The number the caller dialed | +447446466847 |
current_date | Today, human-readable (agent timezone) | Wednesday, May 27, 2026 |
current_iso_date | Today, ISO format | 2026-05-27 |
current_time | Now, 24h HH:MM | 14:32 |
current_iso_time | Now, ISO time format | 14:32:18 |
tomorrow_date | Tomorrow, human-readable | Thursday, May 28, 2026 |
tomorrow_iso_date | Tomorrow, ISO format | 2026-05-28 |
current_day_of_week | Day name | Wednesday |
current_timezone | Agent timezone setting | Europe/London |
call_direction | inbound or outbound | inbound |
call_id | The Twilio call SID | CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
agent_id | The agent’s ID | agent_f2b06c0e0bd877e9 |
caller_history | Summaries of past calls from this number (empty for first-time callers) | PREVIOUS CALLS FROM THIS NUMBER... |
There is no
caller_name variable. Speech-to-text often mishears names. If a name matters to your flow, instruct the agent in its system prompt to ask the caller to spell it and confirm it back before calling the function.What to send back
Your endpoint should respond with JSON. Two valid shapes: Recommended — wrap the data in aresult field:
result and feeds just that to the agent. Cleaner context, faster agent responses.
Also accepted — return the data at the top level:
result field, the engine stringifies the whole body and feeds it to the agent.
Status codes
| Code | Behaviour |
|---|---|
200 | Success. Body is parsed and passed to the agent. |
4xx / 5xx | Treated as a function error. The agent is told the function failed and can apologise or transfer naturally. |
| No response within timeout | Treated as a function error. Default timeout is 5 seconds. |
Writing a good description
This is the most important field on the whole function. The agent reads your description on every conversation turn to decide whether to call the function. A vague description means the agent either never fires it, or fires it at the wrong time. Bad:URL and header variable substitution
Even though all 14 variables are sent in the request body automatically, sometimes you need them in the URL itself (REST APIs) or in a header (authentication). Use{{variable_name}} syntax in the URL or Headers fields.
URL substitution
Header substitution
Headers also support substitution, useful for passing call context through to upstream services that expect it in headers.When to use which
| Your API style | Where data goes | Use |
|---|---|---|
REST resource (GET /customers/{id}) | URL path | {{variable}} in URL |
REST query (GET /search?phone=x) | URL query string | {{variable}} in URL |
| JSON POST endpoint | Request body | Read from req.body.variables |
Substitution only works in URL and Headers. It does not substitute in the description, name, or parameter schema fields.
Authentication
Custom function endpoints are public by default — the engine identifies itself withUser-Agent: Nixflex-VoiceEngine/1.0 but does not yet sign requests.
For now, the recommended pattern is a bearer token in the Headers field:
Request signing (HMAC with rotating secrets) is on the roadmap. When it lands, the engine will send an
X-Nixflex-Signature header you can verify with a per-agent secret. Until then, use bearer tokens in Headers.Mentioning functions in the prompt
You can let the agent discover when to use functions purely from the descriptions, but adding an Actions section to the system prompt makes triggering more reliable:Common use cases
Calendar lookups
Check availability before promising a slot.
CRM record fetches
Pull customer history when they call.
Booking creation
Create the booking in your system once confirmed.
Inventory checks
Verify a product is in stock before quoting.
Order status
“Where’s my order?” — look it up and reply naturally.
Payment links
Generate a Stripe checkout URL and text it via
[SEND_SMS:].Limits and constraints
| Limit | Value | Why |
|---|---|---|
| Functions per agent | 10 | Keeps the agent’s tool list focused. Too many functions and the agent gets confused about which to call. |
| URL scheme | HTTPS only | Plain HTTP is rejected for security. |
| Default timeout | 5 seconds | After this, the function is treated as failed. Override per-function if your API is slow. |
| Response size | 100 KB max | Larger responses are rejected. Big payloads also bloat the agent’s context. |
| Tool rounds per turn | 3 | Stops the agent from looping on the same function indefinitely. |
| Function name format | snake_case, max 64 chars | Matches the agent’s tool name requirements. |
Limitations
- Functions are triggered by the agent during conversation — you cannot trigger them externally.
- The engine does not retry failed functions automatically. Make your endpoint idempotent if the agent might call it twice.
- Function calls happen per conversation turn. There is no streaming partial results back to the agent.
- The tool-aware path is slightly slower than the no-functions path because it waits for the full agent response (including tool calls) before speaking.
Testing your function
The dashboard has a Test Webhook button on every function. It sends a request to your URL with:- Fake
caller_phone(+44XXXXXXXXXX) - Fake
business_phone(+44XXXXXXXXXX) - Fake
call_id(test_<timestamp>) - Real date/time variables (from your agent’s timezone setting)
- Args you type into the Sample Args field
call_id.
For more standardised integrations (Stripe, Salesforce, Google Calendar etc.), MCP server support is on the roadmap.