Skip to main content

Firm data SDK, CLI and MCP

Read stored LegalVoice and MediVoice firm records through the existing customer API. The FAB's Claude Agent SDK tools call the same backend query functions; this package gives scripts and external MCP hosts access through firm API keys.

Official developer documentation: LegalVoice and MediVoice. The voice-firm-data package contains the Python SDK, command-line client, and optional FastMCP server. It contains no API keys, customer records, database credentials, or backend application code.

Install and authenticate

Use Python 3.10 or later:

python -m venv .venv-firm-data
source .venv-firm-data/bin/activate
python -m pip install --upgrade pip
python -m pip install "voice-firm-data[mcp]==0.3.1"

Omit [mcp] if you only need the Python client and CLI. Developer settings also provide a versioned wheel download and checksum. On Windows, activate the virtual environment with .venv-firm-data\Scripts\activate.

Create a data export key in the product's Developer API settings. Set it privately as FIRM_DATA_API_KEY, LEGALVOICE_API_KEY, or MEDIVOICE_API_KEY. Resolution follows that order. Keys need data:read or exports:read; the server derives the firm from the key. A key cannot select a different firm through query arguments.

An API key is required; an OAuth client ID is not. The key identifies the firm (account_id, also called agency_id). The API's client_id identifies a person/client record inside that firm; use it as an optional filter when you want that client's calls, notes, tasks, or web chats. It is not a password and cannot grant access to another firm's records. firm-data whoami reports the account and key identity; firm-data query clients discovers client records.

Set FIRM_DATA_BASE_URL to the API origin shown in Developer settings. It defaults to https://api.legalvoice.app, the shared API default. Use the API origin, not the dashboard's domain. HTTPS is required except for localhost development. Credentials are not accepted as CLI arguments, returned in errors, or forwarded across redirects.

CLI

firm-data whoami
firm-data discover
firm-data query clients --search Jane
firm-data query members
firm-data query web-chats --filter client_id=CLIENT_ID
firm-data query web-chat-messages --filter widget_key=WIDGET_KEY --filter session_id=SESSION_ID
firm-data query web-chat-tools --filter widget_key=WIDGET_KEY --filter session_id=SESSION_ID
firm-data query activity --filter client_id=CLIENT_ID
firm-data query calls --since 2026-09-01 --until 2026-09-08 --filter callback_requested=true
firm-data count calls --since 2026-09-01 --until 2026-09-08 --group-by status
firm-data query tasks --filter status=open --date-field due_on --until 2026-09-15
firm-data query notes --filter client_id=CLIENT_ID
firm-data query profile-notes --search Jane
firm-data query calls --search 'car accident'
firm-data get calls CALL_ID_OR_SID
firm-data query notes --all > notes.jsonl

Single requests print JSON with source references and coverage metadata. Lists return has_more and next_cursor; pass --cursor CURSOR with the same filters. Grouped counts also paginate. Ungrouped count returns the exact count of all matches, regardless of --limit.

query --all streams JSONL through every page (default ceiling: 1,000 pages; configurable with --max-pages). It exits nonzero on errors, repeated/missing cursors or an exceeded page ceiling. A file written before an error is incomplete; check the exit status. Pages are live reads, so concurrent inserts or updates can shift pagination. This is not a transactional snapshot.

Dates are UTC. since is inclusive and until exclusive. For September 1–7, use --since 2026-09-01 --until 2026-09-08. Timestamps require an explicit timezone offset. Exact filters and grouping fields vary by resource; discovery lists the supported fields for the deployed schema. Search is literal, case-insensitive substring matching over listed fields, including call transcripts.

Python SDK

from voice_firm_data import FirmDataClient

with FirmDataClient.from_env() as firm:
    identity = firm.identity()  # account_id, scopes and enforced key/account budgets
    catalog = firm.discover()
    total = firm.query("calls", mode="count", since="2026-09-01")
    tasks = firm.query("tasks", filters={"status": "open"})
    for note in firm.iter_records("notes", filters={"client_id": "CLIENT_ID"}):
        print(note["body"], note["source_ref"])
    call = firm.get("calls", "CALL_ID")  # full transcript/content

An explicit client is FirmDataClient(api_key, base_url). Close it or use a context manager. Queries default to 25 records, maximum 250. Transcripts, metadata and document payloads are omitted from list results unless include_full_payload=True; each result lists omitted_fields. Detail requests include full content. Sensitive configuration resources always use a limited metadata projection, even in full mode.

IDs and relationships

Field Meaning
account_id The firm's existing agency_id, determined by the authenticated key
client_id The stable agency_people.id returned by clients and people; changing a name or phone does not change it
member_id A firm membership's agency_members.id
user_id The member's login identity; one login can belong to multiple firms

client_id is an alias for an existing identity, so there is no new ID backfill. Related records expose it when person_id or primary_person_id is recorded. An unlinked record has client_id: null; clients are never joined by guessing from names or phone numbers. Discovery reports each resource's client_id_field and whether it supports the client_id filter. Other relationships use the catalog's specific IDs, such as call_sid, engagement_id, run_id, and document_id.

Enforced API budgets

All developer-key requests share PostgreSQL counters across server replicas. A reservation checks and charges both the key and its account atomically, before the handler runs. Creating or rotating keys does not reset the account budget. Existing keys automatically receive the standard limits.

Budget Per UTC minute Per UTC day Concurrent requests
Standard key 120 units 12,000 units 3
Limited key preset 30 units 3,000 units 3
Account, shared by all keys 600 units 60,000 units 8

Ordinary requests cost 1 unit, queries/counts 5, discovery/export manifests 10, and CSV exports 60. These are fixed UTC minute/day windows, not rolling windows. Customer data requests have a 90-second deadline; query execution also has a 30-second database timeout. Short leases recover concurrency capacity after a worker stops unexpectedly.

Owners/admins choose a standard or limited budget when creating a key in Developer API settings. The key-creation endpoint also accepts rate_limits: {"per_minute": 30, "per_day": 3000}. Custom positive values cannot exceed the server's standard caps, including when reading stored metadata. A request costing more than a key's entire minute/day budget returns 422; limited keys must use paginated JSON instead of CSV.

An exhausted budget returns 429 with Retry-After in seconds. Responses expose Limit, Remaining, Reset (Unix seconds), Day-Limit, Day-Remaining, Account-Limit, Account-Remaining, and Cost, all prefixed with X-RateLimit-. GET /me / firm-data whoami reports the configured limits. Failed quota storage returns 503 without executing the request. Requests rejected for missing/revoked keys do not reserve a budget; authenticated requests consume units even if their handler rejects the request.

The SDK, CLI, and MCP adapter retry 429 responses up to twice, honoring delays up to 60 seconds. A longer delay, or exhausted retries, raises FirmDataRateLimitError with status_code=429 and retry_after; the CLI exits nonzero. Python callers can set max_retries=0 to handle retries themselves and inspect client.last_rate_limits. Multi-page exports retain their incomplete-file behavior on quota exhaustion.

MCP

Install the mcp extra, then configure your MCP host to run firm-data-mcp over stdio. The server uses the standalone FastMCP framework, pinned to 4.0.3, with from fastmcp import FastMCP and decorated tools. FastMCP owns schema generation, validation, transport and protocol handling. This package exposes local stdio transport; there is no hosted MCP URL or OAuth connector in this release.

{
  "mcpServers": {
    "firm-data": {
      "command": "/absolute/path/to/.venv-firm-data/bin/firm-data-mcp",
      "env": {
        "FIRM_DATA_BASE_URL": "https://api.legalvoice.app",
        "FIRM_DATA_API_KEY": "<set your firm key privately in the host>"
      }
    }
  }
}

Use the host's private environment/secret settings where available. The placeholder must be replaced; it is not automatic shell-variable interpolation. GUI apps may require the executable's absolute path. The server writes protocol traffic to stdout and does not open a listening network port.

The three tools are:

Tool Purpose
discover_firm_data Available resources, search/filter/date/group fields and query schema
query_firm_data Search, filter, paginate or count all matching records
get_firm_record Full record details with a source reference

Try: “Show overdue open tasks grouped by owner,” “Find calls mentioning a car accident,” “Which members handle this client's work?” or “Summarize this client's web chats, notes and open tasks.” Resolve the client through clients, then use its client_id. For web chat transcripts and tool activity, query web-chat-messages and web-chat-tools with both widget_key and session_id from web-chats.

HTTP contract and coverage

All routes use the existing customer API key authentication and scopes:

  • GET /api/v1/customer/v1/data — discovery.
  • GET /api/v1/customer/v1/me — account, key scopes and budgets.
  • POST /api/v1/customer/v1/query — a read-only query body, e.g. {"resource":"tasks","filters":{"status":"open"}}.
  • GET /api/v1/customer/v1/records/{resource}/{record_id} — record detail.

The registry covers 67 named resources (including aliases). Some tables are optional and differ by deployment; discovery reports availability explicitly. Requests to unavailable resources fail instead of claiming zero records. Each registered resource also has list, detail, and CSV export routes in the Developer API catalog.

Area Resources
Clients and members Clients/people, canonical contacts and cases, members/users, identity links, client facts, client messages, client audit history
Communications and intake Calls/transcripts, intakes, web intakes, web chat sessions/messages/tool calls, email, SMS, messaging agent sessions/turns, appointments
Work and activity Saved notes, profile notes, tasks, client activity, engagements/participants/links/events, work items and their events
Documents Source/generated documents, projects, annotations, mentions, document workflows, e-sign envelopes/packages, knowledge sources/text chunks, extraction templates/runs
Automation and campaigns Automations/dispatches, workflow definitions/runs/node runs/events/artifacts/human tasks, campaigns/runs/recipients/events/timeline
Administration Phone numbers, departments, agent profiles/configuration, intake forms, integration metadata, webhook delivery history, audit events, usage and billing periods

Activity and event feeds expose persisted history. They do not imply that every historical UI click or unrecorded action was captured, and this release does not add a universal activity recorder.

notes contains durable team notes; profile-notes contains nonempty agency_people.metadata.contact_notes. These are separate feeds, matching the two sources in the dashboard. people contains dashboard person IDs; contacts uses the canonical contact store when present and falls back to people only when that table is absent. Do not add overlapping resource counts together as unique clients or intakes.

These tools expose registered, stored firm data, not arbitrary database tables, SQL, provider credentials, or every record in an external CRM. Live external case data continues through the existing connected CRM tools. The FAB's chat controls can disable the new tools with the firm-data/recent-context groups; they remain available in review-only mode because they do not mutate records.

Distribution and license

Install from PyPI or the versioned download in Developer settings. The package uses a proprietary SDK license, not an open-source license. Authorized commercial integrations are permitted under the included LICENSE; standalone redistribution and publication of modified SDK versions require written permission. Third-party dependencies keep their own licenses.

The SDK sends requests only to the API origin configured by the developer or MCP host. Use an API origin you trust: the configured origin receives your firm API key. HTTPS certificate verification is enabled; redirects and environment proxy discovery are disabled. No telemetry is implemented by this SDK.

The MCP host may send returned firm data to its selected model provider. Use a host and provider approved for the data you access. Model instructions cannot supply a different API key, account, or API origin through these tools.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

voice_firm_data-0.3.1.tar.gz (11.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

voice_firm_data-0.3.1-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

File details

Details for the file voice_firm_data-0.3.1.tar.gz.

File metadata

  • Download URL: voice_firm_data-0.3.1.tar.gz
  • Upload date:
  • Size: 11.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.9

File hashes

Hashes for voice_firm_data-0.3.1.tar.gz
Algorithm Hash digest
SHA256 ebe9ce0cb02a9dd48176767a53f1c047f44bdef36007636ac782723d99f054aa
MD5 a7d32228eb57cebee1e9291c95485488
BLAKE2b-256 a9a35d4f0aa0721644ce48833caff248ff3065a45712907b898c9bd27c8397f2

See more details on using hashes here.

File details

Details for the file voice_firm_data-0.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for voice_firm_data-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8d8cdfb84413f55300d4c65aa1f3787fe3a770279bf5659484910fd1309222a8
MD5 476400121e3081177ca11fc626bd3dbb
BLAKE2b-256 1521544d516527b9139b66fc98a5b101adc676d31e02d78cc17ac60face78922

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page