Browse all articles
Build an agent with the API
Technical reference for building Kollie agents programmatically: endpoints, config keys, skill types, build order and security.
Last updated:
On this page
Technical reference for building agents programmatically. What to write in the fields is not covered here, and the rules are identical whichever way the agent is built. See How to build your AI phone agent.
Base URL: https://api.kollie.ai. The Swagger UI is at the same address.
Authentication
Generate your own API key on the platform under API Keys in the left-hand menu. That key authenticates every request. There is no token issuance step and nothing else to obtain.
Building an agent: two stages
Stage 1: create the agent
POST /api/v1/agents
{
"name": "SALES-EN-DEMOBOOKING",
"organization_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"config": { }
}
Returns the created agent including its id, which you need for stage 2.
Everything about the agent lives in config.
The three text fields:
config key | Interface field |
|---|---|
initial_message | Introduction |
business_info | Business Information |
main_objective | Main Objective |
These three carry all the prose, and all of it is governed by How to build your AI phone agent. Nothing relaxes because the configuration arrived as JSON rather than through a form.
Everything else in config is a setting. Set these; never describe them in the text fields.
config key | Controls |
|---|---|
language | Voice and language identifier. One per agent. |
temperature | Creativity: how strictly the prompt is followed. |
model | Model selection. |
recording | Call recording. |
notifications | Email / SMS / WhatsApp delivery. Object with email, sms, whatsapp, each {enabled, from, to}. |
hangup_on_voicemail | Voicemail detection. |
allow_agent_to_be_cut_off | Barge-in: whether the caller can interrupt. |
adaptive_interruption, transcriber | Interruption detection and handling. |
stt_keyterms | Industry Terms. Array of words given to the speech recogniser as a reference for anything that sounds ambiguous. |
from_phone, vonage_app_id | Telephony. Set by the phone-linking step, not here. |
version | Config schema version. |
example_dialog | Legacy, no longer used. Leave empty. |
Stage 2: attach each skill
POST /api/v1/agents/{agent_id}/skills, once per skill. The same endpoint updates an existing skill's config.
{
"type": "call_transfer",
"enabled": true,
"config": {
"toPhone": "+3120XXXXX01",
"description": "Sales team, showroom floor. Use this number when the caller is asking about getting a vehicle: availability, delivery times, a price or lease quote, trade-in value, financing, or booking a test drive."
}
}
A skill that exists but is not enabled does nothing.
Skill types
Verified against a live agent carrying all of them.
type | exec_order | Interface name | config |
|---|---|---|---|
api | pre_call | Call API — Before Call | url, method, qs |
api | post_call | Call API — After Call | url, method, qs |
external_action | during_call | External Action / Call API — During Call | name, description, url, method, params[], header, results[] |
call_transfer | — | Call Transfer | toPhone, description |
scheduling | — | Book Meeting | integration_id |
round_robin | — | Round Robin | data.integrations[] |
extract_information | — | Extract Information | data[] of {type, name, description} |
hubspot | post_call | HubSpot Sync | data.integrations[], each {integration_id, contact_custom_fields, calls_custom_fields} |
hubspot_contact_lookup | pre_call | Get Contact by Phone Number | integration_id |
Four things this table settles:
- Call API Pre and Post are one type,
api, distinguished only byexec_order. Not two skills. external_actionis the During Call mode and a genuinely separate type, with the extra fields that mode needs: an actionnamethe agent invokes, adescriptionit reads to decide when,params[]for the request andresults[]for the response.- Get Contact by Attribute has no type of its own. It is an
external_actionpointing at the contacts search endpoint. Only the silent phone-number lookup has a dedicated type. exec_orderonly means something forapiandexternal_action, where it decides when the request fires. On the other types it is stored but carries no timing meaning: read nothing into acall_transfershowingpost_call.
Which types have a description the agent reads: call_transfer, external_action, and each field inside extract_information. Those are the ones the writing rules apply to. The rest are endpoints and integration ids with nothing for the agent to interpret.
Industry Terms is not a skill. It is stt_keyterms in agent config.
Other endpoints
| Method | Path | Use |
|---|---|---|
GET | /api/v1/agents | List agents. |
GET | /api/v1/agents/{agent_id} | Read one back, with its skills. The quickest way to see a working agent's real shape. |
PUT | /api/v1/agents/{agent_id} | Update an agent. |
DELETE | /api/v1/agents/{agent_id} | Delete an agent. |
DELETE | /api/v1/agents/{agent_id}/skills/{skill_id} | Remove a skill (soft delete). |
POST | /api/v1/agents/{agent_id}/call | Trigger an outbound call. Where trigger-time parameters for {{ placeholders }} are passed. |
POST | /api/v1/agents/{agent_id}/webcall | Trigger a web call. |
POST | /api/v1/agents/{agent_id}/campaign | Create an outbound campaign. |
GET | /api/v1/agents/{agent_id}/calls | Call history for the agent. |
Build order
POST /api/v1/agentswithname,organization_idand a completeconfig.- Take
idfrom the response. POST /api/v1/agents/{id}/skillsonce per skill, each withenabled: true.GET /api/v1/agents/{id}and check what came back matches what you sent.- Place a test call.
Driving this from a script or an LLM? The content rules in How to build your AI phone agent apply unchanged, and the automated pre-save check is written to be run as a validation step before step 1.
Security
Your API key is a secret. Keep it in an environment variable or a secrets manager: never in source control, never pasted into a ticket, never in a shared document. If a key has been shown to a model in conversation, treat it as exposed and rotate it. That matters here specifically: if an LLM is driving your script, it should drive the script, not hold the key.
Never put credentials in business_info, main_objective, or a skill description. Those are prompt content. Everything in them is read by the agent on every call, and anything the agent has read, it can be talked into saying.
Credentials a skill legitimately needs go in that skill's own config: on an external_action, the header object with its name and value. That is the correct place, and the only correct place.
But know what that means: skill credentials are readable. GET /api/v1/agents/{agent_id} returns each skill's config in full, header values in plaintext included. Anyone who can read an agent through the API or export its JSON can read the keys inside it. So:
- Give each skill the narrowest key that works, never a shared or admin-scoped one.
- Treat any exported agent JSON as a secret.
- Strip header values before pasting a configuration into a ticket, a chat, a document, or a model.
Watch results[] on external_action. Leave it empty and the agent receives the entire API response: every field the endpoint returns, including internal ids and debug output. Filtering is opt-in. Map the fields you actually need and keep the list narrow: it costs one line of config and keeps attacker-controlled free text in unrelated fields from reaching the agent as content.
{{ placeholder }} tokens are not credentials. They are fill-in-the-blank markers for reusing a saved template with another customer. Never substitute a real key for one.
Related articles
- How to build your AI phone agentHow to build an AI phone agent in the Kollie web app: what to write in each field, where to write it, and what to leave out.
- Set up an outbound calling campaignLet your AI agent call leads, prospects or customers: create a campaign, upload leads, run it and review the results.
- View your call reports and dashboardsTrack agent activity, campaign effectiveness and usage in the Analytics tab, and export transcripts and summaries.
Still need help?
Can't find the answer you're looking for? Send us a ticket and our support team will help you set up and improve your agents.
Submit a support ticket