> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tiro.ooo/llms.txt
> Use this file to discover all available pages before exploring further.

# Search Workspace Notes (Deep)

> 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`.




## OpenAPI

````yaml /openapi.yaml post /v1/external/workspaces/{workspaceGuid}/notes/search
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: []
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.
paths:
  /v1/external/workspaces/{workspaceGuid}/notes/search:
    post:
      tags:
        - Note
      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
      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'
components:
  schemas:
    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'
    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.
    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
    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.
    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.
    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
    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`.
    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
    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: 영업 보고서
    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
    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'
    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...
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: API key in format {id}.{secret}

````