---
title: "List transcriptions"
method: GET
path: "/v1/transcriptions"
tags: ["Transcriptions"]
---

# List transcriptions

`GET /v1/transcriptions`

## Request

- Base URL: `https://api.quillhub.ai`
- URL: `https://api.quillhub.ai/v1/transcriptions`
- Auth: HTTP bearer

Cursor-paginated list of transcriptions created by this API key's owner, newest first by default (`order=desc`); pass `order=asc` for oldest first. Pass `cursor` from the previous response's `next_cursor` to page through results — it continues in whichever direction `order` set. `next_cursor` is `null` on the final page. Use `view=summary` to get lightweight rows (~6 kB each) instead of the legacy bundled shape; use `q`, `created_before`, `created_after` to filter. Pass `workspace_id` to see a shared workspace's recordings instead of just your own — get `workspace_id` / `project_id` values from `GET /v1/workspaces`.

## Query parameters

- `limit` integer: Page size. 1–100, default 20. With the default `view=full` a page never holds more than 20 rows, whatever you ask for — each row bundles the whole transcript. Keep paging with `next_cursor`, or use `view=summary` for larger pages.
- `cursor` string: Opaque cursor returned as `next_cursor` by the previous page. Omit for the first page.
- `status` 'queued' | 'processing' | 'completed' | 'failed' | 'cancelled': Return only transcriptions in this status.
- `view` 'full' | 'summary': `full` (default) keeps the legacy bundled rows. `summary` returns ~6 kB rows with title, summary, key_theses, highlights — what an agent needs to find a specific transcription.
- `order` 'asc' | 'desc': `desc` (default) — newest first, matching legacy behavior. `asc` — oldest first (chronological). `cursor` pages in the same direction as `order`.
- `q` string: Case-insensitive substring search. Covers title, summary, key_theses and topics by default — narrow it with `q_fields`. Cap 200 chars.
- `q_fields` 'all' | 'title': Which fields `q` searches. `all` (default) also scans the summary, key theses and topics stored inside the structured result — thorough, but it reads every candidate recording in full and slows down as a workspace grows. `title` searches titles only and stays in single-digit milliseconds; prefer it when picking a known recording by name.
- `created_before` string, date-time: ISO 8601 timestamp; exclusive upper bound on created_at.
- `created_after` string, date-time: ISO 8601 timestamp; inclusive lower bound on created_at.
- `workspace_id` integer: Restrict to this workspace. Includes teammates' recordings that are shared with the workspace (visibility='visible'); your own and — for owners/admins — all workspace recordings. 403 if you are not a member. Omit to see every transcription the caller authored across all workspaces (default behaviour). Get `workspace_id` / `project_id` values from `GET /v1/workspaces`.
- `project_id` integer, nullable: Restrict to this project. Pass 0 for the Inbox (workspace recordings without a project). Requires workspace_id.
- `needs_project` 'true' | 'false': Pass `true` to list only the recordings the AI listened to and could not file under any project (`ai_layer_status='awaiting_project'`) — the ones waiting on a human decision. Deliberately narrower than `project_id=0`: that returns every projectless recording, which also covers Telegram-bot recordings (never routed at all), recordings the AI deliberately skipped, and recordings whose analysis is still running. Requires workspace_id.
- `unassigned` 'true': Pass `true` to list desktop-recorded meetings (`source='desktop'`, excluding dictation) in the workspace without a project — EXCEPT the ones a human explicitly kept without one (`POST /v1/ai/recordings/:id/keep-unassigned`, `ai_layer_status='kept'`) and the ones whose AI analysis hasn't finished yet (`pending`/`extracting`). Telegram-bot, web, and API recordings are never included — routing never runs for them, and they stay plain transcripts the user can file by hand. Same predicate as `GET /v1/workspaces/:wsId/unassigned-count` — see `apps/api/src/lib/unassigned-filter.ts`. Requires workspace_id.

## Response `200`

Cursor-paginated page of transcriptions.

- union
  - TranscriptionList
    - `data` Transcription[], required: Page of transcriptions, newest first.
      - `id` string, required: Stable identifier with `trs_` prefix.
      - `internal_id` integer, required: Numeric `request.id` used by first-party web/desktop URLs (e.g. https://quillhub.ai/{locale}/transcript/{internal_id}). Public API consumers should keep using `id`; this field exists so first-party clients can deep-link to the existing web transcript page without an extra round-trip.
      - `kind` 'meeting' | 'dictation', nullable: Categorisation of the request: 'dictation' for short voice notes captured via the desktop widget, 'meeting' for recorded calls/uploads. Null on legacy rows; clients should treat null as 'meeting'.
      - `title` string, nullable: Human-readable title. Generated by the structurer once the transcript is ready (e.g. "Митинг с командой о Q3"); falls back to the original filename for sources that don't go through structuring.
      - `status` 'queued' | 'processing' | 'completed' | 'failed' | 'cancelled', required: Lifecycle stage. `queued` → `processing` → one of `completed` / `failed` / `cancelled` (terminal).
      - `stage` 'queued' | 'downloading' | 'transcribing' | 'structuring' | 'completed' | 'failed' | 'insufficient_funds' | 'cancelled', required: Precise processing stage. `status` keeps its existing, back-compatible meaning; `stage` refines it — notably separating `insufficient_funds` from a generic failure, and the download / transcribe / structure phases from a generic `processing`.
      - `progress` number, nullable: Fraction between 0 and 1 while `processing`. `null` otherwise.
      - `source` object, required: What was submitted.
        - `type` 'youtube' | 'instagram' | 'direct' | 'upload', required: Detected source category. `youtube` / `instagram` for those platforms, `direct` for any other reachable URL, `upload` when the client sent an inline base64 file.
        - `url` string, nullable: Normalized source URL. `null` for inline uploads unless `include_source_url: true`.
        - `channel` string, nullable: Which surface created the recording: `web`, `api`, `desktop`, `bot`, `tg_webapp`. `null` for rows created before the column existed (those are web uploads). Deliberately a free-form string, not an enum: the column carries no CHECK constraint, and a new surface must not break response validation for existing clients.
      - `options` object, required: Echoes the create-request options so clients can branch on effective config.
        - `language` string, nullable: Language forced by the caller. `null` if auto-detect was used.
        - `speaker_recognition` boolean, required
        - `structure` boolean, required
      - `duration_seconds` number, nullable: Source duration, detected after download/probe.
      - `language` string, nullable: Detected or forced ISO-639-1 language code. `null` until probed.
      - `share_enabled` boolean, required: Whether the public share link is active.
      - `share_enabled_at` string, date-time, nullable, required: ISO 8601 timestamp when sharing was enabled. `null` if never enabled.
      - `share_url` string, uri, nullable, required: Public share URL. `null` when `share_enabled` is false.
      - `points_spent` number, nullable: Points charged on completion. `null` until the job is terminal.
      - `result` TranscriptionResult, nullable: Populated when `status` is `completed`. `null` for `queued` / `processing` / `failed` / `cancelled`.
        - `text` string, nullable: Full transcript as a single plain-text string.
        - `segments` Segment[]: Phrase-level chunks with timestamps and optional speaker labels.
          - `start` number, required: Seconds from the beginning of the source audio.
          - `end` number, required: Seconds from the beginning of the source audio.
          - `text` string, required
          - `speaker` string, nullable: Generic speaker label (`Speaker 1`, `Speaker 2`, …). Present only when the request set `speaker_recognition: true`.
        - `structured` object, nullable: Title, summary, TOC, paragraphs, highlights, and terms. Populated when `structure: true`.
          - `title` string, nullable: Suggested title inferred by the structurer.
          - `summary` string, nullable: Short summary of the content.
          - `language` string, nullable: Detected language code, echoed from the structurer.
          - `toc` object[]: Table of contents — array of entries with a `title` and a `start_paragraph_number` anchor (plus any auxiliary fields the structurer emits).
          - `chapters` object[]: Chapter-level segmentation with `title`, `start_time`, `end_time`, and the paragraphs that belong to each chapter.
          - `paragraphs` object[]: Paragraph-level readable view with `start_time`, `paragraph_text`, and the index matching back to `result.segments`.
          - `highlights` string[]: Key quotes pulled from the transcript.
          - `key_theses` string[]: Main thesis statements — slightly longer than highlights.
          - `terms` string[]: Glossary of proper nouns, product names, and domain terms the model extracted.
          - `action_items` union[]: Tasks found in the recording, exactly as the structurer emitted them: either a bare string, or an object with `text` plus an optional assignee and deadline. Use `format=summary` for the normalized `ActionItem` shape.
            - union
              - …
          - `decisions` string[]: Decisions reached during the recording.
          - `topics` string[]: Topics covered in the recording.
        - `subtitles` object: Ready-to-use VTT and SRT caption strings.
          - `vtt` string, nullable: Presigned URL to the WebVTT file. Suitable to pass directly into a `<track>` element or a player. Expires after the storage TTL.
          - `srt` string, nullable: Presigned URL to the SRT file. Expires after the storage TTL.
      - `source_url` string, nullable: Short-lived presigned URL to the stored source file. Only present for inline uploads when `include_source_url: true` was set on create.
      - `webhook_url` string, nullable: Callback URL recorded on create. We POST the finished Transcription object here.
      - `error` string, nullable: Human-readable failure reason. Present only when `status` is `failed`. Machine-readable classification lives in `error_code`, never inside this text.
      - `error_code` string, nullable: Stable machine-readable failure code (e.g. `GOT_ARCHIVE`, `CONTENT_PRIVATE`, `NO_SPEECH`). `null` when the failure wasn't classified. Branch on this instead of matching `error` text.
      - `metadata` object, nullable: Arbitrary string→string map passed on create, echoed back unchanged.
      - `workspace_id` integer, nullable: Workspace the transcription belongs to. `null` on legacy rows created before workspaces.
      - `project_id` integer, nullable: Project inside the workspace. `null` means the transcription sits in the workspace Inbox (no project).
      - `created_at` string, required: ISO 8601 timestamp.
      - `completed_at` string, nullable: ISO 8601 timestamp of the terminal transition. `null` otherwise.
    - `next_cursor` string, nullable, required: Pass this as `cursor` on the next request to fetch the following page. `null` on the final page.
  - TranscriptionSummaryList
    - `data` TranscriptionSummary[], required
      - `id` string, required
      - `status` 'queued' | 'processing' | 'completed' | 'failed' | 'cancelled', required: Lifecycle stage. `queued` → `processing` → one of `completed` / `failed` / `cancelled` (terminal).
      - `language` string, nullable, required
      - `duration_seconds` number, nullable, required
      - `created_at` string, required
      - `completed_at` string, nullable, required
      - `internal_id` integer, required: Numeric `request.id` — the same value the full row exposes. Web and desktop URLs are built from it, so clients that need it can stay on the lightweight `view=summary` shape.
      - `stage` 'queued' | 'downloading' | 'transcribing' | 'structuring' | 'completed' | 'failed' | 'insufficient_funds' | 'cancelled': Precise processing stage — see the `full` shape's `stage` for the full description. Notably distinguishes `insufficient_funds` (DB `LOW_BALANCE`) from a generic `failed`.
      - `progress` number, nullable: Fraction between 0 and 1 while `processing`. `null` otherwise.
      - `error` string, nullable: Human-readable failure reason. Present only when `status` is `failed`. Machine-readable classification lives in `error_code`, never inside this text.
      - `error_code` string, nullable: Stable machine-readable failure code (e.g. `GOT_ARCHIVE`, `CONTENT_PRIVATE`, `NO_SPEECH`). `null` when the failure wasn't classified. Branch on this instead of matching `error` text.
      - `title` string, nullable, required
      - `summary` string, nullable, required
      - `key_theses` string[], required
      - `highlights` string[], required
      - `action_items` ActionItem[], required
        - `text` string, required
        - `who` string: Assignee, only when explicitly named in the recording.
        - `due` string: Deadline as spoken (free-form), only when explicitly mentioned.
      - `decisions` string[], required
      - `topics` string[], required
      - `terms` string[], required
      - `participants` string[], required: Resolved speaker names (from voice identification / manual naming). Empty when nobody has been named.
      - `project` object, nullable, required
        - `id` integer, required
        - `name` string, required
      - `workspace` object, nullable, required
        - `id` integer, required
        - `name` string, required
      - `author` object, required
        - `tg_id` number, required
        - `is_me` boolean, required: True when the caller authored this transcription.
      - `kind` string, nullable, required
      - `workspace_id` integer, nullable, required
      - `project_id` integer, nullable, required
      - `author_tg_id` number, required
      - `share_enabled` boolean, required
      - `share_enabled_at` string, date-time, nullable, required
      - `share_url` string, uri, nullable, required
      - `source` object, required
        - `type` string, required
        - `url` string, nullable, required
        - `channel` string, nullable: Which surface created the recording: `web`, `api`, `desktop`, `bot`, `tg_webapp`. `null` for rows created before the column existed.
      - `available_formats` string[], required
    - `next_cursor` string, nullable, required

## Other responses

- `401`: Missing or invalid Bearer token.

---

[API](https://skmtc.dev/quillhub/apis/quillhub-public-api.md) · [All operations](https://skmtc.dev/quillhub/apis/quillhub-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/quillhub/apis/quillhub-public-api/revisions/5bd42ee9d967?raw)
