Skip to main content
Custom functions extend the agent beyond built-in actions like SMS and transfer. You define a function in the dashboard (name, description, your URL, what parameters the agent can pass), and the agent can call it during the conversation — to look up customer records, check inventory, book appointments, anything your API can do.

How it works

1

Create the function in the dashboard

Open the Integrations tab, choose the phone number, open Custom Functions, and add a function. Custom functions are configured per phone number. You give it a name, a description (the agent reads this every turn), an HTTPS URL, and a parameter schema.
2

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.
3

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.
4

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.
5

The agent responds to the caller

The agent uses the data you returned to compose the next reply, spoken naturally to the caller via TTS.

What your endpoint receives

Every request from the engine looks like this:
Three top-level fields: The only header you receive is User-Agent: Nixflex-VoiceEngine/1.0. There is no signature header yet (see Authentication below).

The 14 dynamic variables

These are always present in variables on every request. They cover everything the engine knows about the call.
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 a result field:
The engine extracts result and feeds just that to the agent. Cleaner context, faster agent responses. Also accepted — return the data at the top level:
If there’s no result field, the engine stringifies the whole body and feeds it to the agent.

Status codes

Errors never crash the call — the agent always handles them gracefully.

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:
The agent has no idea when this applies. The function effectively doesn’t exist. Good:
The agent now knows exactly when to fire. Will trigger reliably whenever the conversation matches.
Write the description as instructions to the agent, not as a label for humans. Always include the words “Use when…” followed by the conversational cues that should trigger it.

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

Becomes:

Header substitution

Headers also support substitution, useful for passing call context through to upstream services that expect it in headers.

When to use which

Most modern APIs use the third pattern, so most developers leave the URL static and just read variables from the body. URL substitution is for REST-style and GET endpoints.
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 with User-Agent: Nixflex-VoiceEngine/1.0 but does not yet sign requests. For now, the recommended pattern is a bearer token in the Headers field:
Add it once in the Headers field on the function, and the engine sends it on every request. Verify it on your side before processing.
Use a long random shared secret (32+ characters). Treat it like a password — anyone with it can call your function URL pretending to be Nixflex.
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:
This gives the agent an extra hint about ordering and conditions on top of each function’s description.

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:].

Speak while running

Some functions call a slow API, or the agent may call one without saying anything first. To avoid the caller hearing silence during the wait, set a Speak while running line (speak_during) on the function - a short phrase the engine speaks as the function runs.
If you leave it empty the agent will usually say something natural on its own, but a set phrase guarantees the caller is never left in silence - especially important on functions with a long timeout.

Limits and constraints

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
Use it to confirm your endpoint is reachable, returns the right shape, and responds within the timeout. The actual production call will use real caller numbers and real call_id.
The test panel is reachability-focused. To test a complete real-world flow with a real caller number, just make a real call to your agent.
For more standardised integrations (Stripe, Salesforce, Google Calendar etc.), MCP server support is on the roadmap.