Voice Notes

The Voice Notes API manages audio recordings and their transcriptions. Voice notes are stored with metadata, tags, and workspace associations. Transcription is powered by Whisper and runs asynchronously -- trigger it on demand and poll for results. Deleted notes are soft-deleted (deleted_at timestamp) and filtered from all queries.

Base path: /api/v2/voice-notes|Auth: JWT|Rate limit: 100 req/min

Create Voice Note

POST/api/v2/voice-notesAuthenticated

Creates a new voice note record. Accepts a URL to an already-uploaded audio file. If no title is provided, defaults to 'Voice Note {datetime}'. The note is created with status 'created' -- transcription must be triggered separately.

Body Parameters

audioUrlstringrequired

URL to the audio file (must be pre-uploaded).

titlestring

Title for the voice note. Auto-generated as "Voice Note {datetime}" if omitted.

durationnumber
Default: 0

Recording duration in seconds.

mimeTypestring
Default: audio/webm

Audio MIME type.

metadataobject
Default: {}

Arbitrary key-value metadata.

tagsstring[]
Default: []

Array of tags for organization and filtering.

workspaceIdstring (UUID)

Associate the note with a specific workspace.

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/voice-notes \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_API_KEY" \
  -H 400">class="text-emerald-400">"Content-Type: application/json" \
  -d '{
    400">class="text-emerald-400">"title": 400">class="text-emerald-400">"Sprint retro thoughts",
    400">class="text-emerald-400">"audioUrl": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//cdn.lvng.ai/uploads/audio/a1b2c3d4.webm",
    400">class="text-emerald-400">"duration": 45,
    400">class="text-emerald-400">"mimeType": 400">class="text-emerald-400">"audio/webm",
    400">class="text-emerald-400">"tags": [400">class="text-emerald-400">"retro", 400">class="text-emerald-400">"sprint-14"],
    400">class="text-emerald-400">"workspaceId": 400">class="text-emerald-400">"d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90"
  }'

Response 201

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"voiceNote": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"8f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
    400">class="text-emerald-400">"workspace_id": 400">class="text-emerald-400">"d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
    400">class="text-emerald-400">"title": 400">class="text-emerald-400">"Sprint retro thoughts",
    400">class="text-emerald-400">"audio_url": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//cdn.lvng.ai/uploads/audio/a1b2c3d4.webm",
    400">class="text-emerald-400">"duration": 45,
    400">class="text-emerald-400">"mime_type": 400">class="text-emerald-400">"audio/webm",
    400">class="text-emerald-400">"metadata": {},
    400">class="text-emerald-400">"tags": [400">class="text-emerald-400">"retro", 400">class="text-emerald-400">"sprint-14"],
    400">class="text-emerald-400">"status": 400">class="text-emerald-400">"created",
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T10:00:00.000Z",
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T10:00:00.000Z"
  }
}

List Voice Notes

GET/api/v2/voice-notesAuthenticated

Returns a paginated list of voice notes for the authenticated user. Soft-deleted notes (where deleted_at is set) are excluded. Results are ordered by created_at descending.

Query Parameters

searchstring

Filter by title (case-insensitive partial match).

tagsstring

Comma-separated tags to filter by. Matches notes containing all specified tags.

statusstring

Filter by status: created, processing, completed, or failed.

workspaceIdstring

Filter by workspace ID.

limitnumber
Default: 50

Maximum results to return.

offsetnumber
Default: 0

Number of results to skip for pagination.

Request

cURL
400">curl -X 400">GET 400">class="text-emerald-400">"https:400">class="text-zinc-500">//api.lvng.ai/api/v2/voice-notes?tags=retro&status=completed&limit=10" \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_API_KEY"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"voiceNotes": [
    {
      400">class="text-emerald-400">"id": 400">class="text-emerald-400">"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"8f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
      400">class="text-emerald-400">"workspace_id": 400">class="text-emerald-400">"d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
      400">class="text-emerald-400">"title": 400">class="text-emerald-400">"Sprint retro thoughts",
      400">class="text-emerald-400">"audio_url": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//cdn.lvng.ai/uploads/audio/a1b2c3d4.webm",
      400">class="text-emerald-400">"duration": 45,
      400">class="text-emerald-400">"mime_type": 400">class="text-emerald-400">"audio/webm",
      400">class="text-emerald-400">"metadata": {},
      400">class="text-emerald-400">"tags": [400">class="text-emerald-400">"retro", 400">class="text-emerald-400">"sprint-14"],
      400">class="text-emerald-400">"status": 400">class="text-emerald-400">"completed",
      400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T10:00:00.000Z",
      400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T10:00:45.000Z"
    },
    {
      400">class="text-emerald-400">"id": 400">class="text-emerald-400">"b2c3d4e5-f6a7-8901-bcde-f12345678901",
      400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"8f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
      400">class="text-emerald-400">"workspace_id": 400">class="text-emerald-400">"d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
      400">class="text-emerald-400">"title": 400">class="text-emerald-400">"Feature brainstorm - canvas v2",
      400">class="text-emerald-400">"audio_url": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//cdn.lvng.ai/uploads/audio/b2c3d4e5.m4a",
      400">class="text-emerald-400">"duration": 180,
      400">class="text-emerald-400">"mime_type": 400">class="text-emerald-400">"audio/mp4",
      400">class="text-emerald-400">"metadata": {},
      400">class="text-emerald-400">"tags": [400">class="text-emerald-400">"brainstorm", 400">class="text-emerald-400">"canvas"],
      400">class="text-emerald-400">"status": 400">class="text-emerald-400">"completed",
      400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-17T16:30:00.000Z",
      400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-17T16:33:00.000Z"
    }
  ],
  400">class="text-emerald-400">"total": 28,
  400">class="text-emerald-400">"limit": 10,
  400">class="text-emerald-400">"offset": 0
}

Get Voice Note

GET/api/v2/voice-notes/:idAuthenticated

Returns a single voice note by ID. Only returns notes owned by the authenticated user that have not been soft-deleted.

Path Parameters

idstring (UUID)required

The unique identifier of the voice note.

Request

cURL
400">curl -X 400">GET https:400">class="text-zinc-500">//api.lvng.ai/api/v2/voice-notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_API_KEY"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"voiceNote": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"8f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
    400">class="text-emerald-400">"workspace_id": 400">class="text-emerald-400">"d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
    400">class="text-emerald-400">"title": 400">class="text-emerald-400">"Sprint retro thoughts",
    400">class="text-emerald-400">"audio_url": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//cdn.lvng.ai/uploads/audio/a1b2c3d4.webm",
    400">class="text-emerald-400">"duration": 45,
    400">class="text-emerald-400">"mime_type": 400">class="text-emerald-400">"audio/webm",
    400">class="text-emerald-400">"metadata": {},
    400">class="text-emerald-400">"tags": [400">class="text-emerald-400">"retro", 400">class="text-emerald-400">"sprint-14"],
    400">class="text-emerald-400">"status": 400">class="text-emerald-400">"completed",
    400">class="text-emerald-400">"transcript": 400">class="text-emerald-400">"I think the sprint went well overall. The main blocker was the calendar integration taking longer than expected...",
    400">class="text-emerald-400">"transcript_segments": [
      { 400">class="text-emerald-400">"start": 0.0, 400">class="text-emerald-400">"end": 3.2, 400">class="text-emerald-400">"text": 400">class="text-emerald-400">"I think the sprint went well overall." },
      { 400">class="text-emerald-400">"start": 3.5, 400">class="text-emerald-400">"end": 8.1, 400">class="text-emerald-400">"text": 400">class="text-emerald-400">"The main blocker was the calendar integration taking longer than expected." }
    ],
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T10:00:00.000Z",
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T10:00:45.000Z"
  }
}

Update Voice Note

PUT/api/v2/voice-notes/:idAuthenticated

Updates a voice note's metadata. Only title, tags, and metadata fields can be modified -- audio data and transcripts cannot be changed via this endpoint. Returns 400 if no valid fields are provided.

Path Parameters

idstring (UUID)required

The unique identifier of the voice note.

Body Parameters

titlestring

Updated title for the voice note.

tagsstring[]

Updated tags array (replaces existing tags).

metadataobject

Updated metadata object (replaces existing metadata).

Request

cURL
400">curl -X 400">PUT https:400">class="text-zinc-500">//api.lvng.ai/api/v2/voice-notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_API_KEY" \
  -H 400">class="text-emerald-400">"Content-Type: application/json" \
  -d '{
    400">class="text-emerald-400">"title": 400">class="text-emerald-400">"Sprint 14 Retro - Key Takeaways",
    400">class="text-emerald-400">"tags": [400">class="text-emerald-400">"retro", 400">class="text-emerald-400">"sprint-14", 400">class="text-emerald-400">"action-items"]
  }'

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"voiceNote": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"8f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
    400">class="text-emerald-400">"workspace_id": 400">class="text-emerald-400">"d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
    400">class="text-emerald-400">"title": 400">class="text-emerald-400">"Sprint 14 Retro - Key Takeaways",
    400">class="text-emerald-400">"audio_url": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//cdn.lvng.ai/uploads/audio/a1b2c3d4.webm",
    400">class="text-emerald-400">"duration": 45,
    400">class="text-emerald-400">"mime_type": 400">class="text-emerald-400">"audio/webm",
    400">class="text-emerald-400">"metadata": {},
    400">class="text-emerald-400">"tags": [400">class="text-emerald-400">"retro", 400">class="text-emerald-400">"sprint-14", 400">class="text-emerald-400">"action-items"],
    400">class="text-emerald-400">"status": 400">class="text-emerald-400">"completed",
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T10:00:00.000Z",
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T10:15:00.000Z"
  }
}

Delete Voice Note

DELETE/api/v2/voice-notes/:idAuthenticated

Soft-deletes a voice note by setting the deleted_at timestamp. The note will no longer appear in list or get queries but the data is preserved in the database.

Path Parameters

idstring (UUID)required

The unique identifier of the voice note to delete.

Request

cURL
400">curl -X 400">DELETE https:400">class="text-zinc-500">//api.lvng.ai/api/v2/voice-notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_API_KEY"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"message": 400">class="text-emerald-400">"Voice note deleted"
}

Transcribe Voice Note

POST/api/v2/voice-notes/:id/transcribeAuthenticated

Triggers Whisper transcription for a voice note. The status is set to 'processing' immediately and updated to 'completed' or 'failed' when transcription finishes. The transcript and segment timestamps are stored on the voice note record.

Path Parameters

idstring (UUID)required

The unique identifier of the voice note to transcribe.

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/voice-notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890/transcribe \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_API_KEY"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"message": 400">class="text-emerald-400">"Transcription queued",
  400">class="text-emerald-400">"status": 400">class="text-emerald-400">"processing",
  400">class="text-emerald-400">"voiceNoteId": 400">class="text-emerald-400">"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Get Transcript

GET/api/v2/voice-notes/:id/transcriptAuthenticated

Returns the transcript and segment timestamps for a voice note. Returns 404 if the transcript is not yet available (status is not 'completed'). Segments include start/end timestamps in seconds and the corresponding text.

Path Parameters

idstring (UUID)required

The unique identifier of the voice note.

Request

cURL
400">curl -X 400">GET https:400">class="text-zinc-500">//api.lvng.ai/api/v2/voice-notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890/transcript \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_API_KEY"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"voiceNoteId": 400">class="text-emerald-400">"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  400">class="text-emerald-400">"title": 400">class="text-emerald-400">"Sprint retro thoughts",
  400">class="text-emerald-400">"transcript": 400">class="text-emerald-400">"I think the sprint went well overall. The main blocker was the calendar integration taking longer than expected. We should allocate more buffer time for third-party API work in the next sprint.",
  400">class="text-emerald-400">"segments": [
    { 400">class="text-emerald-400">"start": 0.0, 400">class="text-emerald-400">"end": 3.2, 400">class="text-emerald-400">"text": 400">class="text-emerald-400">"I think the sprint went well overall." },
    { 400">class="text-emerald-400">"start": 3.5, 400">class="text-emerald-400">"end": 8.1, 400">class="text-emerald-400">"text": 400">class="text-emerald-400">"The main blocker was the calendar integration taking longer than expected." },
    { 400">class="text-emerald-400">"start": 8.4, 400">class="text-emerald-400">"end": 14.8, 400">class="text-emerald-400">"text": 400">class="text-emerald-400">"We should allocate more buffer time for third-party API work in the next sprint." }
  ],
  400">class="text-emerald-400">"status": 400">class="text-emerald-400">"completed"
}