Skip to main content

Documentation Index

Fetch the complete documentation index at: https://api-docs.tiro.ooo/llms.txt

Use this file to discover all available pages before exploring further.

Overview

search_notes is the deep tier of note discovery. It takes a required keyword and returns matching notes hydrated with their primary documents (one-pager, custom). Use this when the LLM needs to understand the context behind a topic — its decisions, action items, or conclusions — not just see which notes match. For lightweight metadata-only listing (e.g., “which notes are in folder X”), use list_notes instead. Primary Use Cases:
  • “What did the team decide about OKR Q2?” — search by topic, read documents inline.
  • “Where is the source note for this decision?” — keyword finds the note, documents give the context.
  • “Show me everything we wrote about 네이버” — Korean keyword search with content.
Key Features:
  • Keyword required; results ordered by OpenSearch relevance (_score desc).
  • Each matched note carries its primary documents inline (one-pager, custom).
  • HTML stripped from document content; documents larger than 5,000 chars are truncated and flagged.
  • Graceful degradation when the search index is unavailable.
Heavier than list_notes. Each result includes document content (~1,500 tokens per note). Default page size is 10, max 30. If you only need metadata, use list_notes.

Parameters

ParameterTypeRequiredDescription
keywordstringYesSearch keyword (≥1 char). Matched against title and paragraph content via OpenSearch.
pagination.cursorstringOptionalReserved for future use; the deep-search endpoint currently emits null.
pagination.sizenumberOptionalResults per page (default 10, max 30).
filter.folderIdstringOptionalRestrict to a folder (recursive — includes descendant folders).
filter.createdAtFromstringOptionalISO 8601 datetime, inclusive lower bound on createdAt.
filter.createdAtTostringOptionalISO 8601 datetime, exclusive upper bound on createdAt.

keyword (required)

The search term. Tokenized server-side via OpenSearch; Korean text is morphologically analyzed via the Nori plugin (e.g., 네이버[네, 버]). Empty or whitespace-only keywords return 400. Keyword search currently requires a user-scoped API key. Team-only API keys return 400.

filter.folderId (optional)

Same semantics as list_notes — recursive folder scope, authorized server-side.

pagination (optional)

{ cursor, size }. Default size: 10, max 30. The smaller cap reflects the higher per-result cost (each note carries its documents).

Response Format

Success Response

{
  "notes": [
    {
      "noteGuid": "abc-123-def",
      "title": "OKR Q2 Planning",
      "webUrl": "https://platform.tiro.ooo/notes/abc-123-def",
      "createdAt": "2026-04-15T10:00:00Z",
      "updatedAt": "2026-04-15T11:30:00Z",
      "recordingDurationSeconds": 3625,
      "sourceType": "live-voice",
      "participants": [
        { "name": "Alice Kim", "email": "alice@example.com" }
      ],
      "matchedSnippets": null,
      "documents": [
        {
          "documentGuid": "7821",
          "templateId": 12,
          "templateTitle": "One Pager",
          "content": "## 결정 사항\n- 자동 ingest 우선...\n## Action Items\n- ...",
          "truncated": false,
          "updatedAt": "2026-04-15T11:30:00Z"
        }
      ]
    }
  ],
  "nextCursor": null,
  "degraded": false,
  "degradedReason": null
}
Field Descriptions:
FieldTypeDescription
notes[]arrayMatched notes, ordered by OpenSearch relevance.
notes[].matchedSnippetsstring[] | nullReserved for OpenSearch highlights. Currently null — distinguishes “highlights not yet implemented” from “searched, no highlights matched”.
notes[].documents[]arrayNote’s primary documents. Empty array when the note has no documents.
notes[].documents[].documentGuidstringStable document identifier.
notes[].documents[].templateIdnumber | nullNumeric template id — the only stable discriminator.
notes[].documents[].templateTitlestringDisplay label (e.g., "One Pager", "회의록"). Locale-sensitive and user-editable for custom templates — do NOT discriminate on this string.
notes[].documents[].contentstringHTML-stripped, markdown-friendly text. Capped at 5,000 chars; see truncated.
notes[].documents[].truncatedbooleantrue when content was truncated. Fetch the full document via get_note_document if you need the rest.
nextCursorstring | nullReserved for future use; currently always null.
degradedbooleantrue when the search index was unavailable or failed.
degradedReasonstring | nullWhen degraded=true: "search_index_unavailable" or "search_index_degraded".
Don’t discriminate on templateTitle. It’s a display label, not an enum. For boolean checks (“is this a one-pager?”) use templateId against a known managed-template id, or surface both fields and let your UI choose by label.

Degraded Response

When the search index is unavailable, the response sets degraded=true and returns an empty notes array:
{
  "notes": [],
  "nextCursor": null,
  "degraded": true,
  "degradedReason": "search_index_unavailable"
}
degradedReason is one of:
  • search_index_unavailable — OpenSearch is disabled in the environment.
  • search_index_degraded — OpenSearch threw an error mid-query.
Surface this to the LLM/user so retries can be deferred or the result interpreted appropriately.

Usage Examples

Request:
{
  "keyword": "OKR"
}
Returns the 10 most relevant notes mentioning OKR, each with its primary documents inline.

Example 2: Folder-scoped Korean keyword

Request:
{
  "keyword": "네이버",
  "filter": {
    "folderId": "455765"
  },
  "pagination": {
    "size": 5
  }
}
Searches 네이버 only inside folder 455765 (and descendants). Korean morphological analysis runs server-side. Request:
{
  "keyword": "release",
  "filter": {
    "createdAtFrom": "2026-04-01T00:00:00Z",
    "createdAtTo": "2026-05-01T00:00:00Z"
  }
}

Best Practices

Use list_notes first to find which notes match. If the LLM still needs document content to answer, switch to search_notes for the same keyword. This is the cheapest progressive-disclosure path.
A folder-scoped search is faster and returns better-ranked results because the relevance space is smaller. Pair with list_notes(filter.folderId) to find folder candidates first.
The deep-search endpoint currently emits nextCursor: null. If 30 results aren’t enough, refine the keyword (more specific) or scope by folderId/dateRange instead of paginating.
A degraded=true response is honest — the search index couldn’t run. Don’t treat the empty notes array as “no matches”; instead, surface the degradation to the user/LLM so retries can be timed appropriately.

Common Errors

Empty keyword

Team-only API key

Solution: Use a user-scoped API key. Team-folder keyword search lands in a follow-up.

Token Usage

Per Note (with documents): ~1,500 tokens average. Truncated documents cap at ~1,500 tokens regardless of source size.
Compared to get_note_transcript (~3,000–5,000 tokens per hour of meeting), search_notes returns curated documents that are typically 10× more compact and cover the same key decisions. Reach for transcripts only when you need exact spoken words.