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

# Note Events

> Webhook events for Note resources

export const Json = ({data, lang = 'json', spaces = 2}) => <pre>
    <code className={`language-${lang}`}>{JSON.stringify(data, null, spaces)}</code>
  </pre>;

export const EventBaseStructure = {
  id: "evt_01J9ABCDEF",
  type: "note.created",
  createdAt: "2025-09-05T07:12:34Z",
  workspaceGuid: "ws_a1b2c3d4",
  data: {
    resourceType: "Note",
    resourceId: "note-guid-123",
    resource: {
      "title": "Meeting Note"
    }
  }
};

export const NoteBaseJson = {
  guid: 'note-guid-123',
  workspaceGuid: 'ws_a1b2c3d4',
  title: 'Meeting notes',
  createdAt: '2025-07-20T10:00:00Z',
  updatedAt: '2025-07-20T11:10:00Z',
  sourceType: 'live-voice',
  recordingStartAt: '2025-07-20T10:00:10Z',
  recordingEndAt: '2025-07-20T11:00:10Z',
  recordingDurationSeconds: 3600,
  transcribeLocale: 'en_US',
  translateLocale: 'ko_KR',
  webUrl: 'https://tiro.ooo/n/123',
  collaborators: [{
    guid: 'user-guid-123',
    name: 'John Doe',
    email: 'john@example.com',
    role: 'OWNER'
  }, {
    guid: 'user-guid-456',
    name: 'Jane Smith',
    email: 'jane@example.com',
    role: 'EDITOR'
  }, {
    guid: 'user-guid-789',
    name: 'Sam',
    email: 'sam@example.com',
    role: 'VIEWER'
  }],
  participants: [{
    name: 'Alice Kim',
    email: 'alice@example.com'
  }, {
    name: 'Bob Park',
    email: null
  }]
};

## Overview

Webhook events for Note resources. All note events use `resourceType: "Note"`.

## Event Details

### note.created

* When starting a live-voice note recording
* When creating a note from a recording file

### note.deleted

* When a user permanently deletes a note

### note.recording.completed (Recording paused)

* Fires after a live recording is paused and Tiro finishes processing the audio, transcript, and paragraphs captured so far
* Can fire multiple times for the same note because a recording can be paused more than once during a meeting
* The event name keeps `completed` for compatibility, but it does not mean the note has ended. Use `note.ended` for the final state

### note.user\_content.updated

* When a user manually edits the note content

### note.ended

* Triggered when a note is completely finished (after all processing is complete)
* Fires only once per note lifecycle, unlike `note.recording.completed`, which can fire multiple times
* This is the definitive event for note completion
* Use this event when you need to know that a note has reached its final state

### note.participants.updated

* Triggered when meeting participants are added or removed from a note
* Does **not** fire when an existing participant's name or email is updated
* The `resource` field contains the full Note object with the updated `participants` array

## Example Payload

<Json
  data={{
...EventBaseStructure,
type: "note.ended",
data: {
...EventBaseStructure.data,
resource: NoteBaseJson
}
}}
/>

## Resource Data

Note events include the complete Note resource data. See the [Note API](/api-reference/note/get-note) for field descriptions.

**Important**: Note resources contain only metadata. For transcript content, use the [List Note Paragraphs](/api-reference/note/list-note-paragraphs) API to retrieve the actual text data.

## Guide

### Distinguish a paused recording from an ended note

* `note.recording.completed` means the recording was paused. Fetch fresh note data whenever you receive it
* `note.ended` fires once after the note is fully ended
* Subscribe to both events to handle interim results at each pause and the final result separately

**Example scenario:**

1. Meeting starts → recording begins
2. Recording pauses → transcript and summary processing → `note.recording.completed` fires
3. Recording resumes → processing continues
4. Recording pauses → `note.recording.completed` fires again
5. Recording resumes and ends → `note.ended` fires

**Example handling:**

<CodeGroup>
  ```javascript Node.js theme={"system"}
  async function handleRecordingPaused(event) {
    const noteId = event.data.resourceId;
    const note = event.data.resource;
    const paragraphs = await fetchNoteParagraphs(noteId);

    processPausedNote(note, paragraphs);
  }
  ```

  ```python Python theme={"system"}
  async def handle_recording_paused(event):
      note_id = event['data']['resourceId']
      note = event['data']['resource']
      paragraphs = await fetch_note_paragraphs(note_id)

      process_paused_note(note, paragraphs)
  ```

  ```go Go theme={"system"}
  func handleRecordingPaused(event WebhookEvent) error {
      noteID := event.Data.ResourceID
      note := event.Data.Resource

      paragraphs, err := fetchNoteParagraphs(noteID)
      if err != nil {
          return err
      }

      return processPausedNote(note, paragraphs)
  }
  ```

  ```kotlin Kotlin + Spring theme={"system"}
  suspend fun handleRecordingPaused(event: WebhookEvent) {
      val noteId = event.data.resourceId
      val note = event.data.resource
      val paragraphs = fetchNoteParagraphs(noteId)

      processPausedNote(note, paragraphs)
  }
  ```
</CodeGroup>
