# Transcrieri (/ro/docs/api/gateway/transcripts)

Înregistrezi ședințe și apeluri pe orice dispozitiv și primești o transcriere română/engleză cu vorbitori și marcaje de timp pe cuvânt, apoi un rezumat, idei cheie, acțiuni și prompturi pentru agenți gata de rulat.

Transcrierile transformă o înregistrare în text căutabil și în ceva pe care poți acționa. Aplicația desktop, telefonul și ceasul înregistrează local și încarcă în fundal; gateway-ul transcrie cu etichete de vorbitor și marcaje de timp pe cuvânt (română și engleză, inclusiv amestecate în aceeași înregistrare), apoi scrie analiza: un titlu, un rezumat, idei cheie cu citări, acțiuni, decizii, întrebări deschise și prompturi pentru agenți pe care le poți lansa.

<Callout>
  Transcrierile se activează per cont cât timp sunt în previzualizare. Când funcția e oprită pentru
  cheia ta, toate endpoint-urile de mai jos răspund `404`.
</Callout>

## Drumul unei înregistrări [#drumul-unei-înregistrări]

1. **Creare.** `POST /v1/transcripts` cu un `client_id` generat de client (o reîncercare după un crash întoarce aceeași transcriere) și `started_at`. Stare `recording`.
2. **Încărcare.** Fiecare pistă (`mic`, `system` — sunetul sistemului, sau o singură pistă `mixed`) urcă prin **tus 1.0** la `/v1/uploads`: reluabil, cel mult 8 MB per `PATCH`, deci o conexiune căzută sau o repornire continuă de la ultimul octet pe care îl are serverul (`HEAD /v1/uploads/{id}`). Id-urile de încărcare aparțin contului tău; altă cheie nu le poate continua.
3. **Finalizare.** `POST /v1/transcripts/{id}/finalize` cu id-urile încărcărilor, durata, marcajele și (opțional) textul live. Stare `queued`.
4. **Transcriere.** Procesul de fundal taie sunetul în ferestre de cel mult 15 minute (limita pentru separarea vorbitorilor) și le trimite la Gemini 3.5 Transcribe. Vorbitorii sunt potriviți între ferestre. Stare `transcribing`, apoi `analyzing`.
5. **Analiză.** Un model scrie analiza din transcriere (cu prompt caching). Stare `ready`. Un eșec după 5 încercări se termină cu `failed` și `error`; `POST …/retranscribe` și `…/reanalyze` reiau un pas.

Cât timp un pas se reîncearcă, `status` nu se schimbă; `GET /v1/transcripts/{id}` întoarce `processing` cu `attempts`, `max_attempts`, `last_error` și `next_attempt_at`, ca un client să poată spune „se reîncearcă” în loc să pară blocat. `GET /v1/transcripts/stream` (server-sent events) trimite un eveniment `transcript` la fiecare schimbare de stare.

**Vizualizare live.** În timpul înregistrării, dispozitivul poate trimite `POST /v1/transcripts/{id}/live` cu textul curent (`finals`, `partial`, `level`, `device`, `elapsed_ms`, `paused`) cam o dată pe secundă. Fiecare vizualizator al fluxului (pagina din hub, desktop, telefon, ceas) îl primește ca `op: live`; nu se salvează nimic, iar cadrele la mai puțin de 250 ms sunt ignorate.

```ts
import { readFile } from 'node:fs/promises';
import { Codai } from 'codai-sdk';

const codai = new Codai({ apiKey: process.env.CODAI_API_KEY! });
const t = await codai.transcripts.create({
  client_id: crypto.randomUUID(),
  source: 'desktop',
  started_at: new Date().toISOString(),
});
const uploadId = await codai.transcripts.uploadAudio(await readFile('sedinta.ogg'), {
  transcriptId: t.id,
  onProgress: (sent, total) => console.log(`${sent}/${total}`),
});
await codai.transcripts.finalize(t.id, {
  duration_ms: 1_800_000,
  uploads: [{ track: 'mic', upload_id: uploadId }],
});
for await (const e of codai.transcripts.stream()) if (e.id === t.id && e.status === 'ready') break;
const gata = await codai.transcripts.get(t.id);
console.log(gata.insights?.summary);
```

```python
from codai import Codai

codai = Codai(api_key="codai_...")
t = codai.transcripts.create({"client_id": "rec-2026-10-06-1", "source": "desktop", "started_at": "2026-10-06T09:00:00Z"})
upload_id = codai.transcripts.upload_audio(open("sedinta.ogg", "rb").read(), transcript_id=t["id"])
codai.transcripts.finalize(t["id"], {"duration_ms": 1_800_000, "uploads": [{"track": "mic", "upload_id": upload_id}]})
srt = codai.transcripts.export(t["id"], "srt")["text"]
```

## Lucrul cu o transcriere [#lucrul-cu-o-transcriere]

- **Citire.** `GET /v1/transcripts/{id}`: vorbitorii (redenumești unul sau te marchezi pe tine cu `PATCH …/speakers/{label}`), replicile cu marcaje de timp pe cuvânt (corectezi una cu `PATCH …/utterances/{seq}`), marcajele și ultima analiză.
- **Căutare și întrebări.** `GET /v1/transcripts/search` caută după text și după sens (`mode=hybrid`, implicit). `POST /v1/transcripts/ask` răspunde la o întrebare din toate înregistrările tale, cu citări `[n]` către transcriere, vorbitor și moment.
- **Acțiune.** Analiza conține `prompts` sugerate pentru agenți; `POST …/prompts/{index}/accept` transformă unul într-un [prompt în așteptare](/docs/api/gateway/prompts) cu `source: transcript`, gata de lansat pe un dispozitiv.
- **Export și redare.** `GET …/export?format=md|txt|srt|vtt|json|pdf|docx` (vezi mai jos); `GET …/audio` întoarce linkuri semnate, de scurtă durată, pentru fiecare pistă.
- **Organizare.** Dosare (`/v1/transcript-folders`), etichete și fixare; un vocabular personal (`PUT /v1/transcript-vocabulary`) pentru nume și termeni pe care transcrierea trebuie să-i scrie corect.

## Export ca PDF sau Word [#export-ca-pdf-sau-word]

`GET /v1/transcripts/{id}/export?format=pdf` și `format=docx` întorc un fișier binar atașat, numit după titlu (un `filename` ASCII plus titlul exact în `filename*`). Documentul conține titlul, data, durata și vorbitorii, apoi rezumatul, ideile cheie și acțiunile când există analiza, apoi transcrierea pe vorbitori cu marcaje `[hh:mm:ss]`. PDF-ul încorporează un font Unicode, deci diacriticele (ș, ț, ă, î, â) apar corect la tipărire. Etichetele urmează limba transcrierii (română sau engleză).

```ts
import { writeFile } from 'node:fs/promises';

const pdf = await codai.transcripts.export(t.id, 'pdf'); // { bytes, filename, contentType }
await writeFile(pdf.filename ?? 'transcriere.pdf', pdf.bytes);
```

```python
docx = codai.transcripts.export(t["id"], "docx")  # {"bytes", "filename", "content_type"}
open(docx["filename"] or "transcriere.docx", "wb").write(docx["bytes"])
```

## Partajare printr-un link doar pentru citire [#partajare-printr-un-link-doar-pentru-citire]

`POST /v1/transcripts/{id}/shares` cu un `expiresInDays` opțional (1–365; fără el linkul nu expiră) întoarce `{ id, token, url, expiresAt }`, unde `url` este `https://hub.codai.ro/t/<token>`. Oricine are linkul poate citi titlul, vorbitorii, transcrierea, rezumatul, ideile cheie și acțiunile, **niciodată sunetul**, și nimic care să-ți identifice contul. Deciziile, întrebările deschise și prompturile sugerate rămân private.

- Tokenul are 32 de octeți aleatori și se afișează **o singură dată**: se păstrează doar amprenta lui SHA-256, așa că `GET …/shares` listează linkurile active cu `url: null`.
- `DELETE …/shares/{shareId}` revocă imediat un link; ștergerea transcrierii șterge toate linkurile ei.
- Pagina din spatele linkului citește `GET /v1/public/transcripts/{token}`, care nu cere cheie API, are limită de cereri per vizitator și răspunde `404` pentru un link necunoscut, expirat sau revocat.

```ts
const link = await codai.transcripts.shares.create(t.id, { expiresInDays: 30 });
console.log(link.url); // copiază-l acum; nu mai poate fi afișat
const active = await codai.transcripts.shares.list(t.id);
await codai.transcripts.shares.revoke(t.id, active[0]!.id);
```

## Confidențialitate, păstrare și limite [#confidențialitate-păstrare-și-limite]

- Sunetul stă într-un bucket din UE, criptat cu o cheie dedicată, și **se șterge după 30 de zile**; textul și analiza rămân până le ștergi tu. După ce sunetul dispare, `audio_purged_at` este setat și redarea și retranscrierea nu mai sunt oferite.
- `DELETE /v1/transcripts/{id}` șterge transcrierea și sunetul ei. Ștergerea contului șterge toate înregistrările; exportul contului include toate tabelele de transcrieri (fără sunet).
- Cel mult **3 ore** per înregistrare și **20 de ore pe lună** per cont (`GET /v1/transcripts/usage`).

## Tool-uri MCP [#tool-uri-mcp]

[Serverul MCP](/docs/gateway/clients#mcp-server) expune `list_transcripts`, `get_transcript`, `search_transcripts`, `ask_transcripts`, `export_transcript` (doar formatele text; PDF și Word sunt fișiere binare), `accept_transcript_prompt` și `transcript_share_create`, apelate cu cheia ta API (token-urile OAuth sunt refuzate). Ștergerea, revocarea linkurilor, reluarea și editarea rămân în aplicații.

<OpenAPIPage
  document="./openapi/ro/gateway.yaml"
  operations={[
    { path: '/v1/transcripts', method: 'get' },
    { path: '/v1/transcripts', method: 'post' },
    { path: '/v1/transcripts/usage', method: 'get' },
    { path: '/v1/transcripts/stream', method: 'get' },
    { path: '/v1/transcripts/search', method: 'get' },
    { path: '/v1/transcripts/ask', method: 'post' },
    { path: '/v1/transcripts/{id}', method: 'get' },
    { path: '/v1/transcripts/{id}', method: 'patch' },
    { path: '/v1/transcripts/{id}', method: 'delete' },
    { path: '/v1/transcripts/{id}/finalize', method: 'post' },
    { path: '/v1/transcripts/{id}/retranscribe', method: 'post' },
    { path: '/v1/transcripts/{id}/reanalyze', method: 'post' },
    { path: '/v1/transcripts/{id}/live', method: 'post' },
    { path: '/v1/transcripts/{id}/bookmarks', method: 'post' },
    { path: '/v1/transcripts/{id}/speakers/{label}', method: 'patch' },
    { path: '/v1/transcripts/{id}/utterances/{seq}', method: 'patch' },
    { path: '/v1/transcripts/{id}/audio', method: 'get' },
    { path: '/v1/transcripts/{id}/export', method: 'get' },
    { path: '/v1/transcripts/{id}/prompts/{index}/accept', method: 'post' },
    { path: '/v1/transcripts/{id}/shares', method: 'post' },
    { path: '/v1/transcripts/{id}/shares', method: 'get' },
    { path: '/v1/transcripts/{id}/shares/{shareId}', method: 'delete' },
    { path: '/v1/public/transcripts/{token}', method: 'get' },
    { path: '/v1/transcript-folders', method: 'get' },
    { path: '/v1/transcript-folders', method: 'post' },
    { path: '/v1/transcript-folders/{id}', method: 'patch' },
    { path: '/v1/transcript-folders/{id}', method: 'delete' },
    { path: '/v1/transcript-vocabulary', method: 'get' },
    { path: '/v1/transcript-vocabulary', method: 'put' },
    { path: '/v1/uploads', method: 'post' },
    { path: '/v1/uploads', method: 'options' },
    { path: '/v1/uploads/{id}', method: 'get' },
    { path: '/v1/uploads/{id}', method: 'patch' },
  ]}
/>
