Skip to content
megapromotingLet's talk
Products Kallina

AI voice agents Platform

A good conversation continues with an action.

We build agents that take and initiate calls, use business information and work with your systems. From the first question to a complete request, a confirmation or transfer to a colleague.

ListenCheckActsVOICE + CONTEXT + ACTION
How Kallina works

Kallina

From information to work done.

01

Listen

Understands the request in the context of the conversation and business rules.

02

Check

Checks the knowledge base and authorised integrations before responding.

03

Acts

Completes the data, performs the permitted action or transfers the conversation to a person.

Where it becomes useful.

Reception and support

Frequently asked questions, taking requests and getting back to people who asked to be contacted.

Orders and deliveries

Confirmations and coordination, with the information from the connected order system.

Qualification and scheduling

Collect the necessary details. Calendar access and booking are set for each integration.

Scenarios, phone number, languages and actions are configured for each implementation. The team retains the option to take over the conversation.

Kallina in detail

What you can do with this project.

Kallina is the platform on which we build agents that speak on the phone and in the web page. An agent has a written role, an approved knowledge base, a set of tools it can call, and a limit beyond which it hands the discussion over to a human. The conversation does not end in a transcript: the call has duration, cost per provider, recording and analysis, all linked to the business account.

The voice engine is not a single one. In the agent configuration you choose between ElevenLabs Conversational AI, OpenAI Realtime, Gemini Live or “auto”, in which case Kallina chooses the provider based on language, load and availability. On top of that you choose the text brain separately — the catalogue in code has 78 entries from OpenAI, Google, Anthropic, xAI and ElevenLabs, each with latency and cost per minute displayed in the interface, so the choice is informed, not based on hearsay.

The telephony is ours, not rented from the voice provider. Calls go through a proprietary Asterisk, with routing by working hours and time zone, overnight schedules (for example 22:00 → 06:00) and priority matching: the SIP Diversion header, then the Kallina number, then the fallback rule. For OpenAI Realtime there is an AudioSocket bridge that converts the codec both ways, g711_ulaw ↔ PCM16.

01

Three voice providers plus an “auto” position

In `AGENT_PROVIDERS` there are four options: `elevenlabs` (ConvAI), `openai-realtime`, `gemini-live` and `auto`. For text-to-speech in languages other than English, the default is `eleven_flash_v2_5` — 32 languages, approximately 75 ms latency; the higher-quality alternative, `eleven_turbo_v2_5`, costs approximately 250 ms. The choice is not hidden in code, it is a field in the agent configuration.

02

Model catalogue with displayed latency and cost

78 models in `LLM_MODELS`, grouped by provider in the interface together with the measured latency and cost per minute — from `gpt-5-nano` at approximately 806 ms and around $0.0004/min, up to `claude-sonnet-4-6` at approximately 1.55 s and around $0.0225/min. A client asking “why is it responding slowly” gets an answer with figures, not an opinion.

03

Proprietary telephony on Asterisk

Call forwarding is configured by working hours and time zone, with support for overnight schedules and priority matching (SIP Diversion header → Kallina number → fallback rule). The `openai-realtime-bridge` bridge converts AudioSocket between g711_ulaw and PCM16 for the bidirectional audio flow.

04

Voice embed in a single line, without agent id on the page

`<script src="https://app.kallina.info/embed.js" data-widget="WIDGET_ID"></script>`. The page never finds out which agent responds and does not keep any provider key: it requests a session from Kallina, and Kallina returns a short-lived signed URL. There is also `data-mode="inline"` mode, in which the embed draws absolutely nothing and the page builds its own interface over the `start()` / `stop()` / `toggle()` / `on(event, fn)` API.

05

Outbound calling campaigns

Batch calling with 1–10 simultaneous calls, contact import from CSV, retry logic, real-time monitoring with pause, resume and stop, plus SMS follow-up.

06

Languages

The agent configuration supports 32 languages (`LANGUAGES`), the full platform language map has 41 entries, and the admin panel is translated into 20 (`src/i18n/locales`). Romanian is the default language in `DEFAULT_VALUES`.

Data and operation

What enters the system. What needs to be checked.

Where the data lives
PostgreSQL via Supabase, with Row Level Security and pg_cron; 559 versioned migrations. The server logic consists of Deno edge functions — 472 in the repo at the time of checking.
What never reaches the client page
The voice provider key and the agent identifier. The embed requests `POST /functions/v1/widget-voice-session` with `widget_id` — the public key from `chat_widget_configs.widget_id`, not the row’s internal id — and the server requests a signed URL itself from ElevenLabs, via `convai/conversation/get_signed_url`, and returns it. The old version, which put `agentId` directly in the HTML, bypassed Kallina completely.
Knowledge base
Documents uploaded into the platform, synchronised with ElevenLabs RAG. Above them, conversation guardrails, data collection schemes and call success evaluation criteria are defined per agent.
Measured consumption before, not after
The `usage_events` table keeps consumption broken down by provider and by agent. Before any action that costs, the `check-can-use` function checks the credit — the gate is before the call, not the invoice at the end of the month.

From exploration to implementation

How we prepare a project with Kallina.

01

We choose a single route and write its boundaries

A scenario with a clear input and a clear output — a call received at reception, an order confirmation, a calling campaign. We state explicitly what the agent is not allowed to do and by which route it hands the conversation over to a human.

02

We connect the number and verify it in both directions

The number goes on our Asterisk SIP trunk. Incoming and outgoing calls are tested separately, because they can break separately: an operator restriction on outgoing calls leaves incoming calls working perfectly.

03

We check the route without spending minutes

`scripts/verify-voice-path.mjs` follows the exact path of a browser — the row in the configuration, `get-widget-config`, then `widget-voice-session` — and stops at the signed URL, without opening the websocket. It runs on a single widget or on all those with voice enabled, with 1–3 in parallel, and returns an exit code, so it can go straight into a cron.

Questions worth clarifying.

Which voice engine does it use, concretely?

You choose between ElevenLabs Conversational AI, OpenAI Realtime and Gemini Live, or leave it on “auto” and Kallina decides based on language and availability. For voice synthesis in languages other than English, the default is the `eleven_flash_v2_5` model — 32 languages, around 75 ms; if you want higher quality and accept more latency, `eleven_turbo_v2_5` is around 250 ms. There are ten OpenAI Realtime voices, and their engine goes up to `gpt-realtime-2.1`.

How is it installed on a website?

One line: `<script src="https://app.kallina.info/embed.js" data-widget="WIDGET_ID"></script>`, loaded as a normal script, not as a module. The file is served today and is 13,762 bytes. If you want your own interface, `data-mode="inline"` draws nothing and leaves you `start()`, `stop()`, `toggle()` and the `state`, `message`, `error` events. Note the host: the file is on `app.kallina.info`, not on `kallina.info` — these are two applications on two different servers.

Does it consume minutes if the visitor refuses the microphone?

No. The sequence in `embed.js` is: load the SDK, request the microphone with `getUserMedia({audio:true})`, and only then call `widget-voice-session`. If the person refuses the microphone, the session request is not made at all, so no signed URL is issued and nothing is consumed.

Can it call first, not just answer?

Yes — batch calling, 1–10 at once, contacts from CSV, retries and follow-up by SMS. But outgoing calls depend on the telephone operator, not just on us: our issue log documents a case where the operator’s switch started returning `403 Forbidden` for all outbound calls, with our configuration unchanged and incoming calls working normally. That is why we test outbound calls separately before promising a campaign.

In how many languages does it speak and in how many is it administered?

The agent configuration accepts 32 languages, the internal language map has 41 entries, and the administration panel is translated into 20. Romanian is the default language for new agents.

Is it published automatically with every code change?

No, and it is good to know before planning a launch. The GitHub workflow in the repo targets a Supabase Cloud project that has been deleted, so “push to main = publish” is no longer true since the migration to own infrastructure. Real publishing is done via SSH, with copying and restart. The practical consequence: an urgent change needs a person, not just a commit.

What happens if the agent does not know the answer?

Hand-off to a human is part of the scenario, not an exception. Each agent has written limits and a transfer path configured on telephony; and in the conversation there are guards and success evaluation criteria, precisely so that a case outside the role is stopped, not improvised.

Illustrative example

An incoming call at night, reaching the right place

A use case, without client data or attributed commercial results.

Initial situation

Someone calls the business number at 23:40, outside reception hours.

How it works

Asterisk applies the overnight schedule rule (for example 22:00 → 06:00) and matches by priority: the SIP Diversion header, then the Kallina number, then the fallback rule. The night agent answers on the provider chosen in the configuration, clarifies the request and calls the tools it is allowed to use.

Rezultatul

The call remains in the history with transcript, audio recording, duration and cost broken down by provider. Anything that goes beyond the agent’s role stops and is transferred onwards, instead of being improvised.

What is required:The number connected to our Asterisk SIP trunk, outbound calls permitted by the operator if desired and call-back, plus an agent with a prompt, approved knowledge base and written limits.

Collaboration possibilities

Kallina, in the context of your organisation.

Information and request handling

Voice assistance on approved information, with handover to an operator and clear rules on recording and retaining conversations.

Private companies

We define a pilot around a real process: users, data, integrations, costs and acceptance criteria. Expansion follows after evaluating the result.

State institutions and companies

We establish the requirements for accessibility, hosting, data protection and interoperability. Any connection to AGE or STISC services requires validation of eligibility, access and approvals.

These are adaptation scenarios, not statements about existing contracts or partnerships. The proposed functions are confirmed within the project scope.

Discuss a pilot

Part of an ecosystem.

What would you want to work better?

Tell us about your process. Together we decide what is worth building, what we can connect, and how we check the result.

Let's talk