> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vued.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Vued api guide for coding agents

# Vued API Reference

Self-contained reference with best practices and examples for coding agents.

> Canonical references: `docs/local-api-sdk-mcp.md`, `vued-python-sdk/vued/client.py`, `web-client/electron/main.js`, `Vued-Agent/server/routers/public_api.py`.
> If this page contradicts source, trust source and report the stale doc.

## Overview

Vued has two public access paths:

| Path              | Base                                          | Use for                                                                                            |
| ----------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Cloud API         | `https://vued-office-api-dev.onrender.com/v1` | Auth, org discovery, metadata writes, signed audio URLs, API keys, webhooks, semantic vector refs. |
| Local desktop API | `http://127.0.0.1:<discovered_port>`          | Decrypted meetings, transcripts, search, and file names. Requires unlocked desktop.                |

Python SDK: `vued.Vued`.

CLI/MCP: `vued mcp` starts a stdio MCP proxy to the local desktop `/mcp` endpoint.

## Installation

```bash theme={null}
pip install vued
export VUED_API_KEY="vued_live_..."
```

Development:

```bash theme={null}
cd vued-python-sdk
uv sync
uv run python examples/quickstart.py
```

## Minimal Working Example

```python theme={null}
import os
from vued import Vued, VuedLocalUnavailableError

client = Vued(
    api_key=os.environ["VUED_API_KEY"],
    org_id=os.environ["VUED_ORG_ID"],
)

try:
    results = client.search("paid ads cost", limit=5)
except VuedLocalUnavailableError:
    raise SystemExit("Open and unlock Vued Desktop for decrypted local search.")

for item in results["items"]:
    meeting = item["meeting"]
    print(meeting["id"], meeting["type"], meeting["title"])
```

## Pick Your Pattern

### 1. Decrypted retrieval for agents

Use this when an LLM must answer from meeting text.

```python theme={null}
results = client.search("customer renewal risk", limit=10)
meeting = client.get_meeting(results["items"][0]["meeting"]["id"])
transcript_text = meeting["transcript"]["text"]
```

Rules:

* Desktop must be open and unlocked.
* Prefer `search` for exact names, phrases, decisions, and topics.
* Use `semantic_search` for fuzzy memory retrieval.
* Use `get_meeting` after search/list to fetch full transcript text.

### 2. Cloud metadata and admin operations

Use this for writes and non-plaintext metadata.

```python theme={null}
folder = client.create_file(name="Customer calls", type="folder", visibility="restricted")
room = client.create_room(display_name="Conference Room", microphone_id="tablet-01")
key = client.create_api_key(name="Read-only integration", scopes=["records:read"])
```

Rules:

* `org_id` is required for org-scoped cloud calls.
* Public API keys return `secret` once.
* File/folder names may be encrypted in cloud responses; local `list_files` gives plaintext.

### 3. Signed audio URLs

Use this when an app needs retained audio.

```python theme={null}
audio = client.get_transcript_audio("transcript_event_uuid")
print(audio["url"], audio.get("suggested_clip_secs"))
```

Rules:

* URLs are short-lived.
* Signed audio URLs include a `.m4a` download filename hint, and the response includes `filename` and `mime`.
* Transcript audio can include `offset_secs` and `suggested_clip_secs`.
* Audio retention is currently one day.

### 4. Local MCP

Use this when a coding agent should search decrypted Vued memory directly.

```bash theme={null}
vued mcp
```

MCP tools:

| Tool              | Use                                                        |
| ----------------- | ---------------------------------------------------------- |
| `search`          | Keyword search local decrypted meetings/transcripts.       |
| `semantic_search` | Semantic search with local plaintext hydration.            |
| `list_meetings`   | Browse local meetings by time/source/room/microphone/file. |
| `get_meeting`     | Fetch one meeting plus transcript.                         |
| `get_transcript`  | Fetch one transcript event plus parent meeting ref.        |

Do not use remote `/mcp` unless source adds it. Checked server source currently defines local MCP only.

## Authentication

Cloud:

```http theme={null}
Authorization: Bearer vued_live_...
```

Local desktop:

1. SDK reads discovery automatically.
2. Manual callers read `local-api.json`.
3. Send `Authorization: Bearer <authToken>`.

Discovery search:

| Source                                        | Meaning                    |
| --------------------------------------------- | -------------------------- |
| `VUED_LOCAL_API_URL` + `VUED_LOCAL_API_TOKEN` | Explicit local daemon.     |
| `VUED_LOCAL_API_DISCOVERY`                    | Explicit discovery file.   |
| App support `local-api.json`                  | Default desktop discovery. |

## SDK Methods

Local plaintext:

| Method                                                                                                                                                                                                               | Args                                  | Returns                                                              |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------- |
| `search(q, type=None, include_transcript=True, limit=20)`                                                                                                                                                            | keyword query; optional source filter | Page of `{meeting, matches}`.                                        |
| `semantic_search(q, type=None, limit=5)`                                                                                                                                                                             | natural-language query                | Page of semantic chunks; local results include hydrated text/events. |
| `list_meetings(type=None, started_after=None, started_before=None, room_id=None, microphone_id=None, file_id=None, limit=100, cursor=None)`                                                                          | filters and pagination                | Page of meetings.                                                    |
| `get_meeting(meeting_id)`                                                                                                                                                                                            | meeting UUID                          | `{meeting, transcript}`.                                             |
| `get_transcript(transcript_id)`                                                                                                                                                                                      | transcript event UUID                 | `{event, meeting}`.                                                  |
| `list_files(type=None, q=None, parent_id=None, root_only=None, visibility=None, record_id=None, created_after=None, created_before=None, updated_after=None, updated_before=None, sort=None, limit=50, cursor=None)` | filters and pagination                | Page of decrypted files/folders.                                     |
| `get_file(file_id)`                                                                                                                                                                                                  | file/folder UUID                      | File object.                                                         |

Cloud:

| Method                                                                                                    | Args                  | Returns                         |
| --------------------------------------------------------------------------------------------------------- | --------------------- | ------------------------------- |
| `list_orgs(**filters)`                                                                                    | `limit`, `cursor`     | Page of orgs.                   |
| `get_meeting_audio(meeting_id)`                                                                           | meeting UUID          | Signed audio URL object.        |
| `get_transcript_audio(transcript_id)`                                                                     | transcript event UUID | Signed audio URL object.        |
| `create_file(name="Untitled", type="folder", parent_id=None, visibility="org")`                           | node fields           | File object.                    |
| `update_file(file_id, name=None, parent_id=UNSET, visibility=None)`                                       | patch fields          | File object.                    |
| `list_file_grants(file_id, limit=50, cursor=None)`                                                        | file UUID             | Page of grants.                 |
| `grant_file(file_id, user_id)`                                                                            | file UUID, user UUID  | Grant object.                   |
| `revoke_file_grant(file_id, user_id)`                                                                     | file UUID, user UUID  | `{deleted}`.                    |
| `download_file(file_id)`                                                                                  | file UUID             | ZIP bytes.                      |
| `list_speakers(q=None, limit=50, cursor=None)`                                                            | filters               | Page of speakers.               |
| `get_speaker(speaker_id)`                                                                                 | speaker UUID          | Speaker object.                 |
| `list_rooms(q=None, limit=50, cursor=None)`                                                               | filters               | Page of rooms.                  |
| `get_room(room_id)`                                                                                       | room UUID             | Room object.                    |
| `create_room(display_name, microphone_id)`                                                                | room fields           | Room object.                    |
| `update_room(room_id, display_name=None, microphone_id=None, is_primary=None, participant_user_ids=None)` | patch fields          | Room object.                    |
| `list_microphones(limit=50, cursor=None)`                                                                 | pagination            | Page of microphones.            |
| `get_microphone(microphone_id)`                                                                           | device ID             | Microphone object.              |
| `list_users(q=None, limit=50, cursor=None)`                                                               | filters               | Page of users.                  |
| `get_user(user_id)`                                                                                       | user UUID             | User object.                    |
| `list_api_keys(limit=50, cursor=None)`                                                                    | pagination            | Page of API key metadata.       |
| `create_api_key(name="Public API key", expires_at=None, scopes=None)`                                     | key fields            | `{token, secret}`.              |
| `revoke_api_key(key_id)`                                                                                  | key UUID              | `{deleted}`.                    |
| `list_webhooks(limit=50, cursor=None)`                                                                    | pagination            | Page of webhooks.               |
| `create_webhook(name="Webhook", url, events=None, payload_fields=None, disabled=False)`                   | webhook fields        | Webhook with one-time `secret`. |
| `update_webhook(webhook_id, name=None, url=None, events=None, payload_fields=None, disabled=None)`        | patch fields          | Webhook.                        |
| `delete_webhook(webhook_id)`                                                                              | webhook ID            | `{deleted}`.                    |

## Request Parameters

Common:

| Parameter                         | Type                            | Meaning                                |
| --------------------------------- | ------------------------------- | -------------------------------------- |
| `type`                            | `manual` \| `automatic` \| null | Meeting source filter.                 |
| `limit`                           | integer                         | Page/result size.                      |
| `cursor`                          | string \| null                  | Pagination cursor from prior response. |
| `started_after`, `started_before` | ISO string or epoch             | Meeting start bounds.                  |
| `created_after`, `created_before` | ISO string or epoch             | File creation bounds.                  |
| `updated_after`, `updated_before` | ISO string or epoch             | File update bounds.                    |

File sort values:

```text theme={null}
name_asc, name_desc, updated_at_asc, updated_at_desc,
created_at_asc, created_at_desc, date_asc, date_desc
```

Webhook events:

```text theme={null}
meeting.started
meeting.ended
meeting.transcription.completed
meeting.speaker_id.completed
meeting.finalized
meeting.automatic.surfaced
```

Webhook payload fields:

```text theme={null}
meeting, timestamps, room, participants, speakers, audio_metadata,
transcript_text, transcript_events, summary, topics, title
```

## Response Schemas

Page:

```json theme={null}
{ "items": [], "next_cursor": null }
```

Meeting:

```json theme={null}
{
  "id": "meeting_uuid",
  "object": "meeting",
  "type": "manual",
  "title": "Weekly sync",
  "summary": "Short summary",
  "status": "final",
  "started_at": "2026-06-24T21:24:57.909Z",
  "ended_at": "2026-06-24T21:54:57.909Z",
  "room": { "id": "room_uuid", "display_name": "Conference Room" },
  "microphone_id": "tablet-01",
  "participants": [],
  "diarized_speaker_count": 2,
  "recognized_speaker_count": 1,
  "audio": { "available": true },
  "transcript_event_count": 120
}
```

Transcript event:

```json theme={null}
{
  "id": "event_uuid",
  "index": 0,
  "start": "2026-06-24T21:24:57.909Z",
  "end": "2026-06-24T21:24:58.228Z",
  "speaker": {
    "diarization_id": "speaker_1",
    "profile_id": null,
    "name": "Speaker 1",
    "type": "diarized"
  },
  "text": "Hello."
}
```

Speaker type:

| Value       | Meaning                               |
| ----------- | ------------------------------------- |
| `diarized`  | Meeting-local cluster only.           |
| `anonymous` | Persistent anonymous speaker profile. |
| `named`     | Named speaker profile.                |

File:

```json theme={null}
{
  "id": "file_uuid",
  "object": "file",
  "type": "folder",
  "name": "Customer calls",
  "parent_id": null,
  "visibility": "restricted",
  "record_type": "meeting",
  "record_id": "meeting_uuid",
  "share_id": "share_id",
  "created_at": "2026-06-24T21:24:57.909Z",
  "updated_at": "2026-06-24T21:24:57.909Z"
}
```

Audio URL:

```json theme={null}
{
  "available": true,
  "url": "https://...",
  "expires_at": 1782345900,
  "retention_days": 1,
  "offset_secs": { "start": 12.3, "end": 15.8 },
  "suggested_clip_secs": { "start": 9.3, "end": 18.8, "margin_secs": 3.0 }
}
```

## Error Handling

```python theme={null}
from vued import VuedError, VuedLocalUnavailableError

try:
    client.search("pricing")
except VuedLocalUnavailableError:
    print("Open and unlock Vued Desktop.")
except VuedError as err:
    print(err.status_code, err.body)
```

HTTP status meanings:

| Status | Meaning                                                                                    |
| ------ | ------------------------------------------------------------------------------------------ |
| `400`  | Invalid request or local API error.                                                        |
| `401`  | Missing/invalid bearer token.                                                              |
| `403`  | Missing scope or org access.                                                               |
| `404`  | Object not found or not visible.                                                           |
| `410`  | Audio expired/unavailable.                                                                 |
| `424`  | Cloud response contains encrypted fields; use local API or `X-Vued-Allow-Encrypted: true`. |
| `503`  | Desktop local API unavailable.                                                             |

## Common Mistakes

Do not:

* Use cloud endpoints for decrypted transcript text. Use local `search`, `get_meeting`, or `get_transcript`.
* Assume local API works without Vued Desktop open and unlocked.
* Invent `GET /v1/meetings` on cloud; meeting plaintext list is local-only.
* Treat `automatic` meetings as a separate public object type. Public APIs expose them as `type: "automatic"` meetings.
* Use remote `/mcp`; checked source defines local `/mcp` only.
* Expect public API key secrets to be recoverable after creation.
* Pass `parent_id=None` to `update_file` unless moving to root. Omit `parent_id` to keep the parent.
* Use table names such as `ambient_segmentation_candidates` in public inputs. Use `type="automatic"`.

## Complete Examples

### Keyword search then fetch transcript

```python theme={null}
results = client.search("launch plan", include_transcript=True, limit=5)
for result in results["items"]:
    print(result["meeting"]["title"])
    for match in result["matches"]:
        print(match["snippet"])

meeting = client.get_meeting(results["items"][0]["meeting"]["id"])
print(meeting["transcript"]["text"])
```

### Semantic search with local hydration

```python theme={null}
results = client.semantic_search("decisions about hiring timeline", limit=5)
for item in results["items"]:
    print(item["score"], item["meeting"]["id"], item.get("hydrated"))
    print(item["chunk"].get("text", ""))
```

### List meetings with pagination

```python theme={null}
page = client.list_meetings(type="manual", limit=25)
while page["items"]:
    for meeting in page["items"]:
        print(meeting["started_at"], meeting["title"])
    if not page["next_cursor"]:
        break
    page = client.list_meetings(type="manual", limit=25, cursor=page["next_cursor"])
```

### Create a webhook and verify signatures

```python theme={null}
created = client.create_webhook(
    name="Meeting finalized",
    url="https://example.com/vued",
    events=["meeting.finalized"],
    payload_fields={"default": ["meeting", "timestamps", "title", "summary"]},
)
print(created["secret"])
```

```python theme={null}
import hashlib
import hmac

timestamp = request.headers["Vued-Webhook-Timestamp"]
signature = request.headers["Vued-Signature"].split("v1=", 1)[1]
body = request.get_data()
expected = hmac.new(
    b"whsec_...",
    timestamp.encode() + b"." + body,
    hashlib.sha256,
).hexdigest()
ok = hmac.compare_digest(signature, expected)
```

### Expose Vued to an OpenAI-style tool loop

```python theme={null}
import json
from vued import Vued

client = Vued(api_key=os.environ["VUED_API_KEY"], org_id=os.environ["VUED_ORG_ID"])

tools = [{
    "type": "function",
    "function": {
        "name": "vued_search",
        "description": "Search decrypted Vued meeting memories.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Meeting memory search query"}
            },
            "required": ["query"]
        },
    },
}]

def vued_search(query: str) -> str:
    results = client.search(query, limit=5)
    return json.dumps(results["items"], ensure_ascii=False)
```

## Resources

* Human guide: `docs/local-api-sdk-mcp.md`
* Docs index: `docs/llms.txt`
* SDK README: `vued-python-sdk/README.md`
* Quickstart: `vued-python-sdk/examples/quickstart.py`
