# Greita pradžia

> Nuo rakto sukūrimo iki pirmos nuskaitytos transkripcijos per kelias minutes.

Šaltinis: https://diko.app/api-docs/greita-pradzia

Šiame vadove sukursite raktą, atliksite pirmą užklausą, kuri nuskaito jūsų pačių duomenis, importuosite viešą YouTube vaizdo įrašą ir nuskaitysite jo transkripciją. Visi pavyzdžiai naudoja bazinį URL `https://api.diko.app/api/v1`.

## 1. Sukurkite API raktą

1. Prisijunkite prie Diko ir atidarykite **Nustatymai → API**, tai yra [API raktų puslapį](https://studio.diko.app/settings/api) (`/settings/api`). Senoji nuoroda `/kurejams` nukreipia čia. Reikia „Verslas“ plano.
2. Pasirinkite **Sukurti raktą**, įveskite pavadinimą ir leidimų šabloną **Skaitymas ir importas** (`meetings:read`, `library:write`). Numatytasis galiojimas – 90 dienų.
3. Patvirtinkite veiksmą pakartotiniu prisijungimu, jei Diko to paprašys.
4. Nukopijuokite raktą. **Jis rodomas tik vieną kartą**, o paskui matysite tik užuominą, pavyzdžiui, `dk_live_Ab12…9xYz`.

Raktą laikykite aplinkos kintamajame, o ne kode:

```bash
export DIKO_API_KEY="dk_live_..."
```

> **Įspėjimas:**
> Raktas yra slaptažodis jūsų duomenims. Nedėkite jo į repozitoriją, naršyklės kodą ar žurnalus. Daugiau: [Saugumo gairės](https://diko.app/api-docs/saugumas.md).

## 2. Atlikite pirmą užklausą

Pradėkite nuo užklausos, kuri grąžina jūsų pačių duomenis. Šablonas **Skaitymas ir importas** apima abu žemiau pateiktus sąrašus. `library:write` apima `library:read`, o `meetings:read` nurodytas atskirai. Bazinį URL ir antraštes nustatykite vieną kartą: vėlesni žingsniai jais naudojasi.

### Bibliotekos transkripcijos

`GET /library/transcripts?limit=1` grąžina naujausią jūsų bibliotekoje pridėtą transkripciją. Reikia leidimo `library:read` (arba `library:write`, kuris jį apima).

**cURL**

```bash
curl "https://api.diko.app/api/v1/library/transcripts?limit=1" \
  -H "Authorization: Bearer $DIKO_API_KEY"
```

**Python**

```python
import os

import requests

BASE = "https://api.diko.app/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['DIKO_API_KEY']}"}

first = requests.get(f"{BASE}/library/transcripts", headers=HEADERS, params={"limit": 1}, timeout=30)
first.raise_for_status()
print(first.json()["data"])
```

**TypeScript**

```typescript
const BASE = "https://api.diko.app/api/v1"
const headers = { Authorization: `Bearer ${process.env.DIKO_API_KEY}` }

const first = await fetch(`${BASE}/library/transcripts?limit=1`, { headers })
if (!first.ok) throw new Error(`${first.status} ${await first.text()}`)
console.log((await first.json()).data)
```

Atsakymas yra sąrašas. `data` laiko elementus (tuščias masyvas, jei bibliotekoje dar nėra transkripcijų). `has_more` parodo, ar yra kitas puslapis. `next_cursor` leidžia gauti kitą puslapį ([Puslapiavimas](https://diko.app/api-docs/puslapiavimas.md)):

```json
{
  "object": "list",
  "data": [
    {
      "id": "trn_ZFF3NHc5V2dYY1E",
      "object": "library_transcript",
      "title": "Kaip veikia transkribavimas",
      "source_type": "youtube",
      "youtube_video_id": "dQw4w9WgXcQ",
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
      "channel": "Diko",
      "language": "lt",
      "duration_ms": 212000,
      "transcription_method": "captions",
      "summary": { "status": "ready", "text": null },
      "categories": ["Technologijos"],
      "added_at": "2026-10-11T09:30:00.000Z",
      "archived": false,
      "segment_count": 120,
      "revision": "r_6f6f4bb9762915b561878fd1e1fa7f56",
      "web_url": "https://studio.diko.app/library/dQw4w9WgXcQ"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

### Susitikimai

Jei raktas turi `meetings:read`, `GET /meetings?limit=1` tokiu pat sąrašo formatu grąžina naujausią jūsų susitikimą:

**cURL**

```bash
curl "https://api.diko.app/api/v1/meetings?limit=1" \
  -H "Authorization: Bearer $DIKO_API_KEY"
```

**Python**

```python
meetings = requests.get(f"{BASE}/meetings", headers=HEADERS, params={"limit": 1}, timeout=30)
meetings.raise_for_status()
print(meetings.json()["data"])
```

**TypeScript**

```typescript
const meetings = await fetch(`${BASE}/meetings?limit=1`, { headers })
if (!meetings.ok) throw new Error(`${meetings.status} ${await meetings.text()}`)
console.log((await meetings.json()).data)
```

Susitikimo elementas turi `id` (`mtg_...`), `title`, `status`, `processing`, `transcript` ir `minutes`. Dalyvių sąrašą, įraše atpažintus dalyvius ir kiekius (pvz., segmentų skaičių) grąžina tik `GET /meetings/{meeting_id}`.

### Jei pirma užklausa nepavyksta

- **401** reiškia, kad pats raktas nepriimtas: `missing_api_key`, `invalid_api_key`, `api_key_expired`, `api_key_revoked` arba `api_key_disabled`. Patikrinkite, ar nustatytas `DIKO_API_KEY` ir ar raktas dar aktyvus.
- **403 `insufficient_scope`** reiškia, kad raktas galioja, bet neturi šiam endpointui reikalingo leidimo. Pavyzdžiui, raktas tik su `library:read` kviečia `GET /meetings`:

```http
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer realm="diko", error="insufficient_scope", scope="meetings:read"
```

```json
{
  "type": "error",
  "error": {
    "type": "permission_error",
    "code": "insufficient_scope",
    "message": "API raktas neturi šiam endpointui reikalingo leidimo.",
    "doc_url": "https://diko.app/api-docs/klaidos#insufficient_scope",
    "details": {
      "required_scopes": ["meetings:read"],
      "granted_scopes": ["library:read"]
    }
  },
  "request_id": "req_QBPIQ5QTIWAUYTMDNCLD7CMKBE"
}
```

`details.required_scopes` yra tai, ko reikia endpointui, o `details.granted_scopes` – ką turi jūsų raktas. Sukūrus raktą leidimų pakeisti negalima, todėl sukurkite naują raktą su reikiamu leidimu ([Leidimai](https://diko.app/api-docs/leidimai.md)). Kiti 403 kodai (`plan_required`, `ip_not_allowed` ir kiti) aprašyti [klaidų kataloge](https://diko.app/api-docs/klaidos.md).

> **Pastaba:**
> TypeScript pavyzdžiams reikia Node 20+ su ES moduliais (`.mjs` failai arba `"type": "module"`), nes jie naudoja aukščiausio lygio `await` ir `fetch`.

> **Patarimas:**
> Naudojate `httpx` vietoje `requests`? Pavyzdžiai veikia be pakeitimų: `httpx.get(...)` ir `httpx.post(...)` priima tuos pačius `headers`, `params`, `json` ir `timeout` argumentus.

## 3. Importuokite YouTube vaizdo įrašą

`POST /library/imports` reikalingas leidimas `library:write` (šablonas **Skaitymas ir importas** jį turi). Jis pradeda asinchroninį importą ir niekada nelaukia atsisiuntimo. Visada siųskite `Idempotency-Key`. Jei užklausa nutrūks, tą pačią užklausą su tuo pačiu raktu galėsite saugiai pakartoti. Importas nebus sukurtas du kartus.

**cURL**

```bash
curl -X POST "https://api.diko.app/api/v1/library/imports" \
  -H "Authorization: Bearer $DIKO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'
```

**Python**

```python
import uuid

# BASE ir HEADERS paimti iš 2 žingsnio. Vienas raktas vienam importui; kartodami užklausą naudokite tą patį.
idempotency_key = str(uuid.uuid4())

response = requests.post(
    f"{BASE}/library/imports",
    headers={**HEADERS, "Idempotency-Key": idempotency_key},
    json={"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"},
    timeout=30,
)
response.raise_for_status()
job = response.json()
print(job["id"], job["status"])
```

**TypeScript**

```typescript
// BASE ir headers paimti iš 2 žingsnio. Vienas raktas vienam importui; kartodami užklausą naudokite tą patį.
const idempotencyKey = crypto.randomUUID()

const response = await fetch(`${BASE}/library/imports`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": idempotencyKey },
  body: JSON.stringify({ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }),
})
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`)
let job = await response.json()
console.log(job.id, job.status)
```

Atsakymas yra `201 Created` su antrašte `Location`. Pirmą kartą importuojamas vaizdo įrašas pradeda nuo `queued`:

```json
{
  "id": "imp_6Mfj7Oxm4MfxGGmZRhiUQf",
  "object": "library_import",
  "status": "queued",
  "stage": null,
  "queue_position": 1,
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "youtube_video_id": "dQw4w9WgXcQ",
  "language": null,
  "reused": false,
  "transcript_id": null,
  "error": null,
  "created_at": "2026-10-11T09:30:00.000Z",
  "updated_at": "2026-10-11T09:30:00.100Z",
  "completed_at": null
}
```

Jei transkripcija jau yra jūsų bibliotekoje arba bendroje talpykloje, importas iškart tampa `succeeded` su `reused: true` ir **kreditai nenaudojami**.

## 4. Palaukite rezultato

Importo būseną galite periodiškai tikrinti arba gauti pranešimą per webhooks.

### Periodinis tikrinimas

`GET /library/imports/{import_id}`, kol importas nepasiekė galutinės būsenos, grąžina antraštę `Retry-After: 3`. Tikrinkite ne dažniau nei tai ir nustatykite bendrą laukimo laiką:

**cURL**

```bash
curl "https://api.diko.app/api/v1/library/imports/imp_6Mfj7Oxm4MfxGGmZRhiUQf" \
  -H "Authorization: Bearer $DIKO_API_KEY"
```

**Python**

```python
import time

deadline = time.monotonic() + 15 * 60
while job["status"] not in ("succeeded", "failed", "canceled"):
    if time.monotonic() > deadline:
        raise TimeoutError("Importas dar vyksta: naudokite webhooks arba patikrinkite vėliau")
    time.sleep(3)
    response = requests.get(f"{BASE}/library/imports/{job['id']}", headers=HEADERS, timeout=30)
    response.raise_for_status()
    job = response.json()

if job["status"] != "succeeded":
    raise RuntimeError(job["error"] or job["status"])
print(job["transcript_id"])
```

**TypeScript**

```typescript
const deadline = Date.now() + 15 * 60_000
while (!["succeeded", "failed", "canceled"].includes(job.status)) {
  if (Date.now() > deadline) throw new Error("Importas dar vyksta: naudokite webhooks arba patikrinkite vėliau")
  await new Promise(resolve => setTimeout(resolve, 3000))
  const poll = await fetch(`${BASE}/library/imports/${job.id}`, { headers })
  if (!poll.ok) throw new Error(`${poll.status} ${await poll.text()}`)
  job = await poll.json()
}
if (job.status !== "succeeded") throw new Error(JSON.stringify(job.error ?? job.status))
console.log(job.transcript_id)
```

Ilgi vaizdo įrašai gali užtrukti ilgiau, nei numatėte laukti. Tada nutraukite ciklą ir patikrinkite vėliau arba naudokite webhooks.

### Importo būsenos ir klaidos

Importas turi vieną iš šių `status` reikšmių. Galutinės yra `succeeded`, `failed` ir `canceled`.

| `status` | Reikšmė |
|---|---|
| `queued` | laukia eilėje; `queue_position` rodo jūsų vietą |
| `processing` | vykdomas; `stage` nurodo žingsnį |
| `canceling` | paprašėte atšaukti vykdomą importą; sustojus darbui jis tampa `canceled` |
| `succeeded` | baigtas; nustatytas `transcript_id` |
| `failed` | sustojo dėl klaidos; `error.code` nurodo priežastį |
| `canceled` | atšaukė jūs arba sistema. Sistema atšaukia importą, kai jo raktas atšauktas, išjungtas, ištrintas ar rotuotas be persidengimo, kai raktas atšaukiamas dėl nutekėjimo ir kai sustabdoma API prieiga. Importas eilėje iškart tampa `canceled`, vykdomas pereina per `canceling`. Jau atliktas darbas apmokestinamas kaip įprasta. Rotacija su persidengimu importo neatšaukia |

Kol importas `processing`, `stage` yra viena iš šių reikšmių: `captions` (Diko ieško YouTube subtitrų), `waiting` (laukia laisvos kalbos atpažinimo vietos), `downloading`, `transcribing` arba `summarizing`. Kitose būsenose `stage` yra `null`.

Nepavykusio (`failed`) importo `error.code` gali būti:

| `error.code` | Reikšmė |
|---|---|
| `video_unavailable`, `video_private`, `age_restricted` | vaizdo įrašo gauti neįmanoma; pakartojimas nepadės |
| `video_too_long` | vaizdo įrašas ilgesnis už kalbos atpažinimo ribą (šiuo metu 4 valandos) |
| `video_duration_unknown` | Diko nepavyko nustatyti vaizdo įrašo trukmės |
| `captions_unavailable` | nepavyko gauti subtitrų |
| `download_failed`, `transcription_failed` | nepavyko atsisiųsti arba transkribuoti; bandykite vėliau |
| `transcription_timeout` | importas `queued` būsenoje užsibuvo ilgiau nei 24 valandas arba `processing` ilgiau nei 6 valandas |
| `provider_limit` | pasiekta subtitrų tiekėjo riba; bandykite vėliau |
| `insufficient_credits` | importui užbaigti nepakako kreditų |
| `internal_error` | klaida Diko pusėje; bandykite vėliau |

Norėdami bandyti iš naujo, sukurkite naują importą su nauju `Idempotency-Key`.

**Kreditai.** Transkripcija, kuri jau yra jūsų bibliotekoje ar bendroje talpykloje, nekainuoja nieko (`reused: true`). Kitu atveju Diko tikrina kreditų likutį kuriant importą ir dar kartą prieš mokamą darbą. Likutį raktui su `library:write` rodo `GET /me`. Kreditų įkainiai ir planų apimtys pateikti [kainų puslapyje](https://diko.app/kainos).

### Webhooks

Sukurkite endpointą skiltyje **Nustatymai → API → Webhooks** ([`/settings/api/webhooks`](https://studio.diko.app/settings/api/webhooks)) ir pasirinkite įvykius `library.import.succeeded`, `library.import.failed` ir `library.import.canceled`. Diko atsiųs `POST` užklausą jūsų adresu, kai importas baigsis. Parašo tikrinimas ir pakartojimai aprašyti puslapyje [Įvykiai ir webhooks](https://diko.app/api-docs/webhooks.md).

## 5. Nuskaitykite transkripciją

Kai importas `succeeded`, `transcript_id` yra transkripcijos `trn_...` ID: ji jau jūsų bibliotekoje (matysite ją ir 2 žingsnio sąraše `GET /library/transcripts`). Nuskaitykite jos tekstą:

**cURL**

```bash
# Visas tekstas su laiko žymomis (naudokite importo transcript_id)
curl "https://api.diko.app/api/v1/library/transcripts/trn_ZFF3NHc5V2dYY1E/transcript?format=text" \
  -H "Authorization: Bearer $DIKO_API_KEY"
```

**Python**

```python
transcript_id = job["transcript_id"]

text = requests.get(
    f"{BASE}/library/transcripts/{transcript_id}/transcript",
    headers=HEADERS,
    params={"format": "text"},
    timeout=30,
)
text.raise_for_status()
print(text.text)
```

**TypeScript**

```typescript
const transcriptId = job.transcript_id

const text = await fetch(`${BASE}/library/transcripts/${transcriptId}/transcript?format=text`, { headers })
if (!text.ok) throw new Error(`${text.status} ${await text.text()}`)
console.log(await text.text())
```

Tekstas pateikiamas eilutėmis `[HH:MM:SS] Vardas: tekstas`. Norite segmentų JSON formatu, SRT ar VTT? Žr. [`getLibraryTranscriptTranscript`](https://diko.app/api-docs/zinynas/get-library-transcript-transcript.md).

## Patikrinkite, ką gali jūsų raktas (`GET /me`)

`GET /me` yra paskyros metaduomenys, o ne jūsų duomenys. Jis veikia su bet kuriuo galiojančiu raktu. Todėl greitai parodo, kurį raktą naudojate ir ar paskyra gali naudoti API. Raktui su leidimu `library:write` jis parodo ir kreditų likutį. Naudokite jį, kai kas nors neveikia kaip tikėtasi, o ne kaip pirmą užklausą.

**cURL**

```bash
curl "https://api.diko.app/api/v1/me" \
  -H "Authorization: Bearer $DIKO_API_KEY"
```

**Python**

```python
me = requests.get(f"{BASE}/me", headers=HEADERS, timeout=30)
me.raise_for_status()
print(me.json()["access"])
```

**TypeScript**

```typescript
const me = await fetch(`${BASE}/me`, { headers })
if (!me.ok) throw new Error(`${me.status} ${await me.text()}`)
console.log((await me.json()).access)
```

Sėkmingo atsakymo `access` dalis atrodo taip:

```json
{ "allowed": true, "reason": "subscription", "plan": "verslas" }
```

Jei `allowed` yra `false`, `reason` pasako kodėl (pavyzdžiui, `plan_required`). Klaidų kodų prasmė aprašyta [klaidų kataloge](https://diko.app/api-docs/klaidos.md).

`GET /me` laikosi mažiausių privilegijų principo, todėl siauro leidimo raktas neatskleidžia daugiau, nei reikia. `user.email` visada paslėptas, o `credits` užpildomas tik raktui su `library:write`, vieninteliu leidimu, kuris naudoja kreditus:

```json
{
  "user": { "id": "usr_4iAD1dYhdAEJIkMN5GPczR", "object": "user", "email": "j***@example.com", "display_name": "Jonas" },
  "credits": { "scope": "user", "available": "123.5000", "as_of": "2026-10-11T09:30:00.000Z" }
}
```

Tik skaitymo raktui (`meetings:read`, `library:read`) tame pačiame atsakyme bus `"credits": null`. `GET /me` turi savo, griežtesnę užklausų ribą ([Ribos](https://diko.app/api-docs/ribos.md)), todėl nekvieskite jo cikle.

## Kas toliau

- [Klaidos](https://diko.app/api-docs/klaidos.md): kaip elgtis su kiekvienu kodu ir kada kartoti užklausą.
- [Ribos](https://diko.app/api-docs/ribos.md): užklausų ir importų ribos.
- [Susitikimai](https://diko.app/api-docs/zinynas/list-meetings.md): su `meetings:read` nuskaitykite susitikimų transkripcijas, protokolus ir veiksmų punktus.
