Why these technologies
The team selected each product on this page to prevent one specific failure. This page names each product, its function, and the failure that occurs without it. Where the team recorded a decision, this page also names the alternative and the reason for the rejection. All of the content comes from the platform's written decision records. The team checked the records against the built system.
How to read this page
The sections below are in six groups. The groups are: the voice on the line, the engine room, the record keepers, where people meet the platform, the safety instruments, and the workshop. Each section answers the same four questions:
- What is the function of the tool?
- Why is a tool necessary for that function?
- What failure occurs without the tool?
- If the team recorded a decision, which alternative did the team reject?
Each section is complete on its own. If a link on another page points to one product here, you can read only that section and then go back.
This page does not follow one site rule. Only this page uses product names in the main text. All other pages use role names, for example "the voice", "the record", and "the long memory". On those pages, product names appear only in a small callout with the title "The technical bit, translated". This full page is that callout in a long form.
The voice on the line
Retell — the voice on the line
Retell (retellai.com) operates every live conversation. It listens, it speaks, it takes its turn, and it manages interruptions from the person on the line. In the middle of a sentence, the agent can request an action from the platform. The actions include: book a callback, send a link, and record a request to stop calls. The platform does the action, and the conversation continues without a pause.
- Why the platform buys this and does not build it: real-time voice AI is one of the most difficult engineering problems. The work includes speech recognition, speech generation, and turn management at a speed that seems human. A specialist provider completes the full loop in much less than one second. An in-house build is a full product on its own.
- The failure without it: the platform has no voice on the line.
- The recorded decision: the decision was about the method of use, not about the use itself. The rejected alternative was manual edits of the conversation designs in Retell's own dashboard. A person cannot track, review, or repeat a dashboard edit. The team cannot trust an unreviewed change on a regulated phone call.
The platform keeps the conversation designs in its own system with version control. A reviewer examines each change. Tests run each draft change against simulated conversations. If a test fails, the platform blocks the publication. To reverse a change, the team restores the previous version. Humans continue to examine staging calls and live calls, because a simulation cannot fully test real accents, background noise, or transfer audio.
One honest note: the plans specified one agent for each client. The built system gives each client a default agent. A campaign can also select one or more of its own agent variants, splitting its leads evenly across them. Teams use the variants to compare sales approaches at the same time, on equal terms. If a campaign selects no variant, the platform uses the client's default agent. The platform's own list of agent builds follows Retell's account automatically, once an hour, so a newly built agent is available to select without anyone pressing a button.
Telnyx — the phone company
Telnyx (telnyx.com) supplies each client's own phone numbers and the verified caller identity for those numbers. The carrier signs each call to show that the call comes from its correct owner. The signature follows the telephone industry's caller-authentication standard, with the name STIR/SHAKEN, at its highest grade.
- Why that matters: reputation. Calls without a signature, or with a weak signature, frequently show as "Spam likely" on the recipient's screen. People do not answer those calls. A calling platform without a verified identity gets no answers.
- The failure without a carrier: the platform cannot make calls.
- The rejected alternative: one shared pool of numbers and caller identity for all clients. The team rejected it because isolation at the carrier level is a hard requirement. Client A must never place a call with client B's number or identity. Each client must own its number reputation alone. One client's aggressive campaign must not reduce another client's answer rates.
The clients share the software and the record. Each client's numbers and caller identity stay fully separate; no two clients can ever hold the same number. In the rejected pooled design, one client's bad behaviour damages the reputation of all clients. The account key the platform uses to reach the phone company is shared, but by deployment — the platform's test system and the platform's live system each hold their own key, application, and numbers, so a leaked test key cannot reach a live call and a mistake made while testing cannot pool a real client's number. A dedicated key for one client is possible; none has asked for one.
Telnyx also supplies the platform's one source for a number's spam label and reputation score. An earlier plan named three separate scoring companies as direct relationships; the platform now reads all of that through Telnyx instead, because Telnyx already sits between the platform and those same scoring companies for call delivery, and a second, parallel set of vendor relationships would report on the same numbers without adding an independent check.
The engine room
NestJS — the decision desk's framework
NestJS (nestjs.com) is the framework for the backend. The backend answers questions while a caller speaks. The questions are: which mid-call tools can the agent use, which client owns this call, and which data must the platform record? The backend also receives the event reports from the voice provider and from the carrier. It also serves the control-room screens for your team.
- Why a framework is necessary: a backend with many responsibilities must have an enforced structure. The structure gives one consistent method to identify the requester, to validate the received data, and to keep each module separate. Without the structure, the code becomes disordered, and a programmer can skip a safety check by accident. NestJS supplies that structure, and it processes each request quickly and predictably.
- The failure without it, or without a similar framework: two problems occur. Mid-call answers arrive late, and the agent makes an audible pause on the phone. Also, the safety checks then depend on each programmer's memory.
- The alternative: the team recorded no direct alternative for this choice. The plans selected NestJS because of that exact combination: low delay and dependable structure.
Temporal — the long memory
Temporal (temporal.io) operates every long task on the platform. It writes each step of each task to a journal. Thus, after a crash or a restart, each task continues from its exact last step. The tasks include:
- A lead's calling journey, which continues for weeks, stays inactive most of the time, and becomes active on timers.
- Call attempts, which wait for retry timers and for reports that arrive some minutes later.
- Full campaigns, which the platform paces through the day.
The reasons for it:
- Why a tool is necessary: a standard program loses all of its state when it stops. The platform's core tasks must continue for weeks, longer than any single server.
- The failure without a long memory: one server restart erases every journey in progress. This layer exists to prevent that exact failure.
The decision records contain four separate decisions about Temporal. Thus this is the longest section on the page. The decisions are:
- The primary decision. The alternative was a simple message queue: Amazon's queue service, with the name SQS. A queue only delivers messages. It does not keep the position of a long task. It cannot hold a durable timer, for example a timer for nine days. It cannot accept a signal in the middle of a task, for example a lead's request to stop calls. When a server stops, a queue loses all data about a task in progress. The lead lifecycle needs those four abilities, so the team rejected the queue.
- Its own service. The long memory operates as a separate program, apart from the backend. The team can update the website with no effect on the active calls. The two programs scale independently. A stop of that one program stops all outbound dialling. This gives a clean emergency stop, with no effect on the screens or on the record.
- One journey for each lead. Each lead gets its own long task. The rejected alternative was a central scheduler that scans a work list each minute. The team rejected the scheduler because it causes the exact timing conflicts and duplicate-call risks that Temporal removes. At full scale, approximately 150,000 journeys are in progress at the same time. That load is a deliberate trade, and the team committed to a rehearsal at realistic volume before the final sizing. The team cannot change one capacity setting after the creation of the production system.
- The check is inside the task. The pre-dial compliance check is inside the call-attempt task itself. Thus every route to a dial goes through the identical checks. The routes include the automatic cadence, an operator's manual call command, and each future path. No call can get to the carrier without a recorded verdict. The result is one path to test, and one path to show to a regulator.
The record keepers
PostgreSQL — the record
PostgreSQL (postgresql.org) is the single authoritative record. It holds every client, lead, campaign, call attempt, outcome, permission, suppression, and appointment. The platform accepts an event as a fact only when the event is in the record.
- Why this database: PostgreSQL has decades of proven use. Its crucial feature here is row-level security. Those rules are inside the database itself, and they decide which rows each request can see.
- The failure without it: the platform has no single version of the truth, and no enforced separation between clients.
- The rejected alternative: filters in the application code for each client's data on every query. The team rejected it because one forgotten filter causes a data breach.
The separation rules are inside the database, with one important detail. A database does not apply a table's security rules to the owner of the table. Thus the platform intentionally connects with a lower-privilege identity, and the rules do apply to that identity. The platform marks each request with the client and the user that make the request. Tests prove that the rules operate: a request without the marks gets zero rows.
Supabase — the front door
Supabase (supabase.com) manages sign-in. Its identity service, with the name GoTrue, checks the passwords and issues a signed pass. The backend verifies that pass on every request. The pass contains your identity and your client, in a field that users cannot edit.
- Why the platform does not build sign-in itself: password checks and account recovery are security-sensitive functions. A specialist tool is the best owner of those functions. In-house password code is a frequent source of security weaknesses. That risk is the failure without this choice.
- The recorded decision examined two alternatives, and the team rejected both. The first alternative was sign-in code inside the backend itself. The team rejected it for the reason above. The second alternative was the full Supabase suite. The team rejected it because most of the suite — a heavy gateway and several sub-services — serves features that this platform does not use. Unused complexity in operation is a risk without a benefit.
The platform operates a small, self-hosted subset instead: the database, the sign-in service, and an admin studio, behind a small and simple gateway. Self-hosted means that the subset operates on the platform's own servers, not in a third-party cloud.
Redis — the tally counter
Redis (redis.io) is the platform's very fast short-term memory for counts that expire. It also holds cached data, and it can hold queues of work in the future.
- A concrete example from the built code: the limit on password-reset attempts. Redis counts the attempts for an address, and it deletes the count after fifteen minutes.
- Why a separate tool: some counts change thousands of times and expire in minutes. Those counts do not belong in the permanent record. A specialist in-memory store holds them and deletes them at the correct times.
- The failure without it: one of two problems occurs. Either the permanent record fills with unimportant short-term data, or the platform has no rate limits. Without rate limits, a person can attack the password-reset function continuously.
- The alternative: the team recorded no formal alternative. Redis is the standard tool for this function.
Object storage — the filing cabinet
Object storage holds the large files, primarily the lead spreadsheets that clients upload. The store gives out signed links with time limits. Thus the files move directly between the browser and the store, not through the backend. In development, the store is MinIO (min.io), an open-source substitute. In production, the store can be any compatible host.
- Why a tool: a database is the wrong tool for large files. Object storage is a specialist tool for large files.
- The failure without it: the uploads make the record too large, and each large download goes slowly through the backend.
- The important as-built decision: the platform uses the industry-standard storage interface, Amazon's interface with the name S3. The platform uses only the universal operations of that interface, and intentionally no vendor-specific operations. Thus the team can replace the provider with a configuration change alone, without new code.
Where people meet the platform
React — the control-room screens
React (react.dev) is the toolkit for all of the screens that your team sees and uses. The screens include the dashboard, the lead browser, the call detail view, the campaign controls, and the team settings. They are fast, interactive screens that operate in the browser.
- Why this toolkit: screens that update with the live operation must have a strong interface toolkit. React is the most widely used toolkit, and it has the best support. Its ecosystem supplies ready parts: the navigation, the live data retrieval, the data tables, and the accessible components. The alternative is a hand-built and hand-maintained version of each part.
- The failure without it, or without an equivalent toolkit: your team can then operate the platform only through a programmer.
Resend — the branded post
Resend (resend.com) delivers the platform's email: team invitations, password resets, and the mid-call callback notices. A Callback ASAP notice tells a broker that a merchant wants a person to call as soon as possible.
- The rejected alternative: the standard emails from the sign-in service's built-in mailer. The team rejected it because those templates permit almost no brand changes, no preview, and no review. Instead, the backend makes fully branded templates with a preview option, and Resend's service delivers them. The sign-in service keeps one function only: it makes the one-time secure links inside those emails.
- A good result of that division: in development, the platform can operate without a delivery key. Without the key, the platform sends no emails, and it writes the links to the log. All functions operate with no mail infrastructure.
- The failure without this choice: the platform sends unbranded system mail, or no mail. Then a Callback ASAP notice can stay in an unwatched inbox, and the team loses that lead.
The safety instruments
OpenAI — the reader
After a call ends, a language model from OpenAI (openai.com) reads the transcript. Before the model reads the text, the platform removes phone numbers, email addresses, card and social security numbers, street addresses and ZIP codes. Names, and the voice provider’s call summary, still reach the model. The model then completes the judgement parts of the outcome. Those parts are: the person that the call actually reached, the level of interest, the qualification status, and the financing need. The model also gives a second check on the compliance phrases. People phrase a request to stop calls in many different ways, and the model can detect those phrasings.
The recorded decision also sets limits on the model. Those limits are as important as the tool:
- The model never controls the live call.
- The model never replaces the hard facts. The phone-line events decide if a human answered. A probabilistic judgement never has priority over a deterministic fact.
- Compliance detection always selects the safe result. If the phrase-match check or the model detects a request to stop calls, the platform sets the flag and stops the calls.
- The platform sends the low-confidence results to a queue for human review. The platform does not guess.
- The work is classification, not conversation. Thus a small, low-cost model is sufficient.
Without the model, the outcomes contain only the phone-line facts: connected or not connected. The business then loses the interest data and the qualification data that it needs.
One honest note: the original plans named the product Mastra as an AI analysis layer. The team did not build it. In the built system, this model and the evaluation toolkit below do the analysis.
Coval — the examiner's phone booth
Coval (coval.ai) makes simulated phone calls to the agent, with reactive simulated callers. It scores the conditions that text tests cannot measure: accents, background noise, and interruptions. It also measures how frequently the agent hears a word incorrectly. That measure has the name word-error rate.
The recorded decision examined three alternatives:
- Hamming is a similar service with less maturity. The team rejected it for that reason.
- The voice provider's own test function has no word-error scores and few evaluation features. The team rejected it.
- An in-house build repeats work that an available tool already does. The team rejected it.
The team selected Coval as the specialist option. A layered test strategy operates around it:
- Low-cost, deterministic replay checks and text-simulation checks run on each proposed change in seconds.
- The costly voice layer runs each night, and before the publication of an agent change. Each simulated call costs approximately ten to fifteen cents.
- The strictest rule of the check: the count of missed requests to stop calls must be zero, without exception.
Without Coval, you first discover that the agent hears an accent incorrectly on a call with a real customer.
OpenTelemetry — the flight recorder
OpenTelemetry (opentelemetry.io) is the open standard for the platform's logs, measurements, and traces. Each service — the backend, the worker, and the rehearsal service — writes structured logs, timing measurements, and request traces with it. All of that data goes to one place. Thus you can follow one call across every service that touched the call, and into the long-memory tasks. The platform also runs health checks on itself, keeps measurements of the record, and shows the live status of the outside providers.
- Why a standard and not one product: the platform has four services and three outside providers. Without one continuous trail, the team cannot answer the question: what occurred at two in the morning? Also, with the open standard, the team can replace the monitoring backend without new code.
- The failure without it: the team must find faults with guesses, and outages continue for hours, not minutes.
The workshop
Nx — one workshop for everything
The full platform is in one repository. The repository contains four applications — the backend, the calling worker, the control-room site, and the rehearsal service — plus a set of shared libraries. Nx (nx.dev) manages the repository.
- Why one repository: the backend and the worker must apply exactly the same business rules. Two examples: the definition of a request to stop calls, and the calculation of a call's outcome. In one repository, the two applications use the same rule code, so a difference between them is impossible. Nx also knows the dependencies between the parts. Thus a change rebuilds and retests only the parts that the change touches.
- The failure without it: multiple copies of the rules change separately over time. That separation causes a compliance failure at an unknown future time.