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

# Search Notes (Deep)

`POST /v1/external/notes/search`

> **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
        - `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.net/tiro/apis/tiro-api.md) · [All operations](https://skmtc.net/tiro/apis/tiro-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/tiro/tiro-api/revisions/ae18d7961aa4/schema)
