Sari la conținut
megapromotingHai să discutăm

Expertiză · Telefonie și contact center

Stratul de telefonie dintre operatorul tău și cine răspunde — om sau agent.

Construim centrala: trunkuri SIP, reguli de rutare pe program, meniuri IVR citite din bază, cozi de așteptare, transfer către om, înregistrare și analiză a apelurilor. Apelul devine o înregistrare cu transcript și rezumat, nu o amintire.

Construit dejaTrei implementări proprii, citate mai jos. (1) Stratul Asterisk din platforma Kallina: 5.522 de linii de configurație de dialplan, scripturi AGI și punți audio în `asterisk/`, plus șabloane de trunk generate automat per număr. (2) `asterisk-manager` — un serviciu separat care administrează cozile, trunkurile și fluxul RTP prin interfața de management a centralei. (3) Middleware-ul pentru centrala virtuală a unui operator, care a rulat în producție: commitul de reconciliere din 14 iulie 2026 aduce în depozit cod care rulase pe server și era cu circa 40 de zile înaintea git-ului. Rezerva, spusă înainte să întrebi: gazda SIP prin care trec liniile noastre de test nu răspunde — verificat azi, 06.09.2026, fără răspuns la ping și fără răspuns pe HTTP. Nu prezentăm un număr de demonstrație pe care să suni acum, pentru că nu l-am putea ridica în fața ta.

Între operatorul tău de telefonie și cine răspunde efectiv — un om sau un agent vocal — trebuie să existe un strat care ia decizii. Cine primește apelul la ora 23:40. Ce se întâmplă dacă nu răspunde nimeni. Unde se duce apelul când clientul cere „un om”. Ce rămâne din convorbire după ce s-a închis. Stratul acesta e o centrală, iar noi îl construim ca să fie al afacerii, nu al furnizorului de voce: dacă mâine schimbi motorul agentului, regulile de rutare, cozile și istoricul rămân la tine.

Concret, ce am construit: douăsprezece fișiere de dialplan — producție, IVR, coadă, transfer, voicemail, redirecționare, apeluri ieșite cu agent — patru scripturi AGI în Python și două punți audio, în total 5.522 de linii. Motorul de IVR nu are meniurile scrise în fișier: le citește din bază printr-un script AGI și întoarce una din șase decizii — către un agent, către alt meniu, către o coadă, transfer la un număr extern, mesaj final, sau închidere. Cozile se numesc după identificatorul lor și nu au membri scriși în configurație: se adaugă și se scot din exterior, prin interfața de management, ceea ce înseamnă că un operator poate intra sau ieși din coadă fără repornirea centralei.

Rutarea are reguli reale, nu un singur „sună aici”: ore de program și fus orar, program peste noapte de tipul 22:00 → 06:00, și potrivire pe prioritate — antetul SIP `Diversion`, care poartă numărul original de pe care s-a redirecționat apelul, apoi numărul propriu, apoi regula de rezervă. Trunkurile sunt generate per număr, cu nume construit din furnizor și număr, de o funcție de configurare — nu scrise de mână la fiecare linie nouă.

Ce iese din apel e la fel de important ca apelul. Pentru linia legată de centrala virtuală a unui operator am construit un middleware în Python care interoghează lista de înregistrări la fiecare minut, cu o reconciliere largă la fiecare șase ore ca o pană de rețea să nu piardă nimic, și un scan la trei minute al apelurilor pierdute — acelea nu au înregistrare și altfel ar fi complet invizibile. Fiecare înregistrare se descarcă, se transcrie, se analizează și se oglindește în analiza de apeluri, iar apelul pierdut devine o alertă. Idempotența stă într-un set Redis, ca aceeași înregistrare să nu fie procesată de două ori.

Ce cuprinde

Lucrarea, pe componente

Numărul intră pe un trunk generat, nu scris de mână

Șabloanele de trunk sunt parametrizate și completate de o funcție de configurare, cu nume format din furnizor și număr. În șablon sunt scrise transportul, codecurile permise, tratarea NAT, modul DTMF și autentificarea. Consecința practică: al zecelea număr se conectează la fel ca primul, iar diferențele dintre operatori stau într-un singur loc.

Centrala decide unde merge apelul, după reguli scrise

Ore de program și fus orar, program peste noapte de tipul 22:00 → 06:00, potrivire pe prioritate: antetul SIP `Diversion` (numărul de pe care s-a redirecționat), apoi numărul propriu, apoi regula de rezervă. Căutarea regulii se face printr-un script AGI care întreabă platforma în timpul apelului, cu termen de așteptare propriu — deci o regulă schimbată în interfață se aplică la următorul apel, fără repornire.

Apelul ajunge la agent, la coadă sau la om

Către agentul vocal, audioul trece printr-o punte care convertește codecul în ambele sensuri, `g711_ulaw` ↔ `PCM16`. Către oameni, apelul intră într-o coadă administrată din exterior. Iar transferul e la îndemâna celui care vorbește: transfer orb prin `##` și transfer asistat prin `*2`, cu apelul aterizând într-un context scris pentru asta, care distinge extensiile interne de patru cifre de numerele externe.

Meniu IVR citit din bază, nu din fișier

Motorul de IVR primește identificatorul meniului și îl citește din bază printr-un script AGI. Rezultatul e una din șase decizii: către un agent, către alt meniu (recursiv), către o coadă, transfer extern, mesaj final, închidere. Mesajele pot fi sintetizate sau pot fi fișiere audio înregistrate dinainte. A schimba un meniu înseamnă a schimba un rând în bază, nu a edita un fișier de configurare pe server.

Cozi cu membri dinamici

Fiecare coadă poartă numele derivat din identificatorul ei. Membrii nu sunt persistați în configurație: se adaugă și se scot în timpul funcționării prin interfața de management a centralei, iar poziționarea simultană pe mai multe locuri libere e activată. Practic, un operator intră sau iese din coadă fără ca centrala să fie repornită și fără ca apelurile în așteptare să fie afectate.

Dispecerizare către oameni de pe teren

Un agent poate suna el pe cineva din exterior și să se întoarcă cu răspunsul. Mecanismul e implementat cu tabel propriu și stări explicite — se sună, în curs, se reîncearcă, finalizat, eșuat, fără răspuns, expirat — cu maximum trei încercări și o pauză de două minute între ele, iar rezultatul (inclusiv timpul estimat de sosire) se întoarce structurat către conversația care l-a cerut. Nu e un concept: sunt cinci funcții de server dedicate, plus o măturare a apelurilor rămase agățate.

Apelurile devin date, inclusiv cele la care nu a răspuns nimeni

Un proces programat citește lista de înregistrări la fiecare minut, cu reconciliere largă la fiecare șase ore ca o pană să nu piardă nimic. Înregistrarea se descarcă în WAV, se transcrie, se analizează și se oglindește în analiza de apeluri împreună cu audio. Separat, la fiecare trei minute se citesc apelurile nepreluate — care nu au înregistrare și altfel n-ar exista nicăieri — și devin alertă. Un apel pierdut e un client pierdut; a-l face vizibil e cea mai ieftină îmbunătățire dintr-un centru de apel.

Frâne față de API-ul operatorului

Clientul care vorbește cu centrala operatorului are limitator propriu de rată, cu găleată de jetoane, și tratare explicită a erorilor. Nu e o precauție teoretică: un middleware care interoghează la fiecare minut și reconciliază la șase ore poate, fără frână, să lovească limita operatorului și să fie blocat exact când ai nevoie de el.

Cum arată

Straturile unei linii telefonice: trunkul operatorului, centrala cu regulile de rutare, puntea audio către agent, coada și transferul către om, apoi înregistrarea, transcrierea și analiza.

01

Inventarul liniilor înainte de orice configurație

Ce numere există, la ce operator, cine răspunde azi pe fiecare, în ce program, și ce se întâmplă acum când nu răspunde nimeni. Pare birocrație; e partea care previne surprizele. Din experiența noastră, într-un parc de numere există aproape întotdeauna linii pe care baza spune un lucru și centrala altul — iar ele nu se descoperă la lansare, ci acum.

02

Trunk, apoi test în ambele sensuri, separat

Numărul intră pe trunk, iar apelurile primite și cele ieșite se testează ca două lucruri distincte, pentru că se strică distinct. Avem documentat un caz în care apelurile primite funcționau perfect zile la rând, în timp ce toate apelurile ieșite erau respinse de centrala operatorului cu `403 Forbidden`, fără nicio schimbare la noi. Un singur test „a sunat și a mers” nu acoperă asta.

03

Dialplan: rutare, IVR, coadă, transfer, voicemail

Regulile de program și de prioritate, meniurile, cozile și căile de transfer se scriu ca dialplan și ca rânduri în bază, nu ca înțelegere verbală. La final știi exact ce se întâmplă cu un apel la ora 23:40, sâmbăta, când agentul nu înțelege cererea.

04

Apelurile intră în sistemele tale

Rezultatul apelului — transcript, rezumat, sentiment, adresa înregistrării, durata — se trimite mai departe printr-un webhook semnat, iar organizația se identifică după numărul de telefon. Acolo unde există un CRM, apelul se leagă de fișă și poate muta automat starea; despre partea aceasta scriem pe pagina de CRM și automatizarea vânzărilor.

05

Continuitatea se discută la început, nu după prima cădere

O centrală pe o singură gazdă e un singur punct de defectare, iar noi am trăit exact asta: când gazda nu răspunde, toate liniile care trec prin ea cad odată cu ea, indiferent cât de bine e configurat agentul. Semnătura defectului e limpede — apelul întoarce „request timed out” cu identificatorul de apel SIP gol, adică apelul SIP nu s-a stabilit niciodată. De aceea, într-un proiect real, întrebarea „ce se întâmplă când gazda cade” se pune și se bugetează la început: a doua gazdă, monitorizare care sună un om, și o cale de rezervă către numere obișnuite.

Ce vede utilizatorulAplicațiaRețea și securitateGăzduire și dateFIECARE STRAT, ALES ȘI EXPLICAT
Straturile unei linii telefonice: trunkul operatorului, centrala cu regulile de rutare, puntea audio către agent, coada și transferul către om, apoi înregistrarea, transcrierea și analiza.

Datele

Ce atingem, unde stau și cât rămân

Întrebările pe care le pune oricine are un responsabil cu protecția datelor — puse aici înainte să le pună el.

Unde ajunge evidența apelurilor
Evidența apelurilor a centralei se scrie azi local, în format CSV, pe gazda centralei; scrierea ei într-o bază PostgreSQL este pregătită în configurație, dar rămâne dezactivată. O spunem pentru că are o consecință directă: dacă vrei rapoarte peste apeluri în afara centralei, activarea evidenței în bază e o lucrare de făcut, nu o casetă de bifat. Transcriptele și analizele stau separat, în platformă, legate de spațiul tău de lucru.
Ce se stochează dintr-un apel
Numărul apelantului și numărul apelat, momentul, durata, rezultatul, înregistrarea audio, transcriptul și analiza. Pentru apelurile nepreluate există număr, moment și motivul lipsei de răspuns — nu există audio, pentru că nu s-a produs. Înregistrarea se descarcă în WAV la 8 kHz, mono, și se convertește la un format comprimat pentru livrarea către oameni.
Idempotența, ca datele să nu se dubleze
Fiecare înregistrare procesată e marcată într-un set Redis. Reconcilierea largă poate reciti aceeași fereastră de timp fără să retrimită nimic. E detaliul care face diferența între un sistem care poate fi repornit liniștit și unul care, la fiecare repornire, trimite din nou toate alertele de ieri.
Cine poate asculta o înregistrare
Datele de apel sunt legate de spațiul de lucru al afacerii, iar accesul trece prin autentificare. Nu există un depozit comun peste clienți și nu există acces „de la platformă” fără o identitate. Cine anume din echipa ta are dreptul să asculte se stabilește la implementare, nu implicit.
Retenția și anunțul de înregistrare sunt decizii ale tale
Cât se păstrează audio, transcriptul și evidența apelurilor, și ce se spune la începutul convorbirii despre faptul că e înregistrată, sunt decizii ale operatorului de date — adică ale tale. Ștergerea la cerere e implementată în platformă; ștergerea automată la termen se face azi prin procedură, nu printr-un ceas, deci dacă îți trebuie automată, intră ca lucrare în proiect.

Un caz

Apelurile lungi dispăreau. Cele scurte, nu.

Situația

Într-un flux de analiză a convorbirilor, o parte din apeluri ajungeau în analiză și o parte nu. Tiparul a fost cel care a dat cauza: lipseau exact apelurile lungi. Un defect care se raportează ca „uneori nu merge” și se caută, greșit, în transcriere.

Ce am construit

Erau două căi de transcriere și amândouă cădeau, pentru motive diferite. Calea multimodală trimite fișierul audio întreg codificat în corpul cererii; peste o anumită mărime, limita de corp a serverului intermediar a răspuns cu 413. Calea de rezervă cerea un model de transcriere pe care cheia de acces nu îl mai permitea, deci răspundea cu 403. Ambele eșuau, procesul raporta că toate modelele de transcriere au eșuat, iar apelul era abandonat. Apelurile scurte rămâneau sub limita de corp, deci treceau — de aici tiparul. Reparația a fost: se sare peste calea multimodală pentru fișierele WAV peste 12 MB (prag configurabil din mediu), se refolosește transcriptul deja calculat în loc să se transcrie a doua oară, iar transcrierea de ultimă instanță a fost mutată pe un model permis.

Ce a ieșit

Verificat pe înregistrarea rămasă blocată: o convorbire de 21 de minute, fișier WAV de 41 MB — calea multimodală ocolită, transcript preluat, analiză generată, rând și audio ajunse în analiza de apeluri, zero eșecuri. Reconcilierea a confirmat apoi că nu mai există alte înregistrări blocate.

Ce nu spune cazul

Pragul de 12 MB e o proprietate a serverului intermediar, nu a apelului. Când se schimbă gateway-ul, cheia sau modelul, pragul trebuie reverificat — de aceea l-am făcut configurabil din mediu, nu scris în cod.

Întrebări

Ce ne întreabă oamenii înainte să sune

Aveți un număr pe care pot suna acum, ca să aud agentul?

Nu azi, și preferăm să spunem asta decât să dăm un număr care sună în gol. Partea de agent se poate asculta în pagină, imediat. Partea de telefon depinde de o gazdă SIP, iar gazda prin care trec liniile noastre de test nu răspunde la data scrierii — verificat azi, fără răspuns la ping și fără răspuns pe HTTP. Pentru un proiect al tău, telefonia se ridică pe o gazdă dedicată proiectului, nu pe cea de test.

De ce centrală proprie și nu direct furnizorul de agent vocal?

Pentru că regulile de rutare, cozile, transferul, voicemailul și istoricul apelurilor sunt ale afacerii, nu ale furnizorului de voce. Cu centrală proprie poți schimba motorul agentului fără să rescrii cum se comportă telefonul tău, poți trimite același apel când la un agent, când la un om, și poți ține evidența apelurilor la tine. Fără ea, ești legat de ce alege să expună furnizorul.

Ce se întâmplă dacă serverul centralei cade?

Cad toate liniile care trec prin el. Nu e ipoteză: e ce am trăit noi, iar semnătura e ușor de recunoscut — apelul întoarce „request timed out” cu identificatorul de apel SIP gol, deci nu e vina agentului, a numărului sau a promptului. Concluzia pe care am tras-o și pe care o punem acum în fiecare proiect: continuitatea nu e o funcție a centralei, e o decizie de arhitectură și de buget, luată la început. Se rezolvă cu o a doua gazdă și cu o rută de rezervă către numere obișnuite, nu cu o setare.

Apelurile ieșite funcționează sigur, dacă cele primite funcționează?

Nu. Sunt două lucruri diferite, iar operatorul le poate trata diferit. Avem documentat un caz în care, cu configurația noastră neschimbată și cu apelurile primite funcționale, centrala operatorului a început să respingă toate apelurile ieșite cu `403 Forbidden` — dovada că era la operator a fost că un al doilea cont, cu configurație identică structural, continua să sune în afară. De aceea nu promitem o campanie de apeluri ieșite înainte de un test de ieșire reușit pe numărul tău.

Puteți lucra cu centrala virtuală pe care mi-o dă operatorul?

Da, și am făcut-o: am scris un middleware în Python peste API-ul unei centrale virtuale de operator, cu client propriu, limitator de rată, descărcare de înregistrări, transcriere, analiză și alertare, rulat în producție. Ce trebuie știut dinainte: accesul la API-ul extins e adesea un serviciu separat, contractat aparte, iar credențialele pot să nu funcționeze de la prima încercare — la noi, ciclul de clarificare a specificației și de resetare a parolei cu operatorul a durat luni, cu serviciul deja facturat. De aceea, într-o ofertă care depinde de API-ul unui operator, punem explicit condiția: lucrarea începe după ce autentificarea a fost demonstrată, nu după ce a fost promisă.

Se înregistrează apelurile și cine le poate asculta?

Se pot înregistra, transcrie și analiza. Ele rămân legate de spațiul de lucru al afacerii tale, iar accesul cere autentificare — nu există depozit comun peste clienți. Cine din echipa ta are dreptul de ascultare se stabilește la implementare. Anunțul către interlocutor și temeiul înregistrării sunt decizii ale tale ca operator de date; le scriem în scenariu, nu le presupunem.

Ce se întâmplă cu apelurile la care nu răspunde nimeni?

Sunt cazul cel mai prost tratat în majoritatea firmelor, pentru că nu lasă urmă: nu au înregistrare, nu au transcript, există doar în evidența apelurilor. La noi, un proces citește evidența la fiecare trei minute, identifică apelurile nepreluate și le transformă în alertă și în rând vizibil. Ca să fie clar despre ce depinde: le vedem doar în măsura în care operatorul le expune în evidența lui.

Puteți face meniuri de tip „apasă 1 pentru...”?

Da, iar meniurile stau în bază, nu în fișiere pe server. Motorul citește configurația meniului în timpul apelului și decide una din șase căi: către un agent, către alt meniu, către o coadă, transfer la un număr extern, un mesaj final, sau închidere. Mesajele pot fi sintetizate sau înregistrate dinainte. Practic, o schimbare de meniu nu cere intervenție pe centrală.

Cum aflu dacă un apel s-a pierdut pe drum, între centrală și analiză?

Prin reconciliere, și e o piesă pe care o construim explicit. Interogarea rapidă are o fereastră de câteva zeci de ore, iar peste ea rulează la fiecare șase ore o reconciliere pe o fereastră de o săptămână, care recitește mai multe pagini de rezultate. Fiecare înregistrare procesată e marcată, deci recitirea nu duplică nimic. Fără reconciliere, o pană de o oră înseamnă o gaură permanentă în date — și nimeni n-o observă.

Pe ce se sprijină fiecare afirmație de mai sus (22 surse)
  1. Gazda SIP prin care trec liniile noastre de test nu răspunde: ping 2/2 pierdute, HTTP și HTTPS cod 000ping -c 2 + curl http/https către gazda Asterisk OVH · 2026-09-06
  2. Semnătura defectului când gazda SIP cade: `success: false`, `message: "request timed out"`, `sip_call_id` gol, `call_status = failed`, durată 0reference_asterisk_ovh_down.md:
  3. 5.522 de linii în stratul Asterisk: 12 fișiere de dialplan, 4 scripturi AGI Python, 2 punți audio, configurație de evidență a apelurilor și de coadă (wc -l *.conf *.py *.mjs = 5522):
  4. Motorul de IVR citește meniul din bază prin AGI și întoarce una din șase decizii: route_to_agent, route_to_menu, route_to_queue, transfer, play_message, hangupextensions-ivr-engine.conf:1-30
  5. Cozile poartă numele derivat din identificator, membrii se adaugă dinamic prin interfața de management (persistentmembers = no, autofill = yes)queues-kallina.conf:1-45
  6. Transfer orb `##` și transfer asistat `*2`; contextul de aterizare distinge extensiile interne de patru cifre de numerele externeextensions-transfer.conf:1-40
  7. Rutare pe program și fus orar, program peste noapte 22:00 → 06:00, prioritate antet SIP Diversion → număr propriu → regulă de rezervă; căutarea regulii se face prin AGI, cu termen de așteptareforwarding-lookup.py (305 linii):70-73
  8. Șabloane de trunk parametrizate, completate de o funcție de configurare; nume `{provider}-{număr}`; TLS, codecuri, NAT, DTMF rfc4733 în șablonpjsip-trunks-kallina.conf:1-70
  9. Punte AudioSocket între centrală și agent, cu conversie g711_ulaw ↔ PCM16:76-78
  10. asterisk-manager e un serviciu separat: administrare de cozi prin AMI, monitor de trunkuri, monitor RTP, redirecționare de evenimente):
  11. Dispecerizare cu stări explicite: calling / in_progress / retrying / completed / failed / no_answer / timeout, max_retries = 3, retry_delay_ms = 120000, rezultat JSONB cu timp estimat20260308200000_courier_calls.sql:4-40
  12. Cinci funcții de server pentru dispecerizare: call-courier, check-courier-result, courier-calls-sweep, courier-inbound-identify, courier-postcall-webhook:
  13. Middleware-ul de centrală virtuală a rulat în producție: reconcilierea din 14 iulie 2026 aduce în depozit cod care rulase pe server, cu circa 40 de zile înaintea ultimului commit.git — git log commit 33e4377, corpul mesajului:
  14. Programare: înregistrări la fiecare 60 s, reconciliere la fiecare 6 h, apeluri nepreluate la fiecare 3 minmain.py:242-259
  15. Fereastra de interogare rapidă 48 h, reconciliere pe 168 h (7 zile) și 5 pagini; idempotență într-un set Redis de înregistrări deja procesatetasks.py:44-50
  16. Pana de transcriere pe apelurile lungi: multimodalul codifică WAV-ul întreg și primește 413; calea de rezervă cerea un model refuzat cu 403; reparat cu prag de 12 MB configurabil din mediu și model permistasks.py:59,270-282; corpul commitului 33e4377:59, 270-282
  17. Verificat pe o înregistrare blocată de 21 de minute, WAV de 41 MB: multimodal ocolit, transcript refolosit, analiză generată, rând și audio împinse mai departe, zero eșecuri.git — corpul commitului 33e4377:
  18. Client cu limitator de rată propriu, cu găleată de jetoane, către API-ul centralei operatoruluirate_limiter.py:1-70
  19. Evidența apelurilor se scrie local în CSV; scrierea în PostgreSQL e pregătită dar dezactivată (tot conținutul comentat)REGISTRU-PROBLEME.md, nota de diagnostic din 18 iunie:
  20. Apelurile ieșite respinse de operator cu 403 Forbidden, cu apelurile primite funcționale și configurație identică structural pe un al doilea cont care suna normalREGISTRU-PROBLEME.md:IM-3
  21. Accesul la API-ul extins al centralei operatorului a fost contractat separat și nu a autentificat luni la rând, cu trei resetări de parolă și același cod de eroareINTEGRATION-LOG.md:Faza 2-3
  22. Rezultatul apelului ajunge în CRM printr-un webhook semnat, cu identificarea organizației după numărul de telefonserver.js:1724-1790

Citările interne arată numele fișierului și linia. Calea completă rămâne în depozitul nostru; o putem parcurge împreună, la cerere.

Ce ai vrea să funcționeze mai bine?

Povestește-ne despre procesul tău. Împreună stabilim ce merită construit, ce putem conecta și cum verificăm rezultatul.

Hai să discutăm