Skip to content

Înregistrare și storage ​

Înregistrările, transcrierile și export-urile pot fi scrise în bucket-ul tău, nu în al platformei. Pentru un client reglementat asta e de obicei întrebarea care decide, așa că se configurează per organizație, per tip de artefact, și e validată cu o scriere reală înainte să fie crezută.

Unde ajung artefactele ​

O destinație de storage e un bucket plus credențiale plus un domeniu de aplicare. Există opt drivere:

DriverSecretele de care are nevoieObservații
platformniciunulBucket-ul gestionat al platformei. Implicit, când nu e configurat altceva.
s3access_key_id, secret_access_keyAmazon S3. Are nevoie de region.
s3_stsexternal_idAssume-role, fără chei statice. Are nevoie de role_arn în settings.
r2access_key_id, secret_access_keyCloudflare R2. Are nevoie de account_name.
azure_blobaccount_keyAzure Blob Storage. Câmpul de bucket e containerul.
gcsservice_account_jsonGoogle Cloud Storage.
supabaseaccess_key_id, secret_access_keyGateway-ul S3 al Supabase.
s3_compatibleaccess_key_id, secret_access_keyMinIO, Backblaze B2, Wasabi. Cere un endpoint.

Fiecare driver declară de ce câmpuri are nevoie — region, endpoint, account_name — iar selectorul oferă doar driverele pe care instalarea asta le poate construi efectiv, verificate față de adaptoarele Flysystem prezente. Un driver pe care nu îl poți construi nu e oferit ca opțiune pe care descoperi mai târziu că e stricată.

CâmpCe înseamnă
bucketNumele containerului.
region / endpointObligatorii, în funcție de driver.
path_prefixTot ce scrie CallAgent merge sub el.
use_path_stylePentru endpoint-uri compatibile S3 care au nevoie de el.
applies_torecordings, transcripts sau exports — o destinație nu trebuie să le ia pe toate trei.
retention_daysCurăță după atâtea zile.
is_defaultFolosită când nicio destinație mai specifică nu se potrivește.

Validează înainte să te bazezi pe ea

Acțiunea Test face o scriere, o citire și o ștergere reale în bucket și înregistrează rezultatul. Mai mult: compară octet cu octet ce a citit înapoi cu ce a scris, ceea ce prinde un bucket versionat, cu cache sau doar-scriere. „Credențialele sunt salvate" și „bucket-ul funcționează" sunt afirmații diferite, iar interfața le ține separate.

Destinațiile de storage se configurează din dashboard, la Platform → Storage destinations. Nu există niciun endpoint /api/v1 pentru ele.

Custodia e urmărită per artefact: call_artifacts.storage_destination_id reține în ce destinație a aterizat efectiv un obiect, deci schimbarea celei implicite nu orfanizează tot ce a fost scris înainte. Artefactele existente sunt mutate de un job de relocare, nu re-indicate în tăcere.

Înregistrare ​

Înregistrarea se setează per asistent, în artifact_plan, și per număr de telefon.

CâmpImplicitObservații
recording_enabledtrueSe poate reda un anunț; un refuz nu poate fi respectat — vezi mai jos.
recording_formatwavwav · mp3 · ogg
stereo_recordingfalse
transcript_enabledtrue
messages_enabledtrue
events_enabledtrue
logs_enabledtrue
debug_json_enabledfalse
retention_days—0–3650.
pii_redactionopritVezi mai jos.
post_call_transcriptionoprit{ enabled, provider, model, language }. Sonix e singurul adaptor.

Calea de storage nu e configurabilă

storagePathTemplate există în contract, cu valoarea implicită org/{{call.organizationId}}/calls/{{call.id}}/{{artifact.kind}}.{{artifact.ext}}. Recorderul nu îl citește niciodată — își scrie hardcodat org/{organizationId}/calls/{callId}/{channel}.wav. Folosește path_prefix pe destinația de storage dacă ai nevoie de un prefix propriu.

Două canale ​

mono amestecă ambele părți într-un singur canal. stereo și dual țin apelantul și asistentul separabili, ceea ce face posibile o formă de undă pe două piste, analiza pe vorbitor și o redactare curată — nu poți scoate curat numărul de card al apelantului dintr-o înregistrare amestecată.

Asta e dusă până la carrier, nu simulată: integrarea Twilio setează RecordingChannels pe dual, iar generatorul de directoare FreeSWITCH emite record_stereo pentru trunk-urile proprii. Twilio, Telnyx și BYO SIP declară toate înregistrarea pe două canale ca implementată; verifică matricea de capabilități a furnizorului înainte să presupui că o face și un al patrulea carrier.

call_legs.recording_channel reține ce canal a ocupat fiecare leg, iar rândul de artefact poartă channels, sample_rate, codec, duration_seconds, size_bytes și un checksum_sha256.

Consimțământ ​

recording_consent_plan.mode stabilește ce se spune:

ModComportament
noneImplicit. Nu se spune nimic.
announcementTextul configurat e rostit înainte de salut.
assistant_spokenAsistentul îl spune cu vocea lui.
custom_audioFișierul tău audio de la audio_url.

Se redă un anunț. Consimțământul nu se obține.

Trei lucruri, toate verificate în cod:

Înregistrarea pornește înainte de anunț. Recorderul e construit și pornit, redarea începe, și abia apoi se rostește notificarea. Anunțul e el însuși în înregistrare.

Un refuz nu poate fi respectat. Gateway-ul raportează exact o stare de consimțământ: announced. Nu raportează niciodată granted sau denied, pentru că nimic nu colectează o confirmare — niciun prompt DTMF, niciun matcher de expresii. on_refusal e purtat în configurația apelului, nu e citit și nu se poate declanșa.

regions e documentație. Nimic nu se ramifică pe el. Serviciul care calculează planul spune în propriul comentariu că nu determină dacă o înregistrare e legală.

Dacă obligația ta e să informezi, un anunț o satisface. Dacă e să obții și să respecți consimțământul, rezolvă asta înainte ca apelul să ajungă la asistent, sau nu înregistra. Vezi Dezvăluire AI și consimțământ.

Starea se reține pe apel ca consent_policy, consent_state, consent_recorded_at și consent_region. Citește consent_state: "announced" ca „s-a redat o notificare", nu ca acord.

Redactare PII ​

artifact_plan.pii_redaction scoate categorii din textul stocat — conținutul mesajelor, transcrierea, rezumatul și payload-urile de evenimente — o singură dată, la finalizarea apelului. E oprită implicit. Pornirea ei aduce implicit card (validat Luhn) și national_id (SSN american, CNP românesc, NINo britanic); mai sunt disponibile email, phone, iban și tipare custom date de tine.

redact_recording nu redactează înregistrarea

Câmpul există. Fișierul audio nu e modificat niciodată. Dacă un apelant citește un număr de card cu voce tare, el e în WAV. Ca să nu ajungă în storage, folosește zero data retention sau nu înregistra.

Cum obții o înregistrare ​

GET    /api/v1/calls/{call}/recording          un URL semnat
DELETE /api/v1/calls/{call}/recording          o șterge
GET    /api/v1/calls/{call}/artifacts          tot ce a produs apelul
GET    /api/v1/calls/{call}/artifacts/{artifact}/download

Ruta de download e singura excepție de la autentificarea cu bearer din tot API-ul: e autorizată de un URL semnat, deci un link de înregistrare poate fi dat unui browser sau unui player audio fără să scurgă o cheie.

bash
# Întoarce un URL semnat, de scurtă durată, nu audio-ul în sine

curl "$CALLAGENT_API_URL/calls/01JQ…/recording" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY"
ts
const { data } = await fetch(`${process.env.CALLAGENT_API_URL}/calls/${callId}/recording`, {
  headers: { Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}` },
}).then((response) => response.json());

// data.url e semnat și expiră; nu îl stoca, cere-l din nou.

Ștergerea unei înregistrări e o ștergere reală, ceea ce cere o solicitare GDPR. Vezi Securitate.

Retenție și zero data retention ​

Retenția e per organizație și per categorie de artefact. Șase categorii, fiecare cu propriul câmp {categorie}_days: recordings_days, transcripts_days, events_days, logs_days, structured_outputs_days, analytics_days.

null înseamnă păstrează pentru totdeauna. 0 înseamnă curăță la următoarea rulare. Job-ul de noapte e php artisan callagent:calls:apply-retention, programat la 03:15.

zero_data_retention e modul care ține de toată organizația. Golește conținutul mesajelor, argumentele și rezultatele tools-urilor, timpii pe cuvânt, payload-urile evenimentelor, transcrierea, rezumatul, analiza, structured output-ul și subiectele, și șterge artefactele de înregistrare — lăsând rândul de artefact marcat purged, ca dovadă că a existat ceva. Păstrează intenționat id-ul apelului, statusul, durata, cele două numere E.164, costurile, metricile, leg-urile și jurnalul de audit, pentru că facturarea și rezolvarea disputelor au nevoie de ele și niciunul nu e conținut de conversație.

zdr_delay_minutes: 0 îl rulează inline, la finalizare, nu la job-ul de noapte.

Un apel reține când s-a aplicat fiecare politică (redaction_applied_at, zdr_applied_at, content_purged_at), deci un audit poate arăta nu doar că o politică există, ci că a rulat.

Ștergerea unei înregistrări lasă rândul

RecordingService::purge() șterge audio-ul și pune recording_status = purged, păstrând rândul de artefact ca dovadă că a existat o înregistrare și că a fost ștearsă. De obicei asta vrea o cerere de ștergere — dovada ștergerii, nu absența oricărei urme.

Mai departe ​

Scrisă după cod. Ce nu este încă implementat este marcat ca atare, niciodată descris ca funcțional.