---
title: "Search Notes (Deep)"
method: POST
path: "/v1/external/notes/search"
tags: ["Note"]
deprecated: true
---

# Search Notes (Deep)

`POST /v1/external/notes/search`

## Request

- Base URL: `https://api.tiro.ooo`
- URL: `https://api.tiro.ooo/v1/external/notes/search`
- Auth: HTTP bearer

> **Deprecated.**

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

## Request body

- NoteSearchRequest
  - `keyword` string, required: Search keyword. Full-text matched against note title and paragraph content.
  - `filter` NoteSearchFilter
    - `folderId` string, nullable: Restrict hits to notes inside the folder (and its descendants). For a team API key the folder must belong to the team.
    - `createdAtFrom` string, date-time, nullable: ISO 8601 datetime, inclusive lower bound on `createdAt`.
    - `createdAtTo` string, date-time, nullable: ISO 8601 datetime, exclusive upper bound on `createdAt`.
  - `pagination` NoteSearchPagination
    - `cursor` string, nullable: Reserved for future use; the deep-search endpoint currently emits `nextCursor: null`.
    - `size` integer: 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.

## Response `200`

Matched notes with their documents.

- NoteSearchResponse
  - `notes` Note[], required: Matched notes, ordered by full-text relevance with `createdAt` desc as tiebreaker.
    - `guid` string, required: Unique identifier for the note
    - `workspaceGuid` string, nullable: GUID of the workspace this note belongs to. `null` for notes not associated with a workspace.
    - `title` string, required: Note title
    - `createdAt` string, date-time, required: ISO-8601 creation timestamp
    - `updatedAt` string, date-time, required: ISO-8601 last update timestamp
    - `sourceType` 'onboarding' | 'text' | 'live-voice' | 'recording' | 'offline-mode' | 'webpage' | 'video', required: 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
    - `recordingStartAt` string, date-time, nullable: Actual recording start timestamp. Null for non-recording source types.
    - `recordingEndAt` string, date-time, nullable: Actual recording end timestamp. Null for non-recording source types.
    - `recordingDurationSeconds` integer, required: Actual recording length in seconds. Returns `0` for non-recording source types.
    - `transcribeLocale` string, nullable: Language locale used for transcription. Null for non-recording source types.
    - `translateLocale` string, nullable: Language locale used for translation. Null when no translation was requested.
    - `webUrl` string, uri, required: Web URL to access the note
    - `collaborators` Collaborator[], required: Array of collaborators with their roles
      - `guid` string, required: Unique identifier for the collaborator
      - `name` string, required: Collaborator's name
      - `email` string, email, required: Collaborator's email address
      - `role` 'OWNER' | 'EDITOR' | 'VIEWER', required: Collaborator's role
    - `participants` Participant[], required: Array of meeting participants tagged in the note
      - `name` string, nullable: Participant's name. Null when the name was not provided or is blank.
      - `email` string, email, nullable: Participant's email address. Null when the email was not provided or is blank.
    - `matchedSnippets` string[], nullable: 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` NoteDocument[], nullable: 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.
      - `id` integer, required: Document ID
      - `noteGuid` string, required: The GUID of the note this document belongs to
      - `note` NoteRef, required: Note reference with minimal information
        - `guid` string, required: Note GUID
        - `webUrl` string, uri, required: Web URL to access the note
      - `template` NoteDocumentTemplateSummary, required: Summary information of a note document template
        - `id` integer, required: Template ID
        - `title` string, required: Template title
      - `locale` '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', required: Supported language locale
      - `sections` NoteDocumentSection[], required: Array of document sections
        - `templateSectionId` integer, required: ID of the template section this content was generated from
        - `content` object, required: Generated section content
          - `type` 'text/plain' | 'text/markdown', required: MIME type of the text content
          - `content` string, required: The actual text content
        - `createdAt` string, date-time, required: Section creation timestamp
      - `createdAt` string, date-time, required: Document creation timestamp
      - `updatedAt` string, date-time, required: Document last update timestamp
      - `truncated` boolean: `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`.
  - `nextCursor` string, nullable
  - `degraded` boolean: `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` 'search_index_unavailable' | 'search_index_degraded' | 'null', nullable: Machine-readable reason when `degraded=true`. `null` otherwise.

## Other responses

- `400`: 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).
- `401`: Unauthorized
- `500`: Internal server error

---

[API](https://skmtc.dev/tiro/apis/tiro-api-2.md) · [All operations](https://skmtc.dev/tiro/apis/tiro-api-2/llms.txt) · [OpenAPI document](https://skmtc.dev/tiro/apis/tiro-api-2/revisions/dc1a260c6771?raw)
