openapi: 3.1.0
info:
  title: Tiro API
  description: AI-powered note-taking and voice file processing API
  version: 1.0.0
  contact:
    name: Tiro Support
    email: support@tiro.ooo
    url: https://tiro.ooo
servers:
  - url: https://api.tiro.ooo
    description: Production server
security:
  - BearerAuth: []
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: API key in format {id}.{secret}
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - errorType
            - message
          properties:
            code:
              type: integer
              description: >
                6-digit error code in `AAABBB` form: first 3 digits match the
                HTTP status,

                last 3 digits are a per-status serial (e.g. `404018`). Use only
                when you need

                to distinguish specific error cases within the same HTTP status
                — values may be

                added or renumbered across releases. For general client
                branching, prefer `errorType`.
              example: 404018
            errorType:
              type: string
              description: >
                Stable, coarse-grained error category. Recommended default for
                client-side

                branching: the value-to-status mapping is part of the API
                contract and will not

                change without a breaking-change notice. Typical use:
                  - `unauthorized` → trigger re-authentication
                  - `forbidden` → surface a permission error to the user
                  - `not_found` → treat as missing resource
                  - `too_many_requests` → back off and retry
                  - `internal_error` → retry with exponential backoff
              enum:
                - bad_request
                - unauthorized
                - forbidden
                - not_found
                - not_acceptable
                - conflict
                - payload_too_large
                - unprocessable_entity
                - too_many_requests
                - internal_error
              example: not_found
            message:
              type: string
              description: >-
                Human-readable error message. Not stable; do not use for
                branching.
              example: 'No team found for user #217'
            detail:
              type: string
              nullable: true
              description: Additional error details
              example: null
    PageCursorResponse:
      type: object
      required:
        - content
        - nextCursor
      properties:
        content:
          type: array
          items: {}
          description: Array of items for current page
        nextCursor:
          type: string
          nullable: true
          description: Cursor for next page, null if last page
          example: opaque-cursor-string
    SimpleListResponse:
      type: object
      required:
        - content
      properties:
        content:
          type: array
          items: {}
          description: Array of items
    TextObject:
      type: object
      required:
        - type
        - content
      properties:
        type:
          type: string
          enum:
            - text/plain
            - text/markdown
          description: MIME type of the text content
          example: text/plain
        content:
          type: string
          description: The actual text content
          example: Hello everyone, welcome to today's meeting...
    Collaborator:
      type: object
      required:
        - guid
        - name
        - email
        - role
      properties:
        guid:
          type: string
          description: Unique identifier for the collaborator
          example: user-guid-123
        name:
          type: string
          description: Collaborator's name
          example: John Doe
        email:
          type: string
          format: email
          description: Collaborator's email address
          example: john@example.com
        role:
          type: string
          enum:
            - OWNER
            - EDITOR
            - VIEWER
          description: Collaborator's role
          example: OWNER
    Participant:
      type: object
      properties:
        name:
          type: string
          nullable: true
          description: Participant's name. Null when the name was not provided or is blank.
          example: Alice Kim
        email:
          type: string
          format: email
          nullable: true
          description: >-
            Participant's email address. Null when the email was not provided or
            is blank.
          example: alice@example.com
    Folder:
      type: object
      required:
        - id
        - title
        - isTeamFolder
      properties:
        id:
          type: string
          description: Unique identifier for the folder
          example: '12345'
        title:
          type: string
          description: Folder title
          example: Weekly Team Meetings
        workspaceGuid:
          type: string
          nullable: true
          description: |
            GUID of the workspace the folder belongs to. `null` for legacy
            personal folders that have not been migrated to a workspace.
          example: ws_a1b2c3d4
        isTeamFolder:
          type: boolean
          description: |
            `true` when the folder is shared with the workspace; `false` for
            personal (`PRIVATE`) folders. Retained for backward compatibility.
          example: true
    FolderTreeNode:
      type: object
      required:
        - id
        - title
        - depth
        - isAccessible
        - children
      properties:
        id:
          type: string
          description: Unique identifier for the folder
          example: '12345'
        title:
          type: string
          description: Folder title
          example: Weekly Team Meetings
        parentId:
          type: string
          nullable: true
          description: >
            Parent folder ID. `null` for root-level folders, or when the parent

            folder is not accessible to you — the folder then appears at the
            root

            level of the tree.
          example: '12300'
        depth:
          type: integer
          description: Depth of the node in the returned tree (0 for root-level nodes)
          example: 0
        isAccessible:
          type: boolean
          description: >
            Whether you can access this folder's contents. The tree contains
            only

            folders you can access, so this is currently always `true`.
          example: true
        children:
          type: array
          description: Child folders, nested recursively.
          items:
            $ref: '#/components/schemas/FolderTreeNode'
    FolderPathNode:
      type: object
      description: One folder in a breadcrumb path.
      required:
        - id
        - title
        - isAccessible
      properties:
        id:
          type: string
          description: Unique identifier for the folder
          example: '12300'
        title:
          type: string
          description: Folder title
          example: Team Root
        isAccessible:
          type: boolean
          description: Whether you can access this folder's contents.
          example: true
    Note:
      type: object
      description: >
        The top-level container for a single recording session. A Note holds its

        transcribed content as Paragraphs, and can be summarized into
        NoteSummary

        or rendered into a NoteDocument. See [Data
        Model](/fundamentals/note-data-model)

        for the full structure.
      required:
        - guid
        - title
        - createdAt
        - updatedAt
        - sourceType
        - recordingDurationSeconds
        - collaborators
        - participants
        - webUrl
      properties:
        guid:
          type: string
          description: Unique identifier for the note
          example: note-guid-123
        workspaceGuid:
          type: string
          nullable: true
          description: >
            GUID of the workspace this note belongs to. `null` for notes not
            associated with a workspace.
          example: ws_a1b2c3d4
        title:
          type: string
          description: Note title
          example: Meeting notes
        createdAt:
          type: string
          format: date-time
          description: ISO-8601 creation timestamp
          example: '2025-07-20T10:00:00Z'
        updatedAt:
          type: string
          format: date-time
          description: ISO-8601 last update timestamp
          example: '2025-07-20T11:10:00Z'
        sourceType:
          type: string
          enum:
            - onboarding
            - text
            - live-voice
            - recording
            - offline-mode
            - webpage
            - video
          description: |
            Source type of the note:
            - `live-voice`: Real-time voice recording
            - `recording`: Uploaded audio file
            - `text`: Text-only note
            - `video`: Video recording
            - `webpage`: Web page content
            - `offline-mode`: Offline recording
            - `onboarding`: Onboarding sample note
          example: live-voice
        recordingStartAt:
          type: string
          format: date-time
          nullable: true
          description: >
            Actual recording start timestamp. Null for non-recording source
            types.
          example: '2025-07-20T10:00:10Z'
        recordingEndAt:
          type: string
          format: date-time
          nullable: true
          description: |
            Actual recording end timestamp. Null for non-recording source types.
          example: '2025-07-20T11:00:10Z'
        recordingDurationSeconds:
          type: integer
          description: >
            Actual recording length in seconds. Returns `0` for non-recording
            source types.
          example: 3600
        transcribeLocale:
          type: string
          nullable: true
          description: >
            Language locale used for transcription. Null for non-recording
            source types.
          example: en_US
        translateLocale:
          type: string
          nullable: true
          description: >
            Language locale used for translation. Null when no translation was
            requested.
          example: ko_KR
        webUrl:
          type: string
          format: uri
          description: Web URL to access the note
          example: https://tiro.ooo/n/123
        collaborators:
          type: array
          items:
            $ref: '#/components/schemas/Collaborator'
          description: Array of collaborators with their roles
        participants:
          type: array
          items:
            $ref: '#/components/schemas/Participant'
          description: Array of meeting participants tagged in the note
        matchedSnippets:
          type: array
          items:
            type: string
          nullable: true
          description: |
            Highlight snippets for the keyword that matched this
            note. Present only on responses to the deep-search endpoints
            (`POST /v1/external/workspaces/{workspaceGuid}/notes/search` or the
            deprecated `POST /v1/external/notes/search`); absent (`null`) on
            plain list responses.
        documents:
          type: array
          items:
            $ref: '#/components/schemas/NoteDocument'
          nullable: true
          description: |
            Note's primary documents (one-pager / custom). Present only on
            responses to the deep-search endpoints
            (`POST /v1/external/workspaces/{workspaceGuid}/notes/search` or the
            deprecated `POST /v1/external/notes/search`); absent (`null`) on
            plain list responses. Each item's `truncated` flag indicates
            whether the deep-search budget was exceeded.
    NoteSearchRequest:
      type: object
      required:
        - keyword
      properties:
        keyword:
          type: string
          minLength: 1
          description: >-
            Search keyword. Full-text matched against note title and paragraph
            content.
          example: OKR
        filter:
          $ref: '#/components/schemas/NoteSearchFilter'
        pagination:
          $ref: '#/components/schemas/NoteSearchPagination'
    NoteSearchFilter:
      type: object
      properties:
        folderId:
          type: string
          nullable: true
          description: |
            Restrict hits to notes inside the folder (and its descendants).
            For a team API key the folder must belong to the team.
        createdAtFrom:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 datetime, inclusive lower bound on `createdAt`.
        createdAtTo:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 datetime, exclusive upper bound on `createdAt`.
    NoteSearchPagination:
      type: object
      properties:
        cursor:
          type: string
          nullable: true
          description: >-
            Reserved for future use; the deep-search endpoint currently emits
            `nextCursor: null`.
        size:
          type: integer
          default: 10
          minimum: 1
          maximum: 30
          description: |
            Number of notes to return (1–30). Smaller than the list endpoint
            because results include document content. Defaults to 10 when `size`
            is omitted but a `pagination` object is present; omitting the
            `pagination` object entirely returns up to 50.
    NoteSearchResponse:
      type: object
      required:
        - notes
      properties:
        notes:
          type: array
          items:
            $ref: '#/components/schemas/Note'
          description: >-
            Matched notes, ordered by full-text relevance with `createdAt` desc
            as tiebreaker.
        nextCursor:
          type: string
          nullable: true
        degraded:
          type: boolean
          default: false
          description: |
            `true` when the response was produced via a fallback path (e.g.,
            search index unavailable). When degraded, `notes` may be empty and
            quality is reduced.
        degradedReason:
          type: string
          nullable: true
          enum:
            - search_index_unavailable
            - search_index_degraded
            - null
          description: |
            Machine-readable reason when `degraded=true`. `null` otherwise.
    NoteReservationRequest:
      type: object
      properties:
        title:
          type: string
          description: If provided, sets the title for the note to be created.
          example: Weekly Team Standup
          maxLength: 100
    NoteReservationResponse:
      type: object
      required:
        - guid
        - expiresAt
        - createdAt
      properties:
        guid:
          type: string
          description: Reserved note GUID that can be used for note creation
          example: x6DjzdpXqkEcU
        title:
          type: string
          nullable: true
          description: Title of the note if provided during reservation
          example: Weekly Team Standup
        expiresAt:
          type: string
          format: date-time
          description: >-
            ISO-8601 timestamp when the reservation expires (1 hour from
            creation)
          example: '2024-01-15T11:30:00Z'
        createdAt:
          type: string
          format: date-time
          description: ISO-8601 timestamp when the reservation was created
          example: '2024-01-15T10:30:00Z'
    ShareLinkRequest:
      type: object
      properties:
        usePassword:
          type: boolean
          nullable: true
          description: |
            Controls the share link password.
            - `true` — Generate password (regenerate if one exists)
            - `false` — Remove password (or create without one)
            - `null` / omitted — Keep current password state
    ShareLinkResponse:
      type: object
      required:
        - shareId
        - shareUrl
        - hasPassword
      properties:
        shareId:
          type: string
          description: Unique share link identifier
          example: LHr1bHvCCdVCG
        shareUrl:
          type: string
          format: uri
          description: Full URL for accessing the shared note
          example: https://tiro.ooo/s/LHr1bHvCCdVCG
        sharePassword:
          type: string
          nullable: true
          description: |
            Share link password.
            - Only returned on PUT with `usePassword: true`
            - Always `null` in GET responses
          example: a1b2c3d4
        hasPassword:
          type: boolean
          description: Whether the share link has a password
          example: true
    DiarizedSegment:
      type: object
      description: A speaker-attributed slice of a paragraph.
      required:
        - content
        - speaker
      properties:
        content:
          type: string
          description: Plain-text content of the segment, attributed to one speaker.
          example: 안녕하세요, 회의 시작하겠습니다.
        speaker:
          $ref: '#/components/schemas/SpeakerInfo'
    SpeakerInfo:
      type: object
      description: Identifies the speaker of a diarized segment.
      required:
        - label
      properties:
        label:
          type: string
          description: >
            Diarization-engine label for the speaker (stable within a single
            note, e.g. `SPEAKER_0`).
          example: SPEAKER_0
        personName:
          type: string
          nullable: true
          description: >
            Resolved person name when the user has mapped this label to a
            person. Null when the speaker is unmapped.
          example: Alice Kim
    Paragraph:
      type: object
      description: >
        A semantic unit of a Note's transcript (a speaker turn or topic chunk,
        not

        a prose paragraph). Generated asynchronously as transcription progresses
        —

        fields like `transcript`, `translated`, and `summary` become non-null in

        stages. See [Data Model](/fundamentals/note-data-model).
      required:
        - uuid
        - locked
      properties:
        uuid:
          type: string
          description: Unique identifier for the paragraph
          example: para-1
        transcribeLocale:
          type: string
          nullable: true
          description: >
            Locale used for transcription. Null for paragraphs from
            non-recording source notes.
          example: en_US
        transcript:
          nullable: true
          description: >
            Transcribed text content. Null when transcription has not yet
            completed or is unavailable.
          allOf:
            - $ref: '#/components/schemas/TextObject'
            - example:
                type: text/plain
                content: Hello everyone...
        translateLocale:
          type: string
          nullable: true
          description: |
            Locale used for translation. Null when no translation was requested.
          example: ko_KR
        translated:
          nullable: true
          description: >
            Translated text content. Null when no translation was requested or
            translation has not yet completed.
          allOf:
            - $ref: '#/components/schemas/TextObject'
            - example:
                type: text/plain
                content: 여러분 안녕하세요...
        summaryLocale:
          type: string
          nullable: true
          description: >
            Locale used for summary. Resolved from summaryLocale, then
            translateLocale, then transcribeLocale. Null only when all three
            locale fields are null.
          example: en_US
        summary:
          nullable: true
          description: >
            AI-generated paragraph summary. Null when summary generation has not
            yet completed.
          allOf:
            - $ref: '#/components/schemas/TextObject'
            - example:
                type: text/markdown
                content: '- Greeting and agenda...'
        diarizedSegments:
          type: array
          nullable: true
          description: >
            Speaker-attributed segments. Backend applies userDiarizedTranscript
            →

            diarizedTranscript precedence and resolves user-mapped person names.

            Null when the paragraph has no diarization data — callers should
            fall

            back to `transcript`.
          items:
            $ref: '#/components/schemas/DiarizedSegment'
        timeFrom:
          type: string
          format: date-time
          nullable: true
          description: >
            Start time of the paragraph. Null when timing information is not
            available.
          example: '2025-07-20T10:00:10Z'
        timeTo:
          type: string
          format: date-time
          nullable: true
          description: >
            End time of the paragraph. Null when timing information is not
            available.
          example: '2025-07-20T10:00:25Z'
        locked:
          type: boolean
          description: >
            Whether the paragraph is behind the paywall. `true` means the
            paragraph is past the note's free usage limit on a free or unpaid
            plan, and its text content (`transcript`, `translated`, `summary`)
            is returned masked — length and structure are preserved but the
            words are replaced with placeholder characters. Starting a paid plan
            unlocks the note and returns these paragraphs in full.
          example: false
    ParagraphSummary:
      type: object
      required:
        - jobId
        - locale
        - summary
      properties:
        jobId:
          type: string
          description: Voice file job identifier
          example: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
        locale:
          type: string
          description: Locale of the summary
          example: ko_KR
        summary:
          $ref: '#/components/schemas/TextObject'
          description: Paragraph summary as a TextObject
    VoiceFileJob:
      type: object
      description: >
        Represents a voice file processing job. Voice File Jobs handle the
        complete pipeline of

        audio transcription and optional translation.


        **Processing Pipeline:**

        1. Job created (`CREATED`) → Upload URI provided

        2. File uploaded (`UPLOADED`) → Ready for processing

        3. Processing started (`PROCESSING`) → STT and translation in progress

        4. Processing complete (`COMPLETED`) → Results available


        **Processing Time Estimates:**

        | File Duration | Typical Time |

        |---------------|--------------|

        | < 5 minutes | 45-75 seconds |

        | 5-20 minutes | 1-3 minutes |

        | 20-60 minutes | 3-6 minutes |

        | 1-4 hours | 6-18 minutes |
      required:
        - id
        - status
      properties:
        id:
          type: string
          description: Unique job identifier (UUID format)
          example: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
        status:
          type: string
          enum:
            - CREATED
            - UPLOADED
            - PROCESSING
            - COMPLETED
            - FAILED
          description: |
            Current job processing status:
            - `CREATED`: Job created, waiting for file upload
            - `UPLOADED`: File uploaded, waiting for processing to start
            - `PROCESSING`: Transcription/translation in progress
            - `COMPLETED`: All processing finished, results available
            - `FAILED`: Processing failed (check errorMessage)
          example: PROCESSING
        fileUploadedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when file upload was completed. Null if not yet uploaded.
          example: '2025-07-20T10:00:20Z'
        processStartedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when processing started. Null if not yet started.
          example: '2025-07-20T10:01:00Z'
        processCompletedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when processing completed. Null if still processing.
          example: null
        errorMessage:
          type: string
          nullable: true
          description: Error message if job failed. Null for successful jobs.
          example: null
    VoiceFileJobCreated:
      type: object
      description: >
        Response returned when a new Voice File Job is created.

        Contains the job ID and a presigned URL for uploading the audio file.


        **Next Steps:**

        1. Upload your audio file to `uploadUri` using HTTP PUT

        2. Call `PUT /v1/external/voice-file/jobs/{id}/upload-complete` to start
        processing
      required:
        - id
        - uploadUri
      properties:
        id:
          type: string
          description: >-
            Unique job identifier (UUID format). Use this ID in subsequent API
            calls.
          example: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
        uploadUri:
          type: string
          format: uri
          description: |
            Presigned URL for uploading the audio file.
            - Use HTTP PUT method to upload
            - URL expires in 1 hour
            - Set appropriate Content-Type header (e.g., audio/mpeg, audio/wav)
          example: >-
            https://tiro-uploads.s3.amazonaws.com/voice-files/job-abc123?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
    TranscriptSegment:
      type: object
      required:
        - startTimeMillis
        - endTimeMillis
        - text
      properties:
        startTimeMillis:
          type: integer
          format: int64
          description: >-
            Segment start offset from the beginning of the audio, in
            milliseconds
          example: 1200
        endTimeMillis:
          type: integer
          format: int64
          description: Segment end offset from the beginning of the audio, in milliseconds
          example: 3480
        text:
          type: string
          description: Transcribed text for this segment
          example: Hello everyone.
        speakerLabel:
          type: string
          nullable: true
          description: >-
            Opaque speaker label that is meaningful only within this job. Null
            when diarization does not assign a speaker.
          example: speaker-1
    Transcript:
      type: object
      required:
        - jobId
        - locales
        - text
      properties:
        jobId:
          type: string
          description: Associated job identifier
          example: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
        locales:
          type: array
          items:
            type: string
          description: Locales used for transcription
          example:
            - en_US
        text:
          type: string
          description: Transcribed text
          example: Hello everyone ...
        segments:
          type: array
          description: >-
            Optional sentence-level timestamps and speaker labels. Empty when no
            segment data is available.
          items:
            $ref: '#/components/schemas/TranscriptSegment'
    Translation:
      type: object
      required:
        - jobId
        - locale
        - text
      properties:
        jobId:
          type: string
          description: Associated job identifier
          example: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
        locale:
          type: string
          description: Translation locale
          example: ko_KR
        text:
          type: string
          description: Translated text
          example: 안녕하세요 여러분 ...
    SupportedLocale:
      type: string
      enum:
        - ko_KR
        - en_US
        - de_DE
        - ja_JP
        - es_ES
        - fr_FR
        - id_ID
        - vi_VN
        - tr_TR
        - uk_UA
        - ru_RU
        - hi_IN
        - it_IT
        - zh_CN
        - ms_MY
        - th_TH
        - sv_SE
      description: Supported language locale
      example: ko_KR
    NoteDocumentTemplateSummary:
      type: object
      description: Summary information of a note document template
      required:
        - id
        - title
      properties:
        id:
          type: integer
          format: int64
          description: Template ID
          example: 1
        title:
          type: string
          description: Template title
          example: 영업 보고서
    GenerateNoteDocumentRequest:
      type: object
      required:
        - templateId
        - locale
      properties:
        templateId:
          type: integer
          format: int64
          description: Template ID
          example: 1
        locale:
          allOf:
            - $ref: '#/components/schemas/SupportedLocale'
            - description: Language locale for document generation (AUTO is not supported)
    NoteDocument:
      type: object
      description: >
        A structured multi-section document (e.g., meeting minutes, action
        items)

        generated from a NoteDocumentTemplate. Unlike NoteSummary, it is divided

        into predefined sections. See [Data
        Model](/fundamentals/note-data-model).
      required:
        - id
        - noteGuid
        - note
        - template
        - locale
        - sections
        - createdAt
        - updatedAt
      properties:
        id:
          type: integer
          format: int64
          description: Document ID
          example: 456
        noteGuid:
          type: string
          description: The GUID of the note this document belongs to
          example: note-abc123-def456
        note:
          $ref: '#/components/schemas/NoteRef'
        template:
          $ref: '#/components/schemas/NoteDocumentTemplateSummary'
        locale:
          $ref: '#/components/schemas/SupportedLocale'
        sections:
          type: array
          description: Array of document sections
          items:
            $ref: '#/components/schemas/NoteDocumentSection'
        createdAt:
          type: string
          format: date-time
          description: Document creation timestamp
          example: '2025-10-20T12:35:26Z'
        updatedAt:
          type: string
          format: date-time
          description: Document last update timestamp
          example: '2025-10-20T13:45:30Z'
        truncated:
          type: boolean
          default: false
          description: |
            `true` when the document was emitted as part of a deep-search
            response and its combined section text exceeded the search budget
            (5,000 chars). Plain document fetches always emit `false`.
    NoteDocumentSection:
      type: object
      description: A section within a note document
      required:
        - content
        - createdAt
      properties:
        content:
          allOf:
            - $ref: '#/components/schemas/TextObject'
            - description: Generated section content
        createdAt:
          type: string
          format: date-time
          description: Section creation timestamp
          example: '2025-10-20T12:35:26Z'
    NoteDocumentListItem:
      type: object
      description: Summary information for document list
      required:
        - id
        - template
        - locale
        - createdAt
        - updatedAt
      properties:
        id:
          type: integer
          format: int64
          description: Document ID
          example: 456
        template:
          $ref: '#/components/schemas/NoteDocumentTemplateSummary'
        locale:
          $ref: '#/components/schemas/SupportedLocale'
        createdAt:
          type: string
          format: date-time
          description: Document creation timestamp
          example: '2025-10-20T12:35:26Z'
        updatedAt:
          type: string
          format: date-time
          description: Document last update timestamp
          example: '2025-10-20T13:45:30Z'
    NoteDocumentListResponse:
      type: object
      description: Response containing list of note documents
      required:
        - content
      properties:
        content:
          type: array
          description: Array of document summaries
          items:
            $ref: '#/components/schemas/NoteDocumentListItem'
        totalSize:
          type: integer
          description: Total number of documents
          example: 5
    NoteDocumentTemplateSectionType:
      type: string
      description: Type of document template section
      enum:
        - PLAIN_TEXT
        - ACTION_ITEMS
        - INFORMATIONAL_QNA
        - EXAMPLE
      example: PLAIN_TEXT
    NoteDocumentTemplateSection:
      type: object
      description: Section within a document template
      required:
        - id
        - title
        - sectionType
        - userInstruction
      properties:
        id:
          type: integer
          format: int64
          description: Section ID
          example: 1
        title:
          type: string
          description: Section title
          example: 주요 논의 사항
        sectionType:
          $ref: '#/components/schemas/NoteDocumentTemplateSectionType'
        userInstruction:
          type: string
          description: User-provided instruction for this section
          example: 회의에서 논의된 핵심 주제를 요약해주세요
    NoteDocumentTemplate:
      type: object
      description: |
        A template that defines the section structure for NoteDocuments. Either
        platform-managed (`isManaged: true`) or team-custom. Use this to pick or
        design the shape of a generated document. See
        [Data Model](/fundamentals/note-data-model).
      required:
        - id
        - title
        - description
        - sections
        - favorite
        - isManaged
        - isEditable
        - createdAt
      properties:
        id:
          type: integer
          format: int64
          description: Template ID
          example: 1
        title:
          type: string
          description: Template title
          example: 회의록
        description:
          type: string
          description: Template description
          example: 회의 내용을 체계적으로 정리하는 템플릿
        sections:
          type: array
          description: Template sections
          items:
            $ref: '#/components/schemas/NoteDocumentTemplateSection'
        favorite:
          type: boolean
          description: Whether the template is favorited by the user
          default: false
          example: false
        isManaged:
          type: boolean
          description: Whether the template is managed by the system
          example: true
        isEditable:
          type: boolean
          description: Whether the template is editable
          example: false
        createdAt:
          type: string
          format: date-time
          description: Template creation timestamp
          example: '2025-10-20T12:35:26Z'
        lastUsedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the template was last used. Null if never used.
          example: '2025-10-20T14:20:15Z'
    NoteDocumentTemplateListResponse:
      type: object
      description: Response containing list of note document templates
      required:
        - content
      properties:
        content:
          type: array
          description: Array of document templates
          items:
            $ref: '#/components/schemas/NoteDocumentTemplate'
    NoteSummaryTemplate:
      type: object
      description: Summary template information
      required:
        - id
        - title
      properties:
        id:
          type: integer
          format: int64
          description: Template ID
          example: 1
        title:
          type: string
          description: Template title (e.g., One-Pager, Pitch)
          example: One-Pager
    NoteSummaryListItem:
      type: object
      description: Summary metadata without content (used in list views)
      required:
        - id
        - locale
        - createdAt
      properties:
        id:
          type: integer
          format: int64
          description: Summary ID
          example: 123
        template:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/NoteSummaryTemplate'
          description: >-
            Template used for this summary. Null if the template has been
            deleted.
        locale:
          $ref: '#/components/schemas/SupportedLocale'
        createdAt:
          type: string
          format: date-time
          description: Creation timestamp
          example: '2025-12-12T12:00:00Z'
    NoteRef:
      type: object
      description: Note reference with minimal information
      required:
        - guid
        - webUrl
      properties:
        guid:
          type: string
          description: Note GUID
          example: note-abc123-def456
        webUrl:
          type: string
          format: uri
          description: Web URL to access the note
          example: https://tiro.ooo/n/xQ8YKnZUPGHNB
    NoteSummary:
      type: object
      description: >
        A single block of summary text for a Note (the "one-page" summary). A
        Note

        can have multiple NoteSummaries in different languages or templates.
        Unlike

        NoteDocument, it is not divided into sections. See

        [Data Model](/fundamentals/note-data-model).
      required:
        - id
        - noteGuid
        - note
        - locale
        - content
        - createdAt
        - updatedAt
      properties:
        id:
          type: integer
          format: int64
          description: Summary ID
          example: 123
        noteGuid:
          type: string
          description: Associated note GUID
          example: note-abc123-def456
        note:
          $ref: '#/components/schemas/NoteRef'
        template:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/NoteSummaryTemplate'
          description: >-
            Template used for this summary. Null if the template has been
            deleted.
        locale:
          $ref: '#/components/schemas/SupportedLocale'
        content:
          $ref: '#/components/schemas/TextObject'
        createdAt:
          type: string
          format: date-time
          description: Creation timestamp
          example: '2025-12-12T12:00:00Z'
        updatedAt:
          type: string
          format: date-time
          description: Last update timestamp
          example: '2025-12-12T12:05:00Z'
    NoteSummaryListResponse:
      type: object
      description: Response containing list of note summaries
      required:
        - content
      properties:
        content:
          type: array
          description: Array of summaries
          items:
            $ref: '#/components/schemas/NoteSummaryListItem'
        totalSize:
          type: integer
          description: Total number of summaries
          example: 3
    FolderSharingType:
      type: string
      description: >
        Who can access a folder and the notes inside it.


        | Type | View | Edit |

        |------|------|------|

        | `PRIVATE` | Only you | Only you |

        | `ALL_MEMBER_VIEWER` | All workspace members | No member-wide edit
        access |

        | `ALL_MEMBER_EDITOR` | All workspace members | All workspace members |

        | `LIMITED` | Invited members only | Invited members only (per-member
        role) |


        - `PRIVATE`: Personal folder. Not shared with the workspace.

        - `ALL_MEMBER_VIEWER`: Every workspace member can view; no member-wide
        edit access is granted.

        - `ALL_MEMBER_EDITOR`: Every workspace member can view and edit.

        - `LIMITED`: Only explicitly invited members can access, each with an
        individual role (`VIEWER` or `EDITOR`).
      enum:
        - PRIVATE
        - ALL_MEMBER_VIEWER
        - ALL_MEMBER_EDITOR
        - LIMITED
      example: PRIVATE
    FolderDetail:
      type: object
      description: A folder and its metadata.
      required:
        - id
        - workspaceGuid
        - title
        - description
        - sharingType
        - parentId
        - color
        - isTeamFolder
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          description: Unique identifier for the folder
          example: '12345'
        workspaceGuid:
          type: string
          description: GUID of the workspace the folder belongs to
          example: ws_a1b2c3d4
        title:
          type: string
          description: Folder title (max 50 characters)
          example: Weekly Team Meetings
        description:
          type: string
          description: Folder description. Empty string when unset.
          example: Notes from our weekly sync
        sharingType:
          $ref: '#/components/schemas/FolderSharingType'
        parentId:
          type: string
          nullable: true
          description: |
            Parent folder ID. `null` for root-level folders. In the List Folders
            response, `parentId` is also `null` when the parent folder is not
            accessible to you.
          example: '12300'
        color:
          type: string
          description: Folder color in hex format (#RRGGBB)
          example: '#4A90D9'
        isTeamFolder:
          type: boolean
          description: >
            `true` when the folder is shared with the workspace (any
            `sharingType`

            except `PRIVATE`); `false` for `PRIVATE` folders. Retained for
            backward

            compatibility — use `sharingType` for the precise access level.
          example: true
        createdAt:
          type: string
          format: date-time
          description: ISO-8601 creation timestamp (UTC)
          example: '2025-01-15T10:30:00Z'
        updatedAt:
          type: string
          format: date-time
          description: ISO-8601 last-update timestamp (UTC)
          example: '2025-01-18T14:20:00Z'
    CreateFolderRequest:
      type: object
      description: Create a folder in a workspace.
      required:
        - title
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 50
          description: Folder title. Must not be blank.
          example: Q1 2025 Meetings
        sharingType:
          $ref: '#/components/schemas/FolderSharingType'
        parentId:
          type: string
          nullable: true
          description: >
            Parent folder ID for a nested folder. Omit or set to `null` to
            create at

            the root level. Folders can be nested up to 5 levels below the root
            level.
          example: '12300'
        description:
          type: string
          nullable: true
          description: Folder description. Defaults to an empty string.
          example: Daily engineering standup notes
        color:
          type: string
          nullable: true
          pattern: ^#[0-9A-Fa-f]{6}$
          description: Folder color in hex format (#RRGGBB). Defaults to `#737373`.
          example: '#27AE60'
    PatchFolderRequest:
      type: object
      description: >
        Partial update. Only the fields you include change; omitted fields keep
        their

        current value. To re-parent a folder, use `PUT
        /v1/external/folders/{folderId}/move`

        — `PATCH` cannot change the parent.
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 50
          description: New folder title. Must not be blank.
          example: Engineering Sync
        sharingType:
          $ref: '#/components/schemas/FolderSharingType'
        description:
          type: string
          nullable: true
          description: New folder description
          example: Daily standup notes
        color:
          type: string
          nullable: true
          pattern: ^#[0-9A-Fa-f]{6}$
          description: New folder color in hex format (#RRGGBB)
          example: '#E74C3C'
    PatchNoteRequest:
      type: object
      description: >
        Partial update for a note. Include only the fields named in
        `updateMask`.
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 100
          description: New note title. Must not be blank and is limited to 100 characters.
          example: Q3 Planning Sync
    SharingTypeUpdateStrategy:
      type: string
      description: >
        How the moved folder's sharing permissions are handled.


        | Strategy | Behavior |

        |----------|----------|

        | `KEEP_EXISTING` | Keep the folder's current `sharingType`. |

        | `INHERIT_FROM_PARENT` | Adopt the new parent folder's `sharingType`. |


        - `KEEP_EXISTING`: The folder retains its current access control after
        the move.

        - `INHERIT_FROM_PARENT`: The folder adopts its new parent's
        `sharingType` and its
          member list. You must have access to the new parent. Moving to the root level
          (`newParentId: null`) has no parent to inherit from, so the folder keeps its
          existing `sharingType`.
      enum:
        - KEEP_EXISTING
        - INHERIT_FROM_PARENT
      default: KEEP_EXISTING
      example: KEEP_EXISTING
    MoveFolderRequest:
      type: object
      description: Move a folder under a new parent, or to the root level.
      properties:
        newParentId:
          type: string
          nullable: true
          description: >
            Target parent folder ID. Omit or set to `null` to move the folder to
            the

            root level. The target parent must be in the same workspace and you
            must

            have access to it.
          example: '98765'
        sharingTypeUpdateStrategy:
          $ref: '#/components/schemas/SharingTypeUpdateStrategy'
    ReorderFoldersRequest:
      type: object
      description: Set the display order of sibling folders.
      required:
        - orderedFolderIds
      properties:
        orderedFolderIds:
          type: array
          minItems: 1
          description: >
            Folder IDs in their new display order; positions are assigned by
            array

            index. All folders must belong to the same workspace, which is
            inferred

            from the first ID.
          items:
            type: string
          example:
            - '12346'
            - '12345'
            - '12347'
    AttachNoteRequest:
      type: object
      description: Attach an existing note to a folder.
      required:
        - noteGuid
      properties:
        noteGuid:
          type: string
          description: >
            GUID of the note to attach. The note must belong to the same
            workspace as

            the folder.
          example: note-abc123-def456
    WordMemory:
      type: object
      required:
        - id
        - entry
        - createdAt
      properties:
        id:
          type: integer
          format: int64
          description: Unique identifier of the word memory
          example: 1
        entry:
          type: string
          description: The registered word or term
          example: 인공지능
        createdAt:
          type: string
          format: date-time
          description: When the word memory was created (ISO 8601)
          example: '2026-04-01T10:30:00Z'
    CreateWordMemoryRequest:
      type: object
      required:
        - entry
      properties:
        entry:
          type: string
          minLength: 1
          description: The word or term to register. Must not be blank.
          example: 인공지능
    UpdateWordMemoryRequest:
      type: object
      properties:
        entry:
          type: string
          minLength: 1
          description: Updated word or term. Must not be blank if provided.
          example: 머신러닝
    ExternalWorkspaceListResponse:
      type: object
      required:
        - workspaces
      properties:
        workspaces:
          type: array
          items:
            $ref: '#/components/schemas/ExternalWorkspaceSummary'
          description: List of accessible workspaces
    ExternalWorkspaceSummary:
      type: object
      required:
        - guid
        - name
        - isWikiEnabled
      properties:
        guid:
          type: string
          description: Unique workspace identifier
          example: ws_abc123
        name:
          type: string
          description: Human-readable workspace name
          example: Acme Corp
        isWikiEnabled:
          type: boolean
          description: Whether wiki is both plan-eligible and activated for this workspace
          example: true
    WorkspaceMeResponse:
      type: object
      required:
        - guid
      properties:
        guid:
          type: string
          description: The caller's implicit workspace GUID
          example: ws_abc123
    OrganizationMeResponse:
      type: object
      required:
        - guid
        - name
      properties:
        guid:
          type: string
          description: Unique organization identifier
          example: og_a1b2c3d4
        name:
          type: string
          description: Human-readable organization name
          example: LG Uplus
    WikiPlanRequired:
      type: object
      required:
        - error_code
        - message
        - status_code
      properties:
        success:
          type: boolean
          description: Always false for error responses
          example: false
        error_code:
          type: string
          enum:
            - WIKI_PLAN_REQUIRED
            - WIKI_NOT_ACTIVATED
          description: >
            Machine-readable error code:

            - `WIKI_PLAN_REQUIRED` — plan does not include wiki

            - `WIKI_NOT_ACTIVATED` — plan is eligible but admin has not
            activated wiki
          example: WIKI_PLAN_REQUIRED
        message:
          type: string
          description: Human-readable error message
          example: 위키 기능은 Pro 이상 요금제에서 사용할 수 있어요.
        current_plan:
          type: string
          nullable: true
          description: Current plan name, or null if no subscription
          example: Lite
        required_plans:
          type: array
          items:
            type: string
          nullable: true
          description: >
            Upgrade targets for `WIKI_PLAN_REQUIRED`; null for
            `WIKI_NOT_ACTIVATED`.

            Team Free Trial is intentionally excluded.
          example:
            - pro
            - max
            - team
            - enterprise
        action_url:
          type: string
          format: uri
          nullable: true
          description: >-
            Web link to act on (pricing page for users, null for team members
            without permission)
          example: https://tiro.ooo/#pricing
        status_code:
          type: integer
          description: HTTP status code (always 402)
          example: 402
    WikiInfo:
      type: object
      required:
        - id
        - guid
        - workspaceId
        - name
        - createdAt
      properties:
        id:
          type: integer
          format: int64
          description: Internal wiki ID
          example: 1
        guid:
          type: string
          description: Wiki GUID
          example: wiki_abc123
        workspaceId:
          type: integer
          format: int64
          description: Parent workspace ID
          example: 5
        name:
          type: string
          description: Wiki name
          example: Acme Wiki
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 creation timestamp
          example: '2025-01-01T00:00:00Z'
    WikiPageListResponse:
      type: object
      required:
        - content
        - nextCursor
      properties:
        content:
          type: array
          items:
            $ref: '#/components/schemas/WikiPage'
          description: Array of wiki pages
        nextCursor:
          type: string
          nullable: true
          description: >
            Cursor for the next page of results. Null when there are no more
            pages.

            When searching (q parameter provided), always null.
          example: opaque-cursor-string
    WikiPage:
      type: object
      required:
        - guid
        - wikiId
        - canonicalName
        - pageType
        - extractionStatus
        - mentionCountVisible
        - aliasCount
        - linkCountIn
        - linkCountOut
        - createdAt
        - updatedAt
      properties:
        guid:
          type: string
          description: Wiki page GUID
          example: page_abc123
        wikiId:
          type: integer
          format: int64
          description: Parent wiki ID
          example: 1
        canonicalName:
          type: string
          description: Canonical name of the page (entity, topic, etc.)
          example: Alice Kim
        pageType:
          type: string
          enum:
            - ENTITY
            - MENTION
            - CUSTOM
          description: Type of wiki page
          example: ENTITY
        entitySubtype:
          type: string
          nullable: true
          description: Entity subtype (e.g., PERSON, ORG, LOCATION)
          example: PERSON
        extractionStatus:
          type: string
          enum:
            - EXTRACTED
            - EXTRACTING
            - FAILED
            - STALE
            - NOT_EXTRACTED
          description: Current extraction status
          example: EXTRACTED
        mentionCountVisible:
          type: integer
          description: Number of visible mentions (source notes)
          example: 5
        aliasCount:
          type: integer
          description: Number of aliases for this page
          example: 2
        linkCountIn:
          type: integer
          description: Number of inbound links
          example: 3
        linkCountOut:
          type: integer
          description: Number of outbound links
          example: 2
        lastUpdatedVisible:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 timestamp of last visible update
          example: '2025-01-15T10:30:00Z'
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 creation timestamp
          example: '2025-01-01T00:00:00Z'
        updatedAt:
          type: string
          format: date-time
          description: ISO 8601 last update timestamp
          example: '2025-01-15T10:30:00Z'
        description:
          type: string
          nullable: true
          description: User-provided page description
          example: Senior product manager at Acme
        descriptionStatus:
          type: string
          nullable: true
          enum:
            - GENERATING
            - READY
            - FAILED
          description: >
            Status of the personalized description backfill.

            Null while not yet generated; poll this endpoint until it
            transitions out of GENERATING.
          example: READY
        regenerationAvailable:
          type: boolean
          nullable: true
          description: Whether description can be regenerated
          example: true
    WikiPageDetail:
      type: object
      required:
        - guid
        - wikiId
        - canonicalName
        - pageType
        - extractionStatus
        - mentionCountVisible
        - sourceNoteCountVisible
        - mentions
        - aliases
        - links
        - createdAt
        - updatedAt
      properties:
        guid:
          type: string
          description: Wiki page GUID
          example: page_abc123
        wikiId:
          type: integer
          format: int64
          description: Parent wiki ID
          example: 1
        canonicalName:
          type: string
          description: Canonical name of the page
          example: Alice Kim
        description:
          type: string
          nullable: true
          description: User-provided page description or AI-generated summary
          example: Senior product manager at Acme
        descriptionStatus:
          type: string
          nullable: true
          enum:
            - GENERATING
            - READY
            - FAILED
          description: Status of description backfill
          example: READY
        regenerationAvailable:
          type: boolean
          nullable: true
          description: Whether description can be regenerated
          example: true
        pageType:
          type: string
          enum:
            - ENTITY
            - MENTION
            - CUSTOM
          description: Type of wiki page
          example: ENTITY
        entitySubtype:
          type: string
          nullable: true
          description: Entity subtype
          example: PERSON
        extractionStatus:
          type: string
          enum:
            - EXTRACTED
            - EXTRACTING
            - FAILED
            - STALE
            - NOT_EXTRACTED
          description: Current extraction status
          example: EXTRACTED
        mentionCountVisible:
          type: integer
          description: Number of visible mentions
          example: 5
        sourceNoteCountVisible:
          type: integer
          description: Number of source notes with visible mentions
          example: 5
        mentions:
          type: array
          items:
            $ref: '#/components/schemas/WikiMention'
          description: List of mentions for this page
        aliases:
          type: array
          items:
            $ref: '#/components/schemas/WikiAlias'
          description: List of aliases for this page
        links:
          type: array
          items:
            $ref: '#/components/schemas/WikiLink'
          description: List of links (inbound and outbound)
        lastUpdatedVisible:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 timestamp of last visible update
          example: '2025-01-15T10:30:00Z'
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 creation timestamp
          example: '2025-01-01T00:00:00Z'
        updatedAt:
          type: string
          format: date-time
          description: ISO 8601 last update timestamp
          example: '2025-01-15T10:30:00Z'
    WikiMention:
      type: object
      required:
        - guid
        - noteId
        - kind
        - sourceUserId
        - extractedText
        - createdAt
      properties:
        guid:
          type: string
          description: Mention GUID
          example: mention_abc123
        noteId:
          type: integer
          format: int64
          description: Source note ID
          example: 123
        paragraphId:
          type: integer
          format: int64
          nullable: true
          description: Source paragraph ID within the note
          example: 456
        paragraphUuid:
          type: string
          nullable: true
          description: Source paragraph UUID
          example: para_uuid_123
        kind:
          type: string
          enum:
            - EXPLICIT
            - IMPLICIT
            - REFERENCE
          description: >-
            Type of mention (explicit user tag, implicit extraction, or
            reference)
          example: EXPLICIT
        sourceUserId:
          type: integer
          format: int64
          description: User ID of the mention source
          example: 789
        extractedText:
          type: string
          description: The extracted mention text from the note
          example: Alice Kim mentioned in our meeting
        confidence:
          type: number
          format: double
          nullable: true
          description: Confidence score for extraction (0-1)
          example: 0.95
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 mention creation timestamp
          example: '2025-01-15T10:30:00Z'
    WikiAlias:
      type: object
      required:
        - guid
        - alias
        - source
        - createdAt
      properties:
        guid:
          type: string
          description: Alias GUID
          example: alias_abc123
        alias:
          type: string
          description: The alias string
          example: AK
        source:
          type: string
          enum:
            - USER_PROVIDED
            - EXTRACTED_FROM_MENTION
          description: Source of the alias (user-provided or extracted)
          example: USER_PROVIDED
        sourceMentionGuid:
          type: string
          nullable: true
          description: Source mention GUID if extracted
          example: mention_abc123
        sourceUserId:
          type: integer
          format: int64
          nullable: true
          description: User ID who created the alias (if user-provided)
          example: 789
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 creation timestamp
          example: '2025-01-15T10:30:00Z'
    WikiLink:
      type: object
      required:
        - guid
        - sourcePageGuid
        - targetPageGuid
        - linkType
        - linkTypeDisplayKo
        - linkTypeDisplayEn
        - isDirectional
        - source
        - createdAt
        - updatedAt
      properties:
        guid:
          type: string
          description: Link GUID
          example: link_abc123
        sourcePageGuid:
          type: string
          description: Source page GUID
          example: page_src_123
        sourcePageName:
          type: string
          nullable: true
          description: Source page canonical name
          example: Alice Kim
        targetPageGuid:
          type: string
          description: Target page GUID
          example: page_tgt_456
        targetPageName:
          type: string
          nullable: true
          description: Target page canonical name
          example: Acme Corp
        linkType:
          type: string
          description: Machine-readable link type code
          example: works_at
        linkTypeDisplayKo:
          type: string
          description: Korean display name for link type
          example: 근무처
        linkTypeDisplayEn:
          type: string
          description: English display name for link type
          example: Works At
        isDirectional:
          type: boolean
          description: Whether the link is directional
          example: true
        source:
          type: string
          enum:
            - USER_PROVIDED
            - EXTRACTED_FROM_MENTION
          description: Source of the link
          example: EXTRACTED_FROM_MENTION
        creatorUserId:
          type: integer
          format: int64
          nullable: true
          description: User ID of the link creator (if user-provided)
          example: 789
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 creation timestamp
          example: '2025-01-15T10:30:00Z'
        updatedAt:
          type: string
          format: date-time
          description: ISO 8601 last update timestamp
          example: '2025-01-15T10:30:00Z'
    WikiMentionListResponse:
      type: object
      required:
        - content
        - nextCursor
      properties:
        content:
          type: array
          items:
            $ref: '#/components/schemas/WikiMention'
          description: Array of mentions for the page
        nextCursor:
          type: string
          nullable: true
          description: >-
            Cursor for the next page of results. Null when there are no more
            pages.
          example: opaque-cursor-string
    WikiSearchPagesResponse:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/WikiSearchPage'
          description: Ranked list of matching wiki pages
    WikiSearchPage:
      type: object
      required:
        - guid
        - wikiId
        - canonicalName
        - pageType
        - score
      properties:
        guid:
          type: string
          description: Wiki page GUID
          example: page_abc123
        wikiId:
          type: integer
          format: int64
          description: Parent wiki ID
          example: 1
        canonicalName:
          type: string
          description: Canonical name of the page
          example: Alice Kim
        pageType:
          type: string
          enum:
            - ENTITY
            - MENTION
            - CUSTOM
          description: Type of wiki page
          example: ENTITY
        entitySubtype:
          type: string
          nullable: true
          description: Entity subtype
          example: PERSON
        score:
          type: number
          format: float
          description: Full-text relevance score (higher is more relevant)
          example: 0.85
    WikiSearchMentionsResponse:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/WikiSearchMention'
          description: Ranked list of matching mentions
    WikiSearchMention:
      type: object
      required:
        - guid
        - pageGuid
        - noteId
        - kind
        - extractedText
        - sourceUserId
        - createdAt
        - score
      properties:
        guid:
          type: string
          description: Mention GUID
          example: mention_abc123
        pageGuid:
          type: string
          description: Wiki page GUID this mention references
          example: page_abc123
        noteId:
          type: integer
          format: int64
          description: Source note ID
          example: 123
        paragraphId:
          type: integer
          format: int64
          nullable: true
          description: Source paragraph ID
          example: 456
        paragraphUuid:
          type: string
          nullable: true
          description: Source paragraph UUID
          example: para_uuid_123
        kind:
          type: string
          enum:
            - EXPLICIT
            - IMPLICIT
            - REFERENCE
          description: Type of mention
          example: EXPLICIT
        extractedText:
          type: string
          description: The extracted mention text
          example: Alice Kim mentioned in our meeting
        sourceUserId:
          type: integer
          format: int64
          description: User ID of the mention source
          example: 789
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 mention creation timestamp
          example: '2025-01-15T10:30:00Z'
        score:
          type: number
          format: float
          description: Full-text relevance score (higher is more relevant)
          example: 0.92
    WikiGraphResponse:
      type: object
      required:
        - nodes
        - edges
      properties:
        nodes:
          type: array
          items:
            $ref: '#/components/schemas/WikiGraphNode'
          description: List of wiki page nodes
        edges:
          type: array
          items:
            $ref: '#/components/schemas/WikiGraphEdge'
          description: List of links between nodes
    WikiGraphNode:
      type: object
      required:
        - guid
        - canonicalName
        - pageType
        - extractionStatus
        - mentionCountVisible
      properties:
        guid:
          type: string
          description: Wiki page GUID
          example: page_abc123
        canonicalName:
          type: string
          description: Canonical name of the page
          example: Alice Kim
        pageType:
          type: string
          enum:
            - ENTITY
            - MENTION
            - CUSTOM
          description: Type of wiki page
          example: ENTITY
        entitySubtype:
          type: string
          nullable: true
          description: Entity subtype
          example: PERSON
        extractionStatus:
          type: string
          enum:
            - EXTRACTED
            - EXTRACTING
            - FAILED
            - STALE
            - NOT_EXTRACTED
          description: Current extraction status
          example: EXTRACTED
        mentionCountVisible:
          type: integer
          description: Number of visible mentions
          example: 5
    WikiGraphEdge:
      type: object
      required:
        - guid
        - sourcePageGuid
        - targetPageGuid
        - linkType
        - linkTypeDisplayKo
        - linkTypeDisplayEn
        - isDirectional
      properties:
        guid:
          type: string
          description: Link GUID
          example: link_abc123
        sourcePageGuid:
          type: string
          description: Source page GUID
          example: page_src_123
        targetPageGuid:
          type: string
          description: Target page GUID
          example: page_tgt_456
        linkType:
          type: string
          description: Machine-readable link type code
          example: works_at
        linkTypeDisplayKo:
          type: string
          description: Korean display name for link type
          example: 근무처
        linkTypeDisplayEn:
          type: string
          description: English display name for link type
          example: Works At
        isDirectional:
          type: boolean
          description: Whether the link is directional
          example: true
paths:
  /v1/external/notes:
    get:
      summary: List Notes
      deprecated: true
      description: |
        **Deprecated.** Use `GET /v1/external/workspaces/{workspaceGuid}/notes`
        for workspace-scoped listing. This endpoint stays available for backward
        compatibility.

        List notes with cursor-based pagination.

        When `keyword` is provided the result set is reordered by full-text
        relevance (with `createdAt` desc as tiebreaker) instead of
        `recordingStartAt` desc. Keyword search requires a user-scoped API
        key — team-only API keys with `keyword` set return `400`.

        Use `folderId` to scope the listing to a specific folder (recursive,
        including descendant folders). Combine with `createdAtFrom` /
        `createdAtTo` to bound the result by creation time.
      operationId: listNotes
      tags:
        - Note
      parameters:
        - name: cursor
          in: query
          description: Cursor for the next page
          required: false
          schema:
            type: string
        - name: size
          in: query
          description: Page size (default 100)
          required: false
          schema:
            type: integer
            default: 100
            minimum: 1
            maximum: 1000
        - name: keyword
          in: query
          description: |
            Optional keyword. When present, results are reordered by full-text
            relevance and the response is bounded by what the search index
            returns; `nextCursor` is `null` in this mode. Requires a
            user-scoped API key.
          required: false
          schema:
            type: string
        - name: folderId
          in: query
          description: |
            Restrict to notes inside a specific folder. Includes descendant
            folders (recursive). For a team API key, the folder must belong to
            the team; otherwise the call returns 404.
          required: false
          schema:
            type: string
        - name: createdAtFrom
          in: query
          description: >-
            ISO 8601 datetime — return only notes with `createdAt >=` this
            value.
          required: false
          schema:
            type: string
            format: date-time
        - name: createdAtTo
          in: query
          description: ISO 8601 datetime — return only notes with `createdAt <` this value.
          required: false
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: List of notes
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PageCursorResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/Note'
              examples:
                success:
                  summary: Successful notes list
                  value:
                    content:
                      - guid: note-abc123-def456
                        title: Weekly Team Meeting
                        createdAt: '2024-01-15T10:30:00Z'
                        updatedAt: '2024-01-15T11:45:00Z'
                        sourceType: live-voice
                        recordingStartAt: '2024-01-15T10:30:10Z'
                        recordingEndAt: '2024-01-15T11:30:15Z'
                        recordingDurationSeconds: 3605
                        transcribeLocale: ko_KR
                        translateLocale: en_US
                        webUrl: https://tiro.ooo/n/abc123def456
                        collaborators: []
                        participants:
                          - name: Alice Kim
                            email: alice@example.com
                          - name: Bob Park
                            email: null
                      - guid: note-def456-ghi789
                        title: Product Planning Session
                        createdAt: '2024-01-14T14:00:00Z'
                        updatedAt: '2024-01-14T15:30:00Z'
                        sourceType: live-voice
                        recordingStartAt: '2024-01-14T14:00:05Z'
                        recordingEndAt: '2024-01-14T15:30:20Z'
                        recordingDurationSeconds: 5415
                        transcribeLocale: en_US
                        translateLocale: ko_KR
                        webUrl: https://tiro.ooo/n/def456ghi789
                        collaborators: []
                        participants: []
                    nextCursor: cursor_string
                empty:
                  summary: Empty notes list
                  value:
                    content: []
                    nextCursor: null
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/notes:
    get:
      summary: List Workspace Notes
      description: >
        List the notes in a workspace with cursor-based pagination. This is the

        workspace-scoped successor to the deprecated `GET /v1/external/notes`.


        The API key must be scoped to the workspace in the path; a key bound to
        a

        different workspace returns `403`.


        Use `folderId` to scope the listing to a specific folder (recursive,

        including descendant folders). Combine with `createdAtFrom` /

        `createdAtTo` to bound the result by creation time.
      operationId: listWorkspaceNotes
      tags:
        - Note
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
        - name: cursor
          in: query
          description: Cursor for the next page
          required: false
          schema:
            type: string
        - name: size
          in: query
          description: Page size (default 100, max 200)
          required: false
          schema:
            type: integer
            default: 100
            minimum: 1
            maximum: 200
        - name: keyword
          in: query
          description: >
            Optional keyword for a shallow full-text search. When present,
            results

            are reordered by relevance and bounded by what the search index
            returns;

            `nextCursor` is always `null` in this mode (single page). Combine
            with

            `folderId` and `createdAtFrom` / `createdAtTo` to narrow the
            results.

            For deep search that also returns note documents, use

            `POST /v1/external/workspaces/{workspaceGuid}/notes/search` instead.

            Requires a user-scoped API key.
          required: false
          schema:
            type: string
        - name: folderId
          in: query
          description: |
            Restrict to notes inside a specific folder. Includes descendant
            folders (recursive). The folder must belong to this workspace.
          required: false
          schema:
            type: string
        - name: createdAtFrom
          in: query
          description: >-
            ISO 8601 datetime — return only notes with `createdAt >=` this
            value.
          required: false
          schema:
            type: string
            format: date-time
        - name: createdAtTo
          in: query
          description: ISO 8601 datetime — return only notes with `createdAt <` this value.
          required: false
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: List of notes in the workspace
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PageCursorResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/Note'
              examples:
                success:
                  summary: Successful notes list
                  value:
                    content:
                      - guid: note-abc123-def456
                        workspaceGuid: ws_a1b2c3d4
                        title: Weekly Team Meeting
                        createdAt: '2024-01-15T10:30:00Z'
                        updatedAt: '2024-01-15T11:45:00Z'
                        sourceType: live-voice
                        recordingStartAt: '2024-01-15T10:30:10Z'
                        recordingEndAt: '2024-01-15T11:30:15Z'
                        recordingDurationSeconds: 3605
                        transcribeLocale: ko_KR
                        translateLocale: en_US
                        webUrl: https://tiro.ooo/n/abc123def456
                        collaborators: []
                        participants: []
                    nextCursor: cursor_string
                empty:
                  summary: Empty notes list
                  value:
                    content: []
                    nextCursor: null
        '401':
          description: Unauthorized — missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — the API key is not scoped to this workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/notes/search:
    post:
      summary: Search Workspace Notes (Deep)
      description: >
        Deep keyword search scoped to one workspace, named in the path by

        `workspaceGuid`. Returns notes hydrated with their primary documents

        (one-pager, custom) so an MCP/LLM client can read content alongside

        metadata in a single call. This is the workspace-scoped successor to the

        deprecated `POST /v1/external/notes/search`.


        ## When to use this vs `GET
        /v1/external/workspaces/{workspaceGuid}/notes?keyword=...`


        - **`GET …/notes?keyword=…`** — lightweight: returns matched note
          metadata only. Cheaper.
        - **`POST …/notes/search`** (this) — heavy: also returns the matched
          notes' documents. Use when you need to understand the context behind a
          topic, not just see which notes match.

        ## Which API keys work


        Unlike the deprecated `POST /v1/external/notes/search` (user-scoped keys

        only), this endpoint accepts user, workspace-system, and legacy team API

        keys. A key bound to a workspace must match the `workspaceGuid` in the

        path, otherwise the call returns `403`. A user-scoped key must belong to

        a member of the workspace, otherwise the call returns `403`.


        ## Behavior


        - Results stay inside the path workspace. Both note matching and
        document
          hydration are workspace-bounded, so cross-workspace notes never leak.
        - When the search index is unavailable or fails, the response sets
          `degraded=true` and `degradedReason` to one of
          `search_index_unavailable` / `search_index_degraded` and returns an
          empty `notes` array — clients should surface this to the user/LLM.
        - Document content is structured (`sections`); each document carries a
          `truncated` flag when the combined section text exceeded the 5,000
          char search budget.
        - `nextCursor` is reserved for future use and is currently always
        `null`.
      operationId: searchWorkspaceNotes
      tags:
        - Note
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NoteSearchRequest'
            examples:
              keywordOnly:
                summary: Minimal — keyword only
                value:
                  keyword: OKR
              folderScoped:
                summary: Keyword scoped to a folder
                value:
                  keyword: OKR
                  filter:
                    folderId: '455765'
                    createdAtFrom: '2026-04-01T00:00:00Z'
                  pagination:
                    size: 10
      responses:
        '200':
          description: Matched notes with their documents.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteSearchResponse'
              examples:
                success:
                  summary: Successful deep search
                  value:
                    notes:
                      - guid: note-abc123-def456
                        workspaceGuid: ws_a1b2c3d4
                        title: OKR Q2 Planning
                        createdAt: '2026-04-15T10:00:00Z'
                        updatedAt: '2026-04-15T11:30:00Z'
                        sourceType: live-voice
                        recordingStartAt: '2026-04-15T10:00:05Z'
                        recordingEndAt: '2026-04-15T11:00:30Z'
                        recordingDurationSeconds: 3625
                        transcribeLocale: ko_KR
                        translateLocale: null
                        webUrl: https://tiro.ooo/n/abc123def456
                        collaborators: []
                        participants:
                          - name: Alice Kim
                            email: alice@example.com
                        matchedSnippets: null
                        documents: []
                    nextCursor: null
                    degraded: false
                degraded:
                  summary: Search index unavailable — degraded response
                  value:
                    notes: []
                    nextCursor: null
                    degraded: true
                    degradedReason: search_index_unavailable
        '400':
          description: Bad request — most commonly raised when `keyword` is blank.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: |
            Forbidden — the API key is bound to a different workspace, or a
            user-scoped key does not belong to a member of this workspace.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/search:
    post:
      summary: Search Notes (Deep)
      deprecated: true
      description: >
        **Deprecated.** Use `POST
        /v1/external/workspaces/{workspaceGuid}/notes/search`

        for workspace-scoped deep search, which also accepts workspace-system
        and

        team API keys. This endpoint stays available for backward compatibility.


        Keyword-required deep search. Returns notes hydrated with their primary

        documents (one-pager, custom) so an MCP/LLM client can read content

        alongside metadata in a single call.


        ## When to use this vs `GET /v1/external/notes?keyword=...`


        - **`GET /v1/external/notes?keyword=...`** — lightweight: returns
        matched
          note metadata only. Cheaper.
        - **`POST /v1/external/notes/search`** (this) — heavy: also returns the
          matched notes' documents. Use when you need to understand the context
          behind a topic, not just see which notes match.

        ## Behavior


        - Requires a user-scoped API key (team-only API keys return `400`).

        - When the search index is unavailable or fails, the response sets
          `degraded=true` and `degradedReason` to one of
          `search_index_unavailable` / `search_index_degraded` and returns an
          empty `notes` array — clients should surface this to the user/LLM.
        - Document content is structured (`sections`); each document carries a
          `truncated` flag when the combined section text exceeded the 5,000
          char search budget.
        - `nextCursor` is reserved for future use and is currently always
        `null`.
      operationId: searchNotes
      tags:
        - Note
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NoteSearchRequest'
            examples:
              keywordOnly:
                summary: Minimal — keyword only
                value:
                  keyword: OKR
              folderScoped:
                summary: Keyword scoped to a team folder
                value:
                  keyword: OKR
                  filter:
                    folderId: '455765'
                    createdAtFrom: '2026-04-01T00:00:00Z'
                  pagination:
                    size: 10
      responses:
        '200':
          description: Matched notes with their documents.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteSearchResponse'
              examples:
                success:
                  summary: Successful deep search
                  value:
                    notes:
                      - guid: note-abc123-def456
                        title: OKR Q2 Planning
                        createdAt: '2026-04-15T10:00:00Z'
                        updatedAt: '2026-04-15T11:30:00Z'
                        sourceType: live-voice
                        recordingStartAt: '2026-04-15T10:00:05Z'
                        recordingEndAt: '2026-04-15T11:00:30Z'
                        recordingDurationSeconds: 3625
                        transcribeLocale: ko_KR
                        translateLocale: null
                        webUrl: https://tiro.ooo/n/abc123def456
                        collaborators: []
                        participants:
                          - name: Alice Kim
                            email: alice@example.com
                        matchedSnippets: null
                        documents: []
                    nextCursor: null
                    degraded: false
                degraded:
                  summary: Search index unavailable — degraded response
                  value:
                    notes: []
                    nextCursor: null
                    degraded: true
                    degradedReason: search_index_unavailable
        '400':
          description: |
            Bad request. Most commonly raised when `keyword` is blank or when a
            team-only API key is used (keyword search currently requires a
            user-scoped key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/guids:
    post:
      summary: Reserve Note GUID
      description: >
        Reserve a note GUID for later use in note creation. This allows you to:

        - Get a GUID before actually creating the note

        - Use the reserved GUID when creating a note with POST /v1/notes
        (internal API)

        - Reservation expires after 1 hour if not used


        **Use case**: When you need to know the note GUID before the note
        content is ready,

        such as setting up webhooks or references in advance.
      operationId: reserveNoteGuid
      tags:
        - Note
      requestBody:
        description: Optional parameters for the note reservation
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NoteReservationRequest'
            example:
              title: Weekly Team Standup
      responses:
        '201':
          description: Note GUID successfully reserved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteReservationResponse'
              example:
                guid: x6DjzdpXqkEcU
                title: Weekly Team Standup
                expiresAt: '2024-01-15T11:30:00Z'
                createdAt: '2024-01-15T10:30:00Z'
        '401':
          description: Unauthorized - Invalid or missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: 401001
                  errorType: unauthorized
                  message: API key authentication required
                  detail: null
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/{noteGuid}:
    get:
      summary: Get Note
      description: Retrieve a single note by its GUID
      operationId: getNote
      tags:
        - Note
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Note details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Note'
              example:
                guid: note-abc123-def456
                title: Weekly Team Meeting
                createdAt: '2024-01-15T10:30:00Z'
                updatedAt: '2024-01-15T11:45:00Z'
                sourceType: live-voice
                recordingStartAt: '2024-01-15T10:30:10Z'
                recordingEndAt: '2024-01-15T11:30:15Z'
                recordingDurationSeconds: 3605
                transcribeLocale: ko_KR
                translateLocale: en_US
                webUrl: https://tiro.ooo/n/abc123def456
                collaborators: []
                participants:
                  - name: Alice Kim
                    email: alice@example.com
                  - name: Bob Park
                    email: null
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    patch:
      summary: Update Note
      description: >
        Update a note's metadata (partial update). Currently only the note
        `title`

        can be changed. Requires the `note:write` scope.


        This follows the [AIP-134](https://google.aip.dev/134) field-mask
        convention:

        the required `updateMask` query parameter lists which fields to change,
        and

        only those fields are touched. A field named in `updateMask` but absent
        from

        the body (or sent as `null`) is treated as an error for `title`, since
        the

        title cannot be blank.
      operationId: updateNote
      tags:
        - Note
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
          example: note-abc123-def456
        - name: updateMask
          in: query
          description: >
            Comma-separated list of fields to update. Only `title` is supported
            today.
          required: true
          schema:
            type: string
          example: title
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchNoteRequest'
            examples:
              rename:
                summary: Rename the note
                value:
                  title: Q3 Planning Sync
      responses:
        '200':
          description: Note updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Note'
              example:
                guid: note-abc123-def456
                title: Q3 Planning Sync
                createdAt: '2024-01-15T10:30:00Z'
                updatedAt: '2024-01-15T12:05:00Z'
                sourceType: live-voice
                webUrl: https://tiro.ooo/n/abc123def456
        '400':
          description: >-
            Bad request — empty `updateMask`, unknown field, or a blank/too-long
            title
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — the API key lacks the `note:write` scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/{noteGuid}/paragraphs:
    get:
      summary: List Note Paragraphs
      description: >
        Returns a note's transcript as paragraphs — the "conversation notes"

        / transcript content (a speaker turn or topic chunk per paragraph).


        **Paywall masking (free / unpaid notes).** When a note exceeds the free

        usage limit and is not on a paid plan, the paragraphs past the limit are

        returned with their text content masked instead of withheld. Such

        paragraphs have `locked: true`. The first locked paragraph keeps a short

        readable preview (about the first 80 characters of `transcript`, and the

        summary header plus its first bullet); every locked paragraph after it
        is

        fully masked. Masking preserves length, whitespace, and structure but

        replaces the words with placeholder characters, so masked text reads as

        gibberish rather than the real transcript. Unlocked paragraphs

        (`locked: false`) are always returned in full. Starting a paid plan

        unlocks the note and removes the masking. A response where the
        transcript

        "cuts off partway" is almost always this masking, not a bug.
      operationId: listNoteParagraphs
      tags:
        - Note
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
        - name: cursor
          in: query
          description: Cursor for the next page
          required: false
          schema:
            type: string
        - name: size
          in: query
          description: Page size (default 100)
          required: false
          schema:
            type: integer
            default: 100
            minimum: 1
            maximum: 1000
      responses:
        '200':
          description: List of paragraphs
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PageCursorResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/Paragraph'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/{noteGuid}/share-link:
    put:
      summary: Upsert Share Link
      description: >
        Create or update a share link for a note.


        - If no link exists, creates a new one. If it already exists, updates
        password settings.

        - An empty body `{}` creates a link without a password.


        ### `usePassword` behavior


        | `usePassword` | No existing link | Existing link |

        |---|---|---|

        | `null` (omit) | Create without password | Keep current state |

        | `true` | Create with password | (Re)generate password |

        | `false` | Create without password | Remove password |


        > `sharePassword` is only included when `usePassword: true`. Store it
        immediately — it cannot be retrieved later.
      operationId: upsertShareLink
      tags:
        - Note Share Link
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ShareLinkRequest'
            examples:
              withPassword:
                summary: Create or regenerate password
                value:
                  usePassword: true
              withoutPassword:
                summary: Create without password or remove existing password
                value:
                  usePassword: false
              keepCurrent:
                summary: Keep current password state (update link only)
                value: {}
      responses:
        '200':
          description: Share link created or updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ShareLinkResponse'
              example:
                shareId: LHr1bHvCCdVCG
                shareUrl: https://tiro.ooo/s/LHr1bHvCCdVCG
                sharePassword: a1b2c3d4
                hasPassword: true
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Link sharing not allowed for this team
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: 403003
                  errorType: forbidden
                  message: Link sharing is not allowed for this team
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      summary: Get Share Link
      description: |
        Retrieve the current share link for a note.

        - Returns 404 if no share link exists
        - `sharePassword` is always `null` for security
      operationId: getShareLink
      tags:
        - Note Share Link
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Share link details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ShareLinkResponse'
              example:
                shareId: LHr1bHvCCdVCG
                shareUrl: https://tiro.ooo/s/LHr1bHvCCdVCG
                sharePassword: null
                hasPassword: true
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden - insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Share link not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete Share Link
      description: |
        Delete the share link for a note.

        - Returns 204 even if already deleted (idempotent)
      operationId: deleteShareLink
      tags:
        - Note Share Link
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Share link deleted
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden - insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/folders:
    post:
      summary: Create Folder
      description: >
        Create a folder in a workspace.


        Requires a **user** API key — you must be a writable member of the
        workspace.

        A team-only API key returns `401`.


        To nest the folder, set `parentId` (folders can be nested up to 5 levels
        below the root level).

        `sharingType` defaults to `ALL_MEMBER_VIEWER` when omitted.
      operationId: createWorkspaceFolder
      tags:
        - Folder
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFolderRequest'
            examples:
              basic:
                summary: Private root folder
                value:
                  title: Q1 2025 Meetings
                  sharingType: PRIVATE
              nestedTeam:
                summary: Nested team-shared folder
                value:
                  title: Engineering Standups
                  sharingType: ALL_MEMBER_EDITOR
                  parentId: '12300'
                  description: Daily engineering standup notes
                  color: '#27AE60'
      responses:
        '201':
          description: Folder created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FolderDetail'
              example:
                id: '12348'
                workspaceGuid: ws_a1b2c3d4
                title: Engineering Standups
                description: Daily engineering standup notes
                sharingType: ALL_MEMBER_EDITOR
                parentId: '12300'
                color: '#27AE60'
                isTeamFolder: true
                createdAt: '2025-01-20T09:00:00Z'
                updatedAt: '2025-01-20T09:00:00Z'
        '400':
          description: >-
            Bad request — blank title, invalid color, or the folder would be
            nested more than 5 levels below the root level
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden — you are not a writable member of the workspace, or you
            cannot access the parent folder
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Parent folder not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      summary: List Folders
      description: |
        List the folders you can access in a workspace, as a flat array.

        Requires a **user** API key — folder access is evaluated per user via
        workspace membership. A team-only API key returns `401`.

        Create folders with `POST` on this same path. Read and manage individual
        folders with the endpoints under `/v1/external/folders/{folderId}`.
      operationId: listWorkspaceFolders
      tags:
        - Folder
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
      responses:
        '200':
          description: Folders you can access in the workspace
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FolderDetail'
              example:
                - id: '12345'
                  workspaceGuid: ws_a1b2c3d4
                  title: Weekly Team Meetings
                  description: Notes from our weekly sync
                  sharingType: ALL_MEMBER_VIEWER
                  parentId: null
                  color: '#4A90D9'
                  isTeamFolder: true
                  createdAt: '2025-01-15T10:30:00Z'
                  updatedAt: '2025-01-18T14:20:00Z'
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — you are not a member of this workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/folders/tree:
    get:
      summary: Get Folder Tree
      description: >
        Retrieve the workspace folder hierarchy as a nested tree.


        Requires a **user** API key. The tree contains only folders you can
        access.

        When a folder's parent is not accessible to you, the folder appears at
        the

        root level of the tree instead.
      operationId: getWorkspaceFolderTree
      tags:
        - Folder
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
      responses:
        '200':
          description: Folder tree
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SimpleListResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/FolderTreeNode'
              example:
                content:
                  - id: '12300'
                    title: Team Root
                    parentId: null
                    depth: 0
                    isAccessible: true
                    children:
                      - id: '12345'
                        title: Weekly Team Meetings
                        parentId: '12300'
                        depth: 1
                        isAccessible: true
                        children: []
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — you are not a member of this workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/folders/{folderId}:
    get:
      summary: Get Folder
      description: >
        Retrieve a single folder by ID. The workspace is resolved from the
        folder, so

        no workspace is needed in the path.


        Requires a **user** API key with access to the folder.
      operationId: getFolder
      tags:
        - Folder
      parameters:
        - name: folderId
          in: path
          required: true
          description: Folder ID
          schema:
            type: string
          example: '12345'
      responses:
        '200':
          description: Folder details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FolderDetail'
              example:
                id: '12345'
                workspaceGuid: ws_a1b2c3d4
                title: Weekly Team Meetings
                description: Notes from our weekly sync
                sharingType: ALL_MEMBER_VIEWER
                parentId: null
                color: '#4A90D9'
                isTeamFolder: true
                createdAt: '2025-01-15T10:30:00Z'
                updatedAt: '2025-01-18T14:20:00Z'
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — no access to this folder
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Folder not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    patch:
      summary: Update Folder
      description: >
        Update a folder's title, description, color, or sharing type (partial
        update).

        Requires edit access.


        Changing `sharingType` to `PRIVATE` fails with `403` if the folder still
        has

        other members. `PATCH` cannot change the parent — use

        `PUT /v1/external/folders/{folderId}/move` to re-parent or move to the
        root.
      operationId: updateFolder
      tags:
        - Folder
      parameters:
        - name: folderId
          in: path
          required: true
          description: Folder ID
          schema:
            type: string
          example: '12345'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchFolderRequest'
            examples:
              rename:
                summary: Rename the folder
                value:
                  title: Engineering Sync
              multiple:
                summary: Update several fields
                value:
                  title: Engineering Sync
                  description: Daily standup notes
                  color: '#E74C3C'
                  sharingType: ALL_MEMBER_EDITOR
      responses:
        '200':
          description: Folder updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FolderDetail'
              example:
                id: '12345'
                workspaceGuid: ws_a1b2c3d4
                title: Engineering Sync
                description: Daily standup notes
                sharingType: ALL_MEMBER_EDITOR
                parentId: null
                color: '#E74C3C'
                isTeamFolder: true
                createdAt: '2025-01-15T10:30:00Z'
                updatedAt: '2025-01-20T11:00:00Z'
        '400':
          description: Bad request — blank title or invalid color
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden — no edit access to this folder, or a `PRIVATE` transition
            while the folder still has members
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Folder not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete Folder
      description: |
        Delete a folder. The folder must have no subfolders — delete or move its
        children first. Requires edit access.

        This action is irreversible.
      operationId: deleteFolder
      tags:
        - Folder
      parameters:
        - name: folderId
          in: path
          required: true
          description: Folder ID
          schema:
            type: string
          example: '12345'
      responses:
        '204':
          description: Folder deleted
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — no edit access to this folder
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Folder not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: >-
            Unprocessable — the folder still has subfolders; delete or move them
            first
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/folders/{folderId}/path:
    get:
      summary: Get Folder Path
      description: >
        Retrieve the breadcrumb path from the root to the folder, inclusive. The

        first element is the top-level ancestor and the last element is the
        folder

        itself.


        Requires a **user** API key with access to the folder. Ancestors you
        cannot

        access appear with `isAccessible: false`.
      operationId: getFolderPath
      tags:
        - Folder
      parameters:
        - name: folderId
          in: path
          required: true
          description: Folder ID
          schema:
            type: string
          example: '12345'
      responses:
        '200':
          description: Breadcrumb path (root first, folder last)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SimpleListResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/FolderPathNode'
              example:
                content:
                  - id: '12300'
                    title: Team Root
                    isAccessible: true
                  - id: '12345'
                    title: Weekly Team Meetings
                    isAccessible: true
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — no access to this folder
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Folder not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/folders/{folderId}/move:
    put:
      summary: Move Folder
      description: >
        Move a folder under a new parent, or to the root level with

        `newParentId: null`. The target parent must be in the same workspace and
        you

        must have access to it. You cannot move a folder into its own subtree.


        Use `sharingTypeUpdateStrategy` to control how the folder's sharing

        permissions are handled after the move (defaults to `KEEP_EXISTING`).


        Requires edit access to the folder.
      operationId: moveFolder
      tags:
        - Folder
      parameters:
        - name: folderId
          in: path
          required: true
          description: Folder ID to move
          schema:
            type: string
          example: '12345'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MoveFolderRequest'
            examples:
              moveUnderParent:
                summary: Move under another folder (keep permissions)
                value:
                  newParentId: '98765'
                  sharingTypeUpdateStrategy: KEEP_EXISTING
              moveAndInherit:
                summary: Move under another folder and inherit its permissions
                value:
                  newParentId: '98765'
                  sharingTypeUpdateStrategy: INHERIT_FROM_PARENT
              moveToRoot:
                summary: Move to the root level
                value:
                  newParentId: null
      responses:
        '200':
          description: Folder moved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FolderDetail'
              example:
                id: '12345'
                workspaceGuid: ws_a1b2c3d4
                title: Weekly Team Meetings
                description: Notes from our weekly sync
                sharingType: ALL_MEMBER_VIEWER
                parentId: '98765'
                color: '#4A90D9'
                isTeamFolder: true
                createdAt: '2025-01-15T10:30:00Z'
                updatedAt: '2025-01-20T12:00:00Z'
        '400':
          description: >-
            Bad request — target parent not found or in a different workspace, a
            circular move into the folder's own subtree, or the move would nest
            folders more than 5 levels below the root level
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — no edit access to the folder or the target parent
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Folder not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/folders/reorder:
    post:
      summary: Reorder Folders
      description: >
        Set the display order of sibling folders. Provide every sibling's ID in
        the

        desired order; positions are assigned by array index. The workspace is

        inferred from the first folder ID.


        Requires edit access.
      operationId: reorderFolders
      tags:
        - Folder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReorderFoldersRequest'
            example:
              orderedFolderIds:
                - '12346'
                - '12345'
                - '12347'
      responses:
        '204':
          description: Display order updated
        '400':
          description: >-
            Bad request — empty list, duplicate IDs, folders not found, or
            folders span more than one workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — no edit access
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The first folder in the list was not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/folders/{folderId}/notes:
    post:
      summary: Attach Note to Folder
      description: |
        Add an existing note to the folder. The note must belong to the same
        workspace as the folder. Requires edit access to the folder.

        Attaching a note that is already in the folder succeeds with no effect,
        so the call is safe to retry.
      operationId: attachNoteToFolder
      tags:
        - Folder
      parameters:
        - name: folderId
          in: path
          required: true
          description: Folder ID
          schema:
            type: string
          example: '12345'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttachNoteRequest'
            example:
              noteGuid: note-abc123-def456
      responses:
        '204':
          description: Note attached
        '400':
          description: Bad request — the note belongs to a different workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — no edit access to this folder
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Folder or note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/folders/{folderId}/notes/{noteGuid}:
    delete:
      summary: Detach Note from Folder
      description: |
        Remove a note from the folder. This does not delete the note itself.
        Requires edit access to the folder.
      operationId: detachNoteFromFolder
      tags:
        - Folder
      parameters:
        - name: folderId
          in: path
          required: true
          description: Folder ID
          schema:
            type: string
          example: '12345'
        - name: noteGuid
          in: path
          required: true
          description: Note GUID
          schema:
            type: string
          example: note-abc123-def456
      responses:
        '204':
          description: Note detached
        '401':
          description: Unauthorized — missing API key, or a team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — no edit access to this folder
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Folder or note not found, or the note is not attached to this folder
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/{noteGuid}/folders:
    get:
      summary: List Folders by Note
      description: Retrieve folders for a specific note
      operationId: listFoldersByNote
      tags:
        - Folder
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
      responses:
        '200':
          description: List of folders
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SimpleListResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/Folder'
              examples:
                success:
                  summary: Successful folders list
                  value:
                    content:
                      - id: '12345'
                        title: Project Discussion
                        workspaceGuid: ws_a1b2c3d4
                        isTeamFolder: true
                      - id: '12346'
                        title: Daily Standup
                        workspaceGuid: ws_a1b2c3d4
                        isTeamFolder: true
                empty:
                  summary: Empty folders list
                  value:
                    content: []
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/voice-file/jobs:
    post:
      summary: Create Voice File Job
      description: >
        Create a new Voice File Job for audio transcription and optional
        translation.


        - Returns a presigned upload URI for your audio file

        - Optionally specify source language hints and target translation
        locales

        - Job starts in `CREATED` status — upload your file to begin processing

        - Requires a user or system API key bound to a workspace where Voice
        File Jobs are enabled


        Documentation: [Complete workflow guide with code
        examples](/voice-file/tutorial)
      operationId: createVoiceFileJob
      tags:
        - Voice File
      requestBody:
        description: >
          Optional parameters for transcription and translation.


          - If `transcriptLocaleHints` is omitted, language is auto-detected
          from audio

          - If `translationLocales` is omitted, no translations are generated
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                transcriptLocaleHints:
                  type: array
                  items:
                    type: string
                  maxItems: 1
                  description: |
                    Locale hints for transcription.
                    - Maximum 1 locale
                    - If omitted, language is auto-detected from audio content
                  example:
                    - en_US
                translationLocales:
                  type: array
                  items:
                    type: string
                  maxItems: 5
                  description: Optional locales for translation (max 5)
                  example:
                    - ko_KR
                    - ja_JP
      responses:
        '201':
          description: Job created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceFileJobCreated'
              examples:
                korean_to_english:
                  summary: Korean audio with English translation
                  value:
                    id: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
                    uploadUri: https://storage.example.com/upload/signed-url-abc123
                multilingual:
                  summary: English audio with multiple translations
                  value:
                    id: c3e2bc43-4gf3-5312-c1c5-402bcecbb134
                    uploadUri: https://storage.example.com/upload/signed-url-xyz789
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >
            `403000 forbidden` when the key is not workspace-bound or the
            workspace policy is disabled. Bind the key to an enabled workspace
            or ask a Tiro administrator to enable Voice File Jobs.


            `403013 forbidden` when the key lacks `voice_file_job:write`.
            Reissue the key with the required scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/voice-file/jobs/{jobId}/upload-complete:
    put:
      summary: Notify Upload Complete
      description: >
        Notify that audio file upload is complete and start processing.


        - Call this after uploading your file to the presigned URL from Create
        Voice File Job

        - Triggers the transcription (and optional translation) pipeline

        - Job status transitions: `CREATED` → `UPLOADED` → `PROCESSING`


        Documentation: [Step-by-step upload
        guide](/voice-file/tutorial#step-3-notify-upload-completion)
      operationId: notifyUploadComplete
      tags:
        - Voice File
      parameters:
        - name: jobId
          in: path
          description: The job ID returned from Create Voice File Job
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Upload notification received. No response body.
        '401':
          description: >
            `401009 unauthorized` when the API key is missing or invalid. Send a
            valid key in the Authorization header.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/voice-file/jobs/{jobId}:
    get:
      summary: Get Voice File Job
      description: >
        Retrieve the current status and details of a Voice File Job.


        - Poll this endpoint until status reaches `COMPLETED` or `FAILED`

        - Once completed, use the transcript and translation endpoints to
        retrieve results


        Documentation: [Polling strategy and status
        meanings](/voice-file/overview#polling-strategy-recommended)
      operationId: getVoiceFileJob
      tags:
        - Voice File
      parameters:
        - name: jobId
          in: path
          description: The job ID returned from Create Voice File Job
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Job details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceFileJob'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete Voice File Job
      description: >
        Delete a Voice File Job in any status, including while processing.


        Tiro removes the uploaded audio, transcript, and translations. The
        deleted job is no longer available through the API, and processing
        callbacks that arrive after deletion are ignored.
      operationId: deleteVoiceFileJob
      tags:
        - Voice File
      parameters:
        - name: jobId
          in: path
          description: The job ID returned from Create Voice File Job
          required: true
          schema:
            type: string
            example: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
      responses:
        '204':
          description: Job deleted successfully. No response body.
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >
            `403013 forbidden` when the key lacks `voice_file_job:write`.
            Reissue the key with the required scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: >
            `404030 not_found` when the job does not exist or the key cannot
            access it. Verify the job ID and use a key bound to the job's
            workspace.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/voice-file/jobs/{jobId}/transcript:
    get:
      summary: Get Transcript
      description: >
        Retrieve the transcribed text from a completed Voice File Job.


        - Job status must be `COMPLETED`

        - Returns the full transcript text and detected locales


        Documentation: [How to retrieve
        results](/voice-file/tutorial#step-5-retrieve-results)
      operationId: getTranscript
      tags:
        - Voice File
      parameters:
        - name: jobId
          in: path
          description: The job ID returned from Create Voice File Job
          required: true
          schema:
            type: string
            example: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
      responses:
        '200':
          description: Transcript data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transcript'
              example:
                jobId: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
                locales:
                  - en_US
                text: Hello everyone, welcome to today's meeting...
                segments:
                  - startTimeMillis: 0
                    endTimeMillis: 2300
                    text: Hello everyone, welcome to today's meeting.
                    speakerLabel: speaker-1
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Job or transcript not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/voice-file/jobs/{jobId}/translations:
    get:
      summary: List Translations
      description: >
        List all translations generated for a Voice File Job.


        - Job status must be `COMPLETED`

        - Requires `translationLocales` to have been set during job creation

        - Returns translations for all requested locales


        Documentation: [How to retrieve
        translations](/voice-file/tutorial#step-5-retrieve-results)
      operationId: listTranslations
      tags:
        - Voice File
      parameters:
        - name: jobId
          in: path
          description: The job ID returned from Create Voice File Job
          required: true
          schema:
            type: string
      responses:
        '200':
          description: List of translations
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Translation'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/voice-file/jobs/{jobId}/translations/{locale}:
    get:
      summary: Get Translation
      description: >
        Retrieve a specific translation by locale.


        - More efficient than listing all translations when you know the target
        locale

        - Job status must be `COMPLETED`


        Documentation: [Supported locales](/fundamentals/supported-locales)
      operationId: getTranslation
      tags:
        - Voice File
      parameters:
        - name: jobId
          in: path
          description: The job ID returned from Create Voice File Job
          required: true
          schema:
            type: string
        - name: locale
          in: path
          description: Target locale code (e.g., ko_KR, en_US, ja_JP)
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Translation data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Translation'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Job or translation not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/voice-file/jobs/{jobId}/transcript/paragraph-summary:
    get:
      summary: Get Transcript Paragraph Summary
      description: >
        Retrieve AI-generated paragraph summaries from the transcript.


        - Provides a quick content overview in markdown format

        - Summaries are generated in the transcript's original language


        Documentation: [Paragraph Summary
        feature](/voice-file/overview#paragraph-summary-feature)
      operationId: getTranscriptParagraphSummary
      tags:
        - Voice File
      parameters:
        - name: jobId
          in: path
          description: The job ID returned from Create Voice File Job
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Transcript paragraph summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ParagraphSummary'
              examples:
                success:
                  summary: Successful paragraph summary retrieval
                  value:
                    jobId: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
                    locale: ko_KR
                    summary:
                      type: text/markdown
                      content: >-
                        ### 회의는 프로젝트 진행 상황을 점검하고, 다음 단계에 대한 계획을 수립하는 데 중점을
                        두었습니다.
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Job or summary not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/voice-file/jobs/{jobId}/translations/{locale}/paragraph-summary:
    get:
      summary: Get Translation Paragraph Summary
      description: >
        Retrieve AI-generated paragraph summaries from a translated version.


        - Summaries are generated in the target translation language

        - Requires the translation to exist for the specified locale


        Documentation: [Paragraph Summary
        feature](/voice-file/overview#paragraph-summary-feature)
      operationId: getTranslationParagraphSummary
      tags:
        - Voice File
      parameters:
        - name: jobId
          in: path
          description: The job ID returned from Create Voice File Job
          required: true
          schema:
            type: string
        - name: locale
          in: path
          description: Target locale code (e.g., ko_KR, en_US, ja_JP)
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Translation paragraph summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ParagraphSummary'
              examples:
                success:
                  summary: Successful paragraph summary retrieval
                  value:
                    jobId: b2d1ab32-3fe2-4201-b0b4-391abdbaa023
                    locale: en_US
                    summary:
                      type: text/markdown
                      content: >-
                        ### The meeting focused on reviewing project progress
                        and planning the next steps.
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Job, translation, or summary not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/{noteGuid}/documents:
    post:
      summary: Generate Note Document
      description: >
        Generate a note document based on a template.


        - Blocks until document generation is complete (synchronous)

        - Requires `UPDATE_CONTENT` permission on the note

        - User must own the template or have team access


        See [Template Based
        Documents](/template-based-documents/summary-and-document) for more
        details.
      operationId: generateNoteDocument
      tags:
        - Note Document
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
          example: abc123xyz
        - name: format
          in: query
          description: Content format for generated sections
          required: false
          schema:
            type: string
            enum:
              - text/plain
              - text/markdown
            default: text/markdown
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GenerateNoteDocumentRequest'
            example:
              templateId: 1
              locale: ko_KR
      responses:
        '200':
          description: Document generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteDocument'
              example:
                id: 456
                noteGuid: note-abc123-def456
                note:
                  guid: note-abc123-def456
                  webUrl: https://tiro.ooo/n/xQ8YKnZUPGHNB
                template:
                  id: 1
                  title: 영업 보고서
                locale: ko_KR
                sections:
                  - content:
                      type: text/plain
                      content: 회의는 신제품 출시 계획에 대해 논의했습니다...
                    createdAt: '2025-10-20T12:35:26Z'
                createdAt: '2025-10-20T12:35:26Z'
                updatedAt: '2025-10-20T12:35:26Z'
        '400':
          description: Invalid template or parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      summary: List Note Documents
      description: >
        List all documents generated for a specific note.


        See [Template Based
        Documents](/template-based-documents/summary-and-document) for more
        details.
      operationId: listNoteDocuments
      tags:
        - Note Document
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
          example: abc123xyz
        - name: templateId
          in: query
          description: Filter by template ID
          required: false
          schema:
            type: integer
            format: int64
          example: 1
      responses:
        '200':
          description: List of documents
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteDocumentListResponse'
              example:
                content:
                  - id: 456
                    template:
                      id: 1
                      title: 영업 보고서
                    locale: ko_KR
                    createdAt: '2025-10-20T12:35:26Z'
                    updatedAt: '2025-10-20T13:45:30Z'
                  - id: 457
                    template:
                      id: 1
                      title: 영업 보고서
                    locale: en_US
                    createdAt: '2025-10-20T11:20:15Z'
                    updatedAt: '2025-10-20T11:20:15Z'
                totalSize: 2
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/{noteGuid}/documents/{documentId}:
    get:
      summary: Get Note Document
      description: >
        Retrieve a specific note document by ID.


        See [Template Based
        Documents](/template-based-documents/summary-and-document) for more
        details.
      operationId: getNoteDocument
      tags:
        - Note Document
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
          example: abc123xyz
        - name: documentId
          in: path
          description: Document ID
          required: true
          schema:
            type: integer
            format: int64
          example: 456
        - name: format
          in: query
          description: Response format
          required: false
          schema:
            type: string
            enum:
              - text/plain
              - text/markdown
            default: text/markdown
      responses:
        '200':
          description: Document details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteDocument'
              example:
                id: 456
                noteGuid: note-abc123-def456
                note:
                  guid: note-abc123-def456
                  webUrl: https://tiro.ooo/n/xQ8YKnZUPGHNB
                template:
                  id: 1
                  title: 영업 보고서
                locale: ko_KR
                sections:
                  - content:
                      type: text/plain
                      content: 회의는 신제품 출시 계획에 대해 논의했습니다...
                    createdAt: '2025-10-20T12:35:26Z'
                  - content:
                      type: text/plain
                      content: |-
                        - 다음 주까지 견적서 발송
                        - 담당자 배정
                    createdAt: '2025-10-20T12:35:26Z'
                createdAt: '2025-10-20T12:35:26Z'
                updatedAt: '2025-10-20T13:45:30Z'
            text/markdown:
              schema:
                type: string
              example: |
                # 영업 보고서

                회의는 신제품 출시 계획에 대해 논의했습니다...

                ## 액션 아이템
                - 다음 주까지 견적서 발송
                - 담당자 배정
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Document not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/{noteGuid}/summaries:
    get:
      summary: List Note Summaries
      description: >
        List all summaries generated for a specific note.


        - Returns summary metadata without content

        - To retrieve the full summary content, use the Get Note Summary
        endpoint


        See [Template Based
        Documents](/template-based-documents/summary-and-document) for more
        details.
      operationId: listNoteSummaries
      tags:
        - Note Summary
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
          example: abc123xyz
      responses:
        '200':
          description: List of summaries
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteSummaryListResponse'
              example:
                content:
                  - id: 123
                    template:
                      id: 1
                      title: One-Pager
                    locale: ko_KR
                    createdAt: '2025-12-12T12:00:00Z'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/notes/{noteGuid}/summaries/{summaryId}:
    get:
      summary: Get Note Summary
      description: >
        Retrieve a specific summary with full content.


        - Default format: Markdown (`text/markdown`)

        - Use the `format` query parameter to request `text/plain` instead


        See [Template Based
        Documents](/template-based-documents/summary-and-document) for more
        details.
      operationId: getNoteSummary
      tags:
        - Note Summary
      parameters:
        - name: noteGuid
          in: path
          description: Note GUID
          required: true
          schema:
            type: string
          example: abc123xyz
        - name: summaryId
          in: path
          description: Summary ID from list endpoint
          required: true
          schema:
            type: integer
            format: int64
          example: 123
        - name: format
          in: query
          description: Content format
          required: false
          schema:
            type: string
            enum:
              - text/markdown
              - text/plain
            default: text/markdown
          example: text/markdown
      responses:
        '200':
          description: Summary with full content
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteSummary'
              example:
                id: 123
                noteGuid: note-abc123-def456
                note:
                  guid: note-abc123-def456
                  webUrl: https://tiro.ooo/n/xQ8YKnZUPGHNB
                template:
                  id: 1
                  title: One-Pager
                locale: ko_KR
                content:
                  type: text/markdown
                  content: |-
                    # Meeting Summary

                    ## Key Points
                    - Discussed Q4 roadmap
                    - Budget approved...
                createdAt: '2025-12-12T12:00:00Z'
                updatedAt: '2025-12-12T12:00:00Z'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Note or summary not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/note-document-templates:
    get:
      summary: List Note Document Templates
      description: >
        Retrieve all available note document templates.


        See [Template Based
        Documents](/template-based-documents/summary-and-document) for more
        details.
      operationId: listNoteDocumentTemplates
      tags:
        - Note Document Template
      responses:
        '200':
          description: List of note document templates
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteDocumentTemplateListResponse'
              example:
                content:
                  - id: 1
                    title: 회의록
                    description: 회의 내용을 체계적으로 정리하는 템플릿
                    sections:
                      - id: 1
                        title: 주요 논의 사항
                        sectionType: PLAIN_TEXT
                        userInstruction: 회의에서 논의된 핵심 주제를 요약해주세요
                      - id: 2
                        title: 액션 아이템
                        sectionType: ACTION_ITEMS
                        userInstruction: 회의에서 결정된 실행 항목을 정리해주세요
                    favorite: false
                    isManaged: true
                    isEditable: false
                    createdAt: '2025-10-20T12:35:26Z'
                  - id: 2
                    title: 영업 보고서
                    description: 영업 활동 내용을 정리하는 템플릿
                    sections:
                      - id: 3
                        title: 영업 개요
                        sectionType: PLAIN_TEXT
                        userInstruction: 영업 활동의 전반적인 내용을 요약해주세요
                    favorite: false
                    isManaged: true
                    isEditable: false
                    createdAt: '2025-10-20T11:20:15Z'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/note-document-templates/{templateId}:
    get:
      summary: Get Note Document Template
      description: >
        Retrieve a specific note document template by ID.


        See [Template Based
        Documents](/template-based-documents/summary-and-document) for more
        details.
      operationId: getNoteDocumentTemplate
      tags:
        - Note Document Template
      parameters:
        - name: templateId
          in: path
          description: Template ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      responses:
        '200':
          description: Template details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteDocumentTemplate'
              example:
                id: 1
                title: 회의록
                description: 회의 내용을 체계적으로 정리하는 템플릿
                sections:
                  - id: 1
                    title: 주요 논의 사항
                    sectionType: PLAIN_TEXT
                    userInstruction: 회의에서 논의된 핵심 주제를 요약해주세요
                  - id: 2
                    title: 액션 아이템
                    sectionType: ACTION_ITEMS
                    userInstruction: 회의에서 결정된 실행 항목을 정리해주세요
                favorite: false
                isManaged: true
                isEditable: false
                createdAt: '2025-10-20T12:35:26Z'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Template not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/users/me/word-memories:
    get:
      summary: List User Word Memories
      description: >
        Retrieve user word memories with cursor-based pagination.


        Word memories help Tiro accurately recognize important terms — such as
        company names, people's names, and product names — during voice
        transcription. Registered words are referenced in real-time to reduce
        transcription errors.


        - Use `cursor` from previous response's `nextCursor` to paginate through
        results
      operationId: listUserWordMemories
      tags:
        - Word Memory
      parameters:
        - name: cursor
          in: query
          description: >-
            Cursor for the next page. Obtained from `nextCursor` in previous
            response.
          required: false
          schema:
            type: string
        - name: size
          in: query
          description: Number of word memories to return per page
          required: false
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
      responses:
        '200':
          description: Paginated list of user word memories
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PageCursorResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/WordMemory'
              examples:
                success:
                  summary: Word memories list
                  value:
                    content:
                      - id: 1
                        entry: 인공지능
                        createdAt: '2026-04-01T10:30:00Z'
                      - id: 2
                        entry: Tiro
                        createdAt: '2026-04-01T10:35:00Z'
                    nextCursor: eyJpZCI6MiwiY3JlYXRlZEF0IjoiMjAyNi0wNC0wMVQxMDozNTowMFoifQ
                empty:
                  summary: Empty list
                  value:
                    content: []
                    nextCursor: null
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      summary: Create User Word Memory
      description: >
        Register a new word to the user's personal word memory.


        Once registered, Tiro references this word during voice transcription to
        improve recognition accuracy. Useful for proper nouns, technical terms,
        or any word that standard speech-to-text may not recognize correctly.


        Duplicate entries (same `entry` value) are not allowed and will return
        `409 Conflict`.
      operationId: createUserWordMemory
      tags:
        - Word Memory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWordMemoryRequest'
            examples:
              properNoun:
                summary: Register a proper noun
                value:
                  entry: 인공지능
              companyName:
                summary: Register a company name
                value:
                  entry: Tiro
      responses:
        '201':
          description: Word memory created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 인공지능
                createdAt: '2026-04-01T10:30:00Z'
        '400':
          description: Bad request — entry is blank
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Conflict — a word memory with the same entry already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/users/me/word-memories/{wordMemoryId}:
    get:
      summary: Get User Word Memory
      description: Retrieve a specific word memory by ID
      operationId: getUserWordMemory
      tags:
        - Word Memory
      parameters:
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      responses:
        '200':
          description: Word memory details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 인공지능
                createdAt: '2026-04-01T10:30:00Z'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    patch:
      summary: Update User Word Memory
      description: |
        Update an existing word memory.

        Only provided fields will be updated (partial update).
      operationId: updateUserWordMemory
      tags:
        - Word Memory
      parameters:
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWordMemoryRequest'
            example:
              entry: 머신러닝
      responses:
        '200':
          description: Word memory updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 머신러닝
                createdAt: '2026-04-01T10:30:00Z'
        '400':
          description: Bad request — entry is blank
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Conflict — a word memory with the same entry already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete User Word Memory
      description: >
        Delete a word memory. This action is irreversible.


        Once deleted, Tiro will no longer reference this word during
        transcription.
      operationId: deleteUserWordMemory
      tags:
        - Word Memory
      parameters:
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      responses:
        '204':
          description: Word memory deleted successfully. No response body.
          x-example-description: Returns HTTP 204 with an empty response body.
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/teams/me/word-memories:
    get:
      summary: List Team Word Memories
      deprecated: true
      description: >
        **Deprecated — removed on 2026-06-30.** Use `GET
        /v1/external/workspaces/{workspaceGuid}/word-memories` instead, which
        targets a workspace explicitly by path. Responses to this endpoint carry
        `Deprecation`, `Link` (successor), and `Sunset` headers. Behavior is
        unchanged until the sunset date.


        Retrieve team word memories with cursor-based pagination.


        Team word memories are shared among all team members. When any member
        records a meeting, Tiro references both personal and team word memories
        for accurate transcription. New team members automatically benefit from
        the shared vocabulary without additional setup.


        - Use `cursor` from previous response's `nextCursor` to paginate through
        results
      operationId: listTeamWordMemories
      tags:
        - Word Memory
      parameters:
        - name: cursor
          in: query
          description: >-
            Cursor for the next page. Obtained from `nextCursor` in previous
            response.
          required: false
          schema:
            type: string
        - name: size
          in: query
          description: Number of word memories to return per page
          required: false
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
      responses:
        '200':
          description: Paginated list of team word memories
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PageCursorResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/WordMemory'
              examples:
                success:
                  summary: Team word memories list
                  value:
                    content:
                      - id: 1
                        entry: 딥러닝
                        createdAt: '2026-04-01T10:30:00Z'
                      - id: 2
                        entry: 자연어처리
                        createdAt: '2026-04-01T10:35:00Z'
                    nextCursor: eyJpZCI6MiwiY3JlYXRlZEF0IjoiMjAyNi0wNC0wMVQxMDozNTowMFoifQ
                empty:
                  summary: Empty list
                  value:
                    content: []
                    nextCursor: null
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      summary: Create Team Word Memory
      deprecated: true
      description: >
        **Deprecated — removed on 2026-06-30.** Use `POST
        /v1/external/workspaces/{workspaceGuid}/word-memories` instead. Behavior
        is unchanged until the sunset date.


        Register a new word to the team's shared word memory.


        Team word memories are accessible to all team members. Once registered,
        Tiro references this word during voice transcription for any team
        member's recording.


        Duplicate entries (same `entry` value) are not allowed and will return
        `409 Conflict`.
      operationId: createTeamWordMemory
      tags:
        - Word Memory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWordMemoryRequest'
            examples:
              technicalTerm:
                summary: Register a technical term
                value:
                  entry: 딥러닝
              productName:
                summary: Register a product name
                value:
                  entry: 자연어처리
      responses:
        '201':
          description: Team word memory created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 딥러닝
                createdAt: '2026-04-01T10:30:00Z'
        '400':
          description: Bad request — entry is blank
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Conflict — a team word memory with the same entry already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/teams/me/word-memories/{wordMemoryId}:
    get:
      summary: Get Team Word Memory
      deprecated: true
      description: >
        **Deprecated — removed on 2026-06-30.** Use `GET
        /v1/external/workspaces/{workspaceGuid}/word-memories/{wordMemoryId}`
        instead. Behavior is unchanged until the sunset date.


        Retrieve a specific team word memory by ID.
      operationId: getTeamWordMemory
      tags:
        - Word Memory
      parameters:
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      responses:
        '200':
          description: Team word memory details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 딥러닝
                createdAt: '2026-04-01T10:30:00Z'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Team word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    patch:
      summary: Update Team Word Memory
      deprecated: true
      description: >
        **Deprecated — removed on 2026-06-30.** Use `PATCH
        /v1/external/workspaces/{workspaceGuid}/word-memories/{wordMemoryId}`
        instead. Behavior is unchanged until the sunset date.


        Update an existing team word memory.


        Only provided fields will be updated (partial update).
      operationId: updateTeamWordMemory
      tags:
        - Word Memory
      parameters:
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWordMemoryRequest'
            example:
              entry: 자연어처리
      responses:
        '200':
          description: Team word memory updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 자연어처리
                createdAt: '2026-04-01T10:30:00Z'
        '400':
          description: Bad request — entry is blank
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Team word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Conflict — a team word memory with the same entry already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete Team Word Memory
      deprecated: true
      description: >
        **Deprecated — removed on 2026-06-30.** Use `DELETE
        /v1/external/workspaces/{workspaceGuid}/word-memories/{wordMemoryId}`
        instead. Behavior is unchanged until the sunset date.


        Delete a team word memory. This action is irreversible.


        Once deleted, Tiro will no longer reference this word during
        transcription for any team member.
      operationId: deleteTeamWordMemory
      tags:
        - Word Memory
      parameters:
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      responses:
        '204':
          description: Team word memory deleted successfully. No response body.
          x-example-description: Returns HTTP 204 with an empty response body.
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Team word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/word-memories:
    get:
      summary: List Workspace Word Memories
      description: >
        List a workspace's shared word memories with cursor-based pagination.
        Name the target workspace in the path with its `workspaceGuid` — obtain
        it from `GET /v1/external/workspaces`.


        Workspace word memories are shared among all workspace members. When any
        member records a meeting, Tiro references both personal and workspace
        word memories for accurate transcription. New members benefit from the
        shared vocabulary without additional setup.


        Use a **user** or **workspace-bound** API key. A workspace-bound key
        must match the `workspaceGuid` in the path, or it returns `403`. A user
        key must belong to a member of the workspace, or it returns `403`.


        - Use `cursor` from the previous response's `nextCursor` to paginate
        through results.
      operationId: listWorkspaceWordMemories
      tags:
        - Word Memory
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
        - name: cursor
          in: query
          description: >-
            Cursor for the next page. Obtained from `nextCursor` in the previous
            response.
          required: false
          schema:
            type: string
        - name: size
          in: query
          description: Number of word memories to return per page
          required: false
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
      responses:
        '200':
          description: Paginated list of workspace word memories
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PageCursorResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/WordMemory'
              examples:
                success:
                  summary: Workspace word memories list
                  value:
                    content:
                      - id: 1
                        entry: 딥러닝
                        createdAt: '2026-04-01T10:30:00Z'
                      - id: 2
                        entry: 자연어처리
                        createdAt: '2026-04-01T10:35:00Z'
                    nextCursor: eyJpZCI6MiwiY3JlYXRlZEF0IjoiMjAyNi0wNC0wMVQxMDozNTowMFoifQ
                empty:
                  summary: Empty list
                  value:
                    content: []
                    nextCursor: null
        '401':
          description: Unauthorized — missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden — the API key is not scoped to this workspace, or you are
            not a member of it
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Workspace not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      summary: Create Workspace Word Memory
      description: >
        Register a new word to a workspace's shared word memory. Name the target
        workspace in the path with its `workspaceGuid`.


        Workspace word memories are accessible to all workspace members. Once
        registered, Tiro references this word during voice transcription for any
        member's recording.


        Requires a **user** API key — you must be a writable member of the
        workspace. A workspace-bound key must also match the `workspaceGuid` in
        the path. A system or team-only key (no user identity) returns `401`.


        Duplicate entries (same `entry` value) are not allowed and return `409
        Conflict`.
      operationId: createWorkspaceWordMemory
      tags:
        - Word Memory
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWordMemoryRequest'
            examples:
              technicalTerm:
                summary: Register a technical term
                value:
                  entry: 딥러닝
              productName:
                summary: Register a product name
                value:
                  entry: 자연어처리
      responses:
        '201':
          description: Workspace word memory created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 딥러닝
                createdAt: '2026-04-01T10:30:00Z'
        '400':
          description: Bad request — entry is blank
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing API key, or a system/team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden — the API key is not scoped to this workspace, or you are
            not a writable member of it
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Workspace not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            Conflict — a workspace word memory with the same entry already
            exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/word-memories/{wordMemoryId}:
    get:
      summary: Get Workspace Word Memory
      description: >
        Retrieve a specific workspace word memory by ID.


        Use a **user** or **workspace-bound** API key. A workspace-bound key
        must match the `workspaceGuid` in the path, or it returns `403`. A user
        key must belong to a member of the workspace, or it returns `403`.
      operationId: getWorkspaceWordMemory
      tags:
        - Word Memory
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      responses:
        '200':
          description: Workspace word memory details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 딥러닝
                createdAt: '2026-04-01T10:30:00Z'
        '401':
          description: Unauthorized — missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden — the API key is not scoped to this workspace, or you are
            not a member of it
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Workspace or word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    patch:
      summary: Update Workspace Word Memory
      description: >
        Update an existing workspace word memory. Only provided fields are
        updated (partial update).


        Requires a **user** API key — you must be a writable member of the
        workspace. A workspace-bound key must also match the `workspaceGuid` in
        the path. A system or team-only key (no user identity) returns `401`.
      operationId: updateWorkspaceWordMemory
      tags:
        - Word Memory
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWordMemoryRequest'
            example:
              entry: 자연어처리
      responses:
        '200':
          description: Workspace word memory updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WordMemory'
              example:
                id: 1
                entry: 자연어처리
                createdAt: '2026-04-01T10:30:00Z'
        '400':
          description: Bad request — entry is blank
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — missing API key, or a system/team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden — the API key is not scoped to this workspace, or you are
            not a writable member of it
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Workspace or word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            Conflict — a workspace word memory with the same entry already
            exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete Workspace Word Memory
      description: >
        Delete a workspace word memory. This action is irreversible. Once
        deleted, Tiro no longer references this word during transcription for
        any workspace member.


        Requires a **user** API key — you must be a writable member of the
        workspace. A workspace-bound key must also match the `workspaceGuid` in
        the path. A system or team-only key (no user identity) returns `401`.
      operationId: deleteWorkspaceWordMemory
      tags:
        - Word Memory
      parameters:
        - name: workspaceGuid
          in: path
          required: true
          description: Workspace GUID. Obtain it from `GET /v1/external/workspaces`.
          schema:
            type: string
          example: ws_a1b2c3d4
        - name: wordMemoryId
          in: path
          description: Word memory ID
          required: true
          schema:
            type: integer
            format: int64
          example: 1
      responses:
        '204':
          description: Workspace word memory deleted successfully. No response body.
          x-example-description: Returns HTTP 204 with an empty response body.
        '401':
          description: Unauthorized — missing API key, or a system/team-only key was used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden — the API key is not scoped to this workspace, or you are
            not a writable member of it
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Workspace or word memory not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces:
    get:
      summary: List Workspaces
      description: >
        List all workspaces accessible to the caller's API key or OAuth token.


        Resolution order:

        1. Workspace-bound API key → the single bound workspace

        2. Organization-bound API key → all active workspaces in the
        organization

        3. Legacy team API key → the team's workspace

        4. Personal/OAuth key → all workspaces the user is a member of


        Use this endpoint to enumerate workspaces when your account belongs to
        multiple workspaces,

        then pass the chosen workspace `guid` to the wiki endpoints.
      operationId: listWorkspaces
      tags:
        - Wiki
      responses:
        '200':
          description: List of accessible workspaces
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalWorkspaceListResponse'
              example:
                workspaces:
                  - guid: ws_abc123
                    name: Acme Corp
                    isWikiEnabled: true
                  - guid: ws_def456
                    name: Personal
                    isWikiEnabled: false
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/me:
    get:
      summary: Get My Workspace
      description: >
        Retrieve the single workspace implicit in the caller's API key.


        Resolution follows the same order as `GET /v1/external/workspaces`:

        1. Workspace-bound key → that workspace's GUID

        2. Legacy team key → the team's workspace GUID

        3. Personal/OAuth key → the user's default workspace GUID


        Used by the MCP server and CLI to fill the `{workspaceGuid}` path
        segment

        without requiring the caller to pass a workspace parameter explicitly.
      operationId: getMyWorkspace
      tags:
        - Wiki
      responses:
        '200':
          description: The caller's implicit workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceMeResponse'
              example:
                guid: ws_abc123
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: No workspace is associated with this API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/organizations/me:
    get:
      summary: Get My Organization
      description: >
        Retrieve the organization bound to the caller's API key. Requires an

        organization API key — keys issued by an organization admin from the

        organization console. Personal, workspace, and legacy team keys return
        `401`.


        Organization API keys carry fixed scopes (for example
        `note_document:write`)

        and can reach the notes in every workspace that belongs to the
        organization.

        Use this endpoint to verify which organization your key is bound to.
      operationId: getMyOrganization
      tags:
        - Organization
      responses:
        '200':
          description: The organization bound to the API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationMeResponse'
              example:
                guid: og_a1b2c3d4
                name: LG Uplus
        '401':
          description: Unauthorized — missing key, invalid key, or not an organization key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/organizations/me/notes:
    get:
      summary: List Organization Notes
      description: >
        List ended notes in the workspaces of the organization bound to the API
        key,

        with cursor-based pagination. A note is "ended" when its recording has

        finished (`recordingEndAt` is set) — the same condition that fires the

        `note.ended` webhook event.


        Filter by `endedAfter` / `endedBefore` (ISO 8601, applied to

        `recordingEndAt`) to bound the window. Results are ordered by note ID

        descending (newest-created first) with an ID-based cursor; the time

        filters bound the window, they do not change the sort order.
      operationId: listOrganizationNotes
      tags:
        - Organization
      parameters:
        - name: endedAfter
          in: query
          description: >-
            ISO 8601 datetime — return only notes with `recordingEndAt >=` this
            value.
          required: false
          schema:
            type: string
            format: date-time
          example: '2026-07-01T00:00:00Z'
        - name: endedBefore
          in: query
          description: >-
            ISO 8601 datetime — return only notes with `recordingEndAt <` this
            value.
          required: false
          schema:
            type: string
            format: date-time
          example: '2026-07-08T00:00:00Z'
        - name: cursor
          in: query
          description: Cursor for the next page
          required: false
          schema:
            type: string
        - name: size
          in: query
          description: Page size (default 100, max 200)
          required: false
          schema:
            type: integer
            default: 100
            minimum: 1
            maximum: 200
      responses:
        '200':
          description: List of ended notes in the organization's workspaces
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PageCursorResponse'
                  - type: object
                    properties:
                      content:
                        type: array
                        items:
                          $ref: '#/components/schemas/Note'
              examples:
                success:
                  summary: Successful notes list
                  value:
                    content:
                      - guid: note-abc123-def456
                        workspaceGuid: ws_a1b2c3d4
                        title: OO기업 AX 도입 미팅
                        createdAt: '2026-07-03T05:10:00Z'
                        updatedAt: '2026-07-03T05:41:02Z'
                        sourceType: live-voice
                        recordingStartAt: '2026-07-03T05:10:00Z'
                        recordingEndAt: '2026-07-03T05:40:20Z'
                        recordingDurationSeconds: 1820
                        transcribeLocale: ko_KR
                        webUrl: https://tiro.ooo/n/abc123def456
                        collaborators: []
                        participants: []
                    nextCursor: cursor_string
                empty:
                  summary: Empty notes list
                  value:
                    content: []
                    nextCursor: null
        '401':
          description: Unauthorized — missing key, invalid key, or not an organization key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki:
    get:
      summary: Get Wiki Info
      description: >
        Retrieve metadata for the workspace's wiki (name, creation timestamp,
        etc.).


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: getWikiInfo
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Wiki metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiInfo'
              example:
                id: 1
                guid: wiki_abc123
                workspaceId: 5
                name: Acme Wiki
                createdAt: '2025-01-01T00:00:00Z'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/pages:
    get:
      summary: List Wiki Pages
      description: >
        List wiki pages with cursor-based pagination. Optionally filter by page
        type or creation date,

        or search by keyword (which reorders results by relevance and disables
        cursor pagination).


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: listWikiPages
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: cursor
          in: query
          description: Cursor for pagination (from `nextCursor` of previous response)
          required: false
          schema:
            type: string
        - name: limit
          in: query
          description: Page size (default 50, max 200)
          required: false
          schema:
            type: integer
            default: 50
            minimum: 1
            maximum: 200
        - name: type
          in: query
          description: Filter by page type (ENTITY, MENTION, CUSTOM, etc.)
          required: false
          schema:
            type: string
        - name: since
          in: query
          description: ISO 8601 datetime — return only pages updated on or after this time
          required: false
          schema:
            type: string
            format: date-time
        - name: q
          in: query
          description: >
            Optional search keyword. When provided, results are reordered by
            full-text relevance

            and cursor pagination is disabled (nextCursor is always null).
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Paginated list of wiki pages
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPageListResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/pages/{pageGuid}:
    get:
      summary: Get Wiki Page Details
      description: >
        Retrieve full details for a wiki page, including body/description,
        mentions, aliases, and links.


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: getWikiPageDetail
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: pageGuid
          in: path
          description: Wiki page GUID
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Full wiki page details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPageDetail'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace or page not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/pages/{pageGuid}/mentions:
    get:
      summary: List Page Mentions
      description: >
        List mentions (references from notes) for a specific wiki page with
        cursor-based pagination.


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: listWikiPageMentions
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: pageGuid
          in: path
          description: Wiki page GUID
          required: true
          schema:
            type: string
        - name: cursor
          in: query
          description: Cursor for pagination (from `nextCursor` of previous response)
          required: false
          schema:
            type: string
        - name: limit
          in: query
          description: Page size (default 50, max 200)
          required: false
          schema:
            type: integer
            default: 50
            minimum: 1
            maximum: 200
      responses:
        '200':
          description: Paginated list of page mentions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiMentionListResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace or page not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/search/pages:
    get:
      summary: Search Wiki Pages
      description: >
        Keyword-required search for wiki pages. Returns pages ranked by
        full-text relevance.


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: searchWikiPages
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: q
          in: query
          description: Search keyword (required)
          required: true
          schema:
            type: string
        - name: size
          in: query
          description: Result size (default 20, max 100)
          required: false
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
      responses:
        '200':
          description: Ranked list of matching wiki pages
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiSearchPagesResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/search/mentions:
    get:
      summary: Search Wiki Mentions
      description: >
        Keyword-required search for mentions (references in notes). Returns
        ranked mentions with source context.


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: searchWikiMentions
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: q
          in: query
          description: Search keyword (required)
          required: true
          schema:
            type: string
        - name: size
          in: query
          description: Result size (default 20, max 100)
          required: false
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
      responses:
        '200':
          description: Ranked list of matching mentions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiSearchMentionsResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/graph/seed:
    get:
      summary: Get Wiki Graph Seed
      description: >
        Retrieve an initial set of nodes and edges for graph visualization.
        Optionally filter by page type,

        creation date, or search keyword.


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: getWikiGraphSeed
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: type
          in: query
          description: Filter by page type (ENTITY, MENTION, CUSTOM, etc.)
          required: false
          schema:
            type: string
        - name: since
          in: query
          description: ISO 8601 datetime — include only pages updated on or after this time
          required: false
          schema:
            type: string
            format: date-time
        - name: q
          in: query
          description: Optional search keyword to filter the seed
          required: false
          schema:
            type: string
        - name: folderId
          in: query
          description: |
            Restrict the seed graph to wiki pages mentioned by notes inside this
            folder, including its descendant folders (recursive). An empty,
            nonexistent, or inaccessible folder yields an empty graph. The value
            must be numeric; a non-numeric value returns 400.
          required: false
          schema:
            type: integer
            format: int64
        - name: limit
          in: query
          description: Maximum nodes to return (default 200, max 200)
          required: false
          schema:
            type: integer
            default: 200
            minimum: 1
            maximum: 200
      responses:
        '200':
          description: Wiki graph with nodes and edges
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiGraphResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/graph/expand:
    get:
      summary: Expand Wiki Graph
      description: >
        Expand the graph around a specific wiki page by traversing links up to a
        given depth.


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: getWikiGraphExpand
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: pageGuid
          in: query
          description: Page GUID to expand from (required)
          required: true
          schema:
            type: string
        - name: depth
          in: query
          description: Link traversal depth (default 1, min 1, max 10)
          required: false
          schema:
            type: integer
            default: 1
            minimum: 1
            maximum: 10
        - name: limit
          in: query
          description: Maximum nodes to return (default 50, max 200)
          required: false
          schema:
            type: integer
            default: 50
            minimum: 1
            maximum: 200
      responses:
        '200':
          description: Expanded wiki graph centered on the page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiGraphResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace or page not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/graph/around:
    get:
      summary: Get Wiki Graph Around
      description: >
        Retrieve the graph in the neighborhood of a wiki page (radius-based
        expansion).


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: getWikiGraphAround
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: pageGuid
          in: query
          description: Page GUID to center the neighborhood around (required)
          required: true
          schema:
            type: string
        - name: radius
          in: query
          description: Neighborhood radius (default 2, min 1, max 10)
          required: false
          schema:
            type: integer
            default: 2
            minimum: 1
            maximum: 10
        - name: limit
          in: query
          description: Maximum nodes to return (default 200, max 200)
          required: false
          schema:
            type: integer
            default: 200
            minimum: 1
            maximum: 200
      responses:
        '200':
          description: Wiki graph in the neighborhood of the page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiGraphResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace or page not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/external/workspaces/{workspaceGuid}/wiki/graph/links:
    get:
      summary: Get Wiki Graph Links
      description: >
        Retrieve the graph of links between multiple wiki pages. Pass one or
        more page GUIDs as

        repeated `pageGuids` query parameters.


        Returns 402 if wiki is not plan-eligible or not activated.
      operationId: getWikiGraphLinks
      tags:
        - Wiki
      parameters:
        - name: workspaceGuid
          in: path
          description: Workspace GUID
          required: true
          schema:
            type: string
        - name: pageGuids
          in: query
          description: >
            Page GUIDs to link (repeated parameter, required). Example:
            `?pageGuids=page1&pageGuids=page2`
          required: true
          schema:
            type: array
            items:
              type: string
          style: form
          explode: true
      responses:
        '200':
          description: Wiki graph showing links between the specified pages
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiGraphResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Wiki plan requirement not met or not activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WikiPlanRequired'
        '404':
          description: Workspace not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
tags:
  - name: Note
    description: Operations for managing notes and their paragraphs
  - name: Note Share Link
    description: Manage share links for notes
  - name: Note Summary
    description: Operations for retrieving note summaries
  - name: Note Document
    description: Template-based document generation from notes
  - name: Note Document Template
    description: Operations for managing note document templates
  - name: Folder
    description: Operations for retrieving folders
  - name: Voice File
    description: Operations for voice file processing
  - name: Word Memory
    description: >
      Manage word memories to improve voice transcription accuracy. Register
      important terms like company names, people's names, and product names so
      Tiro recognizes them precisely during recording. Personal word memories
      (User) and a workspace's shared word memories (Workspace) are managed
      separately. The legacy team word memory endpoints
      (`/v1/external/teams/me/word-memories`) are deprecated — removed on
      2026-06-30 — in favor of the workspace-explicit
      `/v1/external/workspaces/{workspaceGuid}/word-memories`.
  - name: Wiki
    description: |
      Access workspace wikis — unified knowledge graphs built from notes.
      Requires a workspace with wiki plan and activation enabled.
  - name: Organization
    description: >
      Endpoints for organization API keys. An organization key is issued by an

      organization admin, carries fixed scopes chosen at issuance, and can reach

      the notes in every workspace that belongs to the organization. Built for

      server-to-server integrations such as CRM sync — receive `note.ended`
      webhook

      events, generate documents for notes, and reconcile with the organization

      notes list.
  - name: Organization Management
    description: Operations for the authenticated user's organization.
