# Add Client Matters Source: https://developers.harvey.ai/api-reference/add/add-client-matters /client_matters_api.json post /api/v1/client_matters Adds a list of client matters to Harvey. Each client matter includes a name and an optional description. ### Permissions Requires `Client matters admin` permission. # Authentication Source: https://developers.harvey.ai/api-reference/authentication To create and manage API tokens for your organization’s workspace, visit the "API Tokens" section in your workspace settings. If this section isn't visible to you, contact your Customer Success Manager. The Harvey API uses bearer token authentication. Include the token in the Authorization header of all API requests. ```bash theme={null} curl https://api.harvey.ai/v2/endpoint \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -H "Content-Type: application/json" ``` Your bearer tokens grant access to sensitive data and privileged operations, so they must be kept secure. Never share tokens in public repositories, client-side code, or unsecured channels. If you need to contact Harvey support, make sure to redact your token from any example requests or screenshots. All API requests must use HTTPS. Requests sent over HTTP or without authentication will be rejected. ## Permissions To help you further control what can be done with your bearer tokens, each token also has a managable permissions list which can be used to restrict what API endpoints can be used with the token. Consult the API Tokens setting page to learn more. Some permissions are only available if your workspace has been specially configured for them. See your Order Form, or email [support@harvey.ai](mailto:support@harvey.ai) for details on which feature(s) your organization can use. ## Country-Specific Endpoint URL If your organization is using Harvey’s EU-hosted deployment, update the request URL to point to the EU API endpoint: [**https://eu.api.harvey.ai**](https://eu.api.harvey.ai) ```bash theme={null} curl https://eu.api.harvey.ai/v2/endpoint \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -H "Content-Type: application/json" ``` If your organization is using Harvey’s AU-hosted deployment, update the request URL to point to the AU API endpoint: [**https://au.api.harvey.ai**](https://au.api.harvey.ai) ```bash theme={null} curl https://au.api.harvey.ai/v2/endpoint \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -H "Content-Type: application/json" ``` ## Testing Authentication ```bash theme={null} GET https://api.harvey.ai/api/whoami ``` Returns the underlying service user account associated with the API token, useful for testing that the token works or identifying which token has taken actions surfaced in audit logs. # Completion Source: https://developers.harvey.ai/api-reference/completion/completion /v2_completion_api.json post /api/v2/completion Harvey's Completion API provides access to Harvey's models via our orchestration engine, allowing users to ask complex, freeform questions and receive detailed legal-grade responses programmatically. It can also be used in conjunction with files attached to the request, Vaults, and Regional Knowledge Sources. Access to this API requires `Assistant access via API` permission, which is only available in your workspace with an additional purchase. To get started, contact your Account Manager or reach out to us at support@harvey.ai to discuss an agreement. ### Permissions Requires `Assistant access via API` and `Assistant access` permission. # Delete Client Matters Source: https://developers.harvey.ai/api-reference/delete/delete-client-matters /client_matters_api.json delete /api/v1/client_matters Deletes a list of client matters from Harvey, preventing them from being associated with any future queries. If a client matter does not exist or is already deleted, it will be skipped. Deleting a Client Matter does not delete historical queries associated with that Client Matter, nor does it remove the Client Matter from those historical queries. Users and Admins can update the Client Matter associated with a previous query in the Dashboard. ### Permissions Requires `Client matters admin` permission. # Query Audit Logs Source: https://developers.harvey.ai/api-reference/query/query-audit-logs /audit_logs_api.json get /api/v1/logs/audit Paginates forward in time from a given audit log ID. It takes a log ID parameter to begin fetching from and a take parameter for the number of log entries to fetch. For a complete list of all audit log types and their descriptions, see the [Audit Logs Guide](/guides/audit_logs#audit-log-types). ### Permissions Requires `Territory admin` or `Organization admin` permission. # Rate Limits Source: https://developers.harvey.ai/api-reference/ratelimits Harvey API implements rate limiting to ensure fair usage and maintain service stability. Rate limits are applied per organization and are reset every minute. ## Rate Limits by Endpoint | Endpoint Category | Rate Limit (requests/minute) | | --------------------------------- | ---------------------------- | | **Assistant Completion Endpoint** | 20 | | **Vault API Endpoints** | 10 | | **Audit Log Endpoints** | 60 | | **History Export Endpoints** | 2 | | **Client Matters Endpoints** | 150 | ## Handling Rate Limits When you exceed the rate limit, the API returns a `429 Too Many Requests` status code. To handle rate limits effectively: 1. **Monitor the rate limit headers** to track your usage 2. **Implement exponential backoff** when you receive a 429 response 3. **Space out your requests** to stay within the limits 4. **Consider batching operations** where possible to reduce the number of API calls # Get Client Matters Source: https://developers.harvey.ai/api-reference/retrieve/get-client-matters /client_matters_api.json get /api/v1/client_matters Retrieves the full list of client matters in Harvey, including deleted ones, with usage statistics. ### Permissions Requires `Access client matters` permission. # Retrieve Earliest Audit Log Source: https://developers.harvey.ai/api-reference/retrieve/retrieve-earliest-audit-log /audit_logs_api.json get /api/v1/logs/audit/earliest Returns the earliest audit log for the workspace. Useful to begin pagination to get more logs. For a complete list of all audit log types and their descriptions, see the [Audit Logs Guide](/guides/audit_logs#audit-log-types). ### Permissions Requires `Territory admin` or `Organization admin` permission. # Retrieve Latest Audit Log Source: https://developers.harvey.ai/api-reference/retrieve/retrieve-latest-audit-log /audit_logs_api.json get /api/v1/logs/audit/latest Returns the latest audit log for the workspace. Useful to begin pagination to get more logs. For a complete list of all audit log types and their descriptions, see the [Audit Logs Guide](/guides/audit_logs#audit-log-types). ### Permissions Requires `Territory admin` or `Organization admin` permission. # Search Audit Logs Source: https://developers.harvey.ai/api-reference/search/search-audit-logs /audit_logs_api.json get /api/v1/logs/audit/search/ Takes a timestamp as a parameter and returns the audit log at or after the timestamp. Useful to begin pagination to get more logs. For a complete list of all audit log types and their descriptions, see the [Audit Logs Guide](/guides/audit_logs#audit-log-types). ### Permissions Requires `Territory admin` or `Organization admin` permission. # Add Row to Review Table Source: https://developers.harvey.ai/api-reference/vault/add-row-to-review-table /vault_api.json post /api/v1/vault/add_row/{review_table_id} Adds one or more files to an existing review table as new rows and populates each new row's cells for every existing visible column. Send a single file ID in `file_ids` to add it as its own row. Send two or more file IDs to create a **file group** — the files are reviewed together and occupy a single row in the table. Pass the optional `group_name` to name that group; it defaults to the first file's name. Every file must belong to the same Vault project the review table was created from and must have finished processing. Use **List Files in a Vault Project** or **Get File Details** to check a file's `processing_status` before adding it. The run is asynchronous: a successful response means the request was accepted and the rows were scheduled for execution. Poll **Get Review Table Row Details** with the same `review_table_id` and one of the submitted file IDs until the row's cells are returned. For a file group, requesting any member file returns the group's single row. A file that already has a row in the table, or that already belongs to a file group in it, is rejected with `409`; the error message names the offending file ID. Adding a file whose row was previously deleted from the table restores that row rather than creating a duplicate. The `review_table_id` path parameter is the review table's integer ID — the same value as `review_table_ids` entries in **Get Vault Project Metadata** and as `review_table_id` in the **Get Review Table Metadata** response. ### Permissions Requires `Vault API` permission and permission to modify workspace projects. # Create a new Vault project Source: https://developers.harvey.ai/api-reference/vault/create-a-new-vault-project /vault_api.json post /api/v1/vault/create_project Creates a new project in the Vault system. The project can be designated as a knowledge base. ### Permissions Requires `Vault API` and `Modify workspace projects` permissions. # Delete a file from a Vault project Source: https://developers.harvey.ai/api-reference/vault/delete-a-file-from-a-vault-project /vault_api.json delete /api/v1/vault/delete_file/{file_id} Enables authorized organizations to remove an existing file from a Vault project. The endpoint verifies that the file exists and that the requesting user belongs to the file's workspace before proceeding with the deletion. In cases where deletion cannot be immediately completed (for example, if there are pending jobs associated with the file), the API responds with a conflict status. On success, the system logs an audit event and returns confirmation of the deletion. ### Permissions Requires `Vault API` and `Modify workspace projects` permissions. # Delete an entire vault project and all its contents Source: https://developers.harvey.ai/api-reference/vault/delete-an-entire-vault-project-and-all-its-contents /vault_api.json delete /api/v1/vault/delete_project/{project_id} ### Permissions Requires `Vault API` and `Modify workspace projects` permissions. # Get File Details Source: https://developers.harvey.ai/api-reference/vault/get-file-details /vault_api.json get /api/v1/vault/get_files Retrieves details and processing status for one or more files by their IDs. A maximum of 1000 file IDs can be provided per request. This endpoint is useful for checking the processing status of recently uploaded files to determine when they are ready to query. Files that are not found or not accessible are returned with an error field instead of file details. ### Permissions Requires `Vault API` permission. # Get Review Table Metadata Source: https://developers.harvey.ai/api-reference/vault/get-review-table-metadata /vault_api.json get /api/v1/vault/review_table/{review_table_id} Fetches metadata for a single review table by its ID, including its title, creation timestamp, and the list of file IDs associated with it. Use the `review_table_ids` returned by **Get Vault Project Metadata** to enumerate available review tables in a project. Once you have a `review_table_id`, you can: - Call this endpoint to retrieve the table's `title`, `created_at`, and `file_ids`. - Call **Get Review Table Row** with a `review_table_id` and `file_id` to retrieve row-level data for a specific file. ### Permissions Requires `Vault API` permission. # Get Review Table Row Details Source: https://developers.harvey.ai/api-reference/vault/get-review-table-row-details /vault_api.json get /api/v1/vault/get_row/{review_table_id}/{file_id} Enables authorized users to retrieve a row from a review table, given a review table ID and a file ID corresponding to the row. Files that belong to a file group (multiple files reviewed together as a single row) are supported: requesting any file in the group returns the group's row, with `file_id` in the response echoing the requested file. The `review_table_id` path parameter is the review table's integer ID — the same value as `review_table_ids` entries in **Get Vault Project Metadata** and as `review_table_id` in the **Get Review Table Metadata** response. Use **Get Review Table Metadata** to obtain the `file_ids` valid for a given `review_table_id`. For each cell in the response, `summary` contains the short answer and `additional_context` contains the full reasoning behind it. Within each field, a user-edited value takes precedence over the AI-generated value, including the empty string — if a user clears a field, the API returns `""` for that field and sets `is_edited` to `true` rather than falling back to the AI text. The AI value is only used when the user has never edited that field. ### Permissions Requires `Vault API` permission. # Get Vault Project Metadata Source: https://developers.harvey.ai/api-reference/vault/get-vault-project-metadata /vault_api.json get /api/v1/vault/get_metadata/{project_id} Fetches metadata for a specified Vault project, including file details and storage limits. ### Permissions Requires `Vault API` permission. # List Files in a Vault Project Source: https://developers.harvey.ai/api-reference/vault/list-files-in-a-vault-project /vault_api.json get /api/v1/vault/projects/{project_id}/files Lists files within a single vault project, with filtering and sorting supported. **Pagination.** Omit `cursor` on the first request. Subsequent requests should pass back the `next_cursor` value returned in the previous response. Continue until `has_more` is `false`. ### Permissions Requires `Vault API` permission and access to the specified vault project. # List Project Users Source: https://developers.harvey.ai/api-reference/vault/list-project-users /vault_api.json get /api/v1/vault/projects/{project_id}/users Lists all workspace users with current active access to a specified Vault project, along with their access levels. Includes effective user access (including inherited access), and the project owner is always included with `MANAGE` access. Requires vault sharing to be enabled. ### Permissions Requires `Vault API` permission, and either `Vault sharing (view only)` or `Vault sharing` permission. # List Vault Projects and Knowledge Bases Source: https://developers.harvey.ai/api-reference/vault/list-vault-projects-and-knowledge-bases /vault_api.json get /api/v1/vault/workspace/projects Lists all Vault projects and knowledge bases in the current workspace with pagination support. This endpoint returns a paginated list of projects that the authenticated user has permission to view. ### Permissions Requires `View workspace projects` permission. # List Vaults in the Recycle Bin Source: https://developers.harvey.ai/api-reference/vault/list-vaults-in-the-recycle-bin /vault_api.json get /api/v1/vault/workspace/recycle_bin Lists every vault currently in the recycle bin for the current workspace. When a Vault project is deleted it is not purged immediately — it first moves to a workspace recycle bin, where it can be reviewed before being permanently deleted. Entries are ordered by `deleted_at` descending. This endpoint is restricted to workspace vault admins (the same permission as `GET /api/v1/vault/workspace/projects`). ### Permissions Requires `View workspace projects` permission. # Remove Project Users Source: https://developers.harvey.ai/api-reference/vault/remove-project-users /vault_api.json delete /api/v1/vault/projects/{project_id}/users Removes direct workspace user shares for specified users (identified by email address) from a Vault project. Only direct `WORKSPACE_USER` shares are removed; inherited access via workspace, group, or space shares is not affected. Per-user validation failures (e.g. unknown email, inactive user, project owner, self-removal) are returned in the `failed` list rather than rejecting the entire request. Requires vault sharing to be enabled. ### Permissions Requires `Vault API` and `Vault sharing` permissions. # Semantic search over a vault project Source: https://developers.harvey.ai/api-reference/vault/semantic-search-over-a-vault-project /vault_api.json post /api/v1/vault/semantic_search Performs semantic search over documents in a single vault project. Returns the most relevant text chunks for the given natural-language query. Intended for use by external systems (e.g. a customer's own assistant or LLM) that need to retrieve relevant passages and then generate responses using their own models. Requires vault sharing to be enabled. ### Permissions Requires `Vault API` and `Vault sharing` permissions. # Update Project Users Source: https://developers.harvey.ai/api-reference/vault/update-project-users /vault_api.json post /api/v1/vault/projects/{project_id}/users Adds or updates workspace user shares on a Vault project. This endpoint uses an additive/partial-update model: users in the request are added or have their access level updated; users not in the request are left unchanged. The project owner cannot be included in the request. Requires vault sharing to be enabled. ### Permissions Requires `Vault API` and `Vault sharing` permissions. # Upload Files to Project Source: https://developers.harvey.ai/api-reference/vault/upload-files-to-project /vault_api.json post /api/v1/vault/upload_files/{project_id} The Upload Files API endpoint enables organizations to both upload new files and update existing ones within Vault projects. A maximum of 50 files can be uploaded per API request. ### Permissions Requires `Vault API` and `Modify workspace projects` permissions. # Assistant Source: https://developers.harvey.ai/guides/assistant Transform legal workflows with powerful AI-powered reasoning Harvey's Assistant API enables powerful legal reasoning over your documents and data. With a single endpoint, you can embed natural language queries, document analysis, and grounded legal insights directly into your applications and workflows. The current API request rate limit for Assistant API endpoint is **20 requests per minute**. ```bash theme={null} POST /api/v2/completion ``` ## Overview The Assistant API provides AI-powered responses to complex legal questions, document analysis, and specialized tasks. Use it to build intelligent legal applications that deliver accurate, context-aware results to your users. ### Key Capabilities * **Natural Language Processing**: Process complex legal queries with nuanced understanding * **Document Analysis**: Extract insights from contracts and legal documents * **Knowledge Grounding**: Upload relevant documents to provide context * **Content Generation**: Create professional drafts for emails and responses ## Use Cases ### Use Case 1: Internal Knowledge Chatbot **Challenge**: Attorneys often need quick access to firm policies, past contract negotiations, case law, or regulatory updates. Searching through internal databases or asking colleagues takes time and disrupts workflows. By integrating Harvey’s AI into internal chatbots, firms empower attorneys to instantly retrieve relevant legal insights, improving efficiency without sacrificing accuracy. **Solution**: Integrate the Assistant API into a secure internal chatbot to return policy guidance, research, and previous work product on demand. ```json theme={null} { "prompt": "Summarize our indemnity position in past vendor contracts.", "stream": false } ``` ### Use Case 2: Self-Serve Legal Guidance **Challenge**: Business teams frequently need input on policies, contracts, compliance, and other complex topics. Waiting for expert review slows down workflows and creates bottlenecks. **Solution**: Embed the Assistant API in internal tools to offer reliable, policy-grounded answers instantly. ```json theme={null} { "prompt": "Can I sign this NDA or does it need legal review?", "stream": false } ``` ### Use Case 3: Drafting Responses to Legal Inquiries **Challenge**: Drafting accurate and professional responses for routine legal questions is repetitive and time-consuming. **Solution**: Use the Assistant API to generate draft replies to client or internal questions directly within email tools. ```json theme={null} { "prompt": "Draft a response to this client email about contract renewal timing: 'Hi, our agreement is coming up for renewal next month. Can you please advise on our options and the timeline we should follow?'", "mode": "draft", "stream": false } ``` ### Use Case 4: Document Ingestion in ETL Pipelines **Challenge**: Manually ingesting and analyzing documents from diverse sources slows down workflows. **Solution**: Automate document classification and summarization as part of backend ingestion systems. ```json theme={null} { "prompt": "Extract key clauses and obligations from the attached contract.", "stream": false } ``` ### Use Case 5: AI-Powered Document Review in Third-Party Platforms **Challenge**: Assessing vendor documents for compliance with regulations or internal policies is repetitive and resource-intensive. **Solution**: Integrate Harvey with vendor management tools to automatically review documents against internal playbooks. ```json theme={null} { "prompt": "Does this MSA comply with our internal data security standards?", "stream": false } ``` ## Best Practices ### Optimize Prompts * **Avoid**: "Review this contract" * **Use**: "Identify and summarize indemnity clauses in this vendor MSA and flag any deviations from our standard policy." ### Stay Within Prompt Limits If you're uploading a file, limit the prompt to 4,000 characters. Without a file, prompts can be up to 20,000 characters. ### Stream vs. Non-Stream Set `stream: true` if you want to receive partial results as they are generated. Default is `false`. ### Model selection You can pass an optional **model** form parameter to choose which model handles the request. Omit the parameter to use your workspace's default model. **Supported model slugs:** `gpt-5`, `gpt-5-1`, `gpt-5-2`, `gpt-5-4`, `gpt-5-4-mini`, `gpt-5-5`, `gpt-4-1`, `claude-opus-4-5`, `claude-sonnet-4-5`, `claude-opus-4-6`, `claude-opus-4-7`. ## Error Handling The Assistant API uses standard HTTP status codes. Always check and handle error responses appropriately. | Status Code | Description | Example Error Message | | ----------- | --------------------------------------- | ------------------------------------------- | | 200 | Success | N/A | | 400 | Bad Request – Invalid parameters | `{ "error": "Missing prompt parameter" }` | | 401 | Unauthorized – Invalid API key | `{ "error": "Invalid API key provided" }` | | 429 | Too Many Requests – Rate limit exceeded | `{ "error": "Rate limit exceeded" }` | | 500 | Internal Server Error | `{ "error": "An internal error occurred" }` | *** Need help getting started? Contact your Harvey Customer Success Manager for more information. # Audit Log Example Source: https://developers.harvey.ai/guides/audit-logs-example # Using the Public API v1 Audit Log APIs This guide explains how to retrieve audit logs via the Public API using the **search** and **query** endpoints. The main idea: **you use a timestamp once to find a starting point, then use log IDs for all actual retrieval and pagination.** ## **Why log IDs instead of timestamps?** * **Search by time** is supported only to get a **starting point** (the first log at or after a given time). The API returns one log and its **ID**. * **Fetching and pagination** use that **log ID** (and then the ID of the last log in each page). We do not support “give me all logs between 10:00 and 10:15” by timestamp in a single call. Reasons we key off IDs: 1. **Stable ordering** — Logs are ordered by ID. IDs are unique and never change, so pagination is consistent even if many events share the same second. 2. **No gaps or duplicates** — Using “last seen ID” as the cursor avoids skipping or duplicating logs when events are dense. 3. **Clear “next page”** — The next request is always “logs after this ID,” which is unambiguous. So: **think of the timestamp as “where do I start?”** and **the log ID as “where am I in the stream?”** for all subsequent requests. ## **The two endpoints** | **Purpose** | **Endpoint** | **You provide** | **You get** | | :------------------------------- | :----------------------------------------------- | :------------------------------------------------------- | :---------------------------------------------------------------------------------------- | | **Find a starting log by time** | `GET /api/v1/logs/audit/search?time=` | A timestamp (e.g. 10:00 AM) | One log object — the **first** log at or after that time. That log’s `id` is your cursor. | | **Fetch logs after a given log** | `GET /api/v1/logs/audit?from=&take=` | A log ID (`from`) and how many to fetch (`take`, 1–1000) | Up to `take` logs whose ID is **after** `from`, in ascending order by ID. | Important details: * **Search** returns a **single** log: the first one with `timestamp >=` your `time`. The response body is `{ "log": { "id": "...", "timestamp": "...", ... } }`. You need that `log.id` for the next step. * **Query** returns logs with **ID strictly greater than** `from`. So the log you got from search is **not** included in the first query response — it is the first log in your time range; you add it to your results yourself, then use its ID to fetch the rest. Base URL for the Public API: `https://api.harvey.ai` (or your environment’s base URL). Full paths are `/api/v1/logs/audit/search` and `/api/v1/logs/audit`. See [developers.harvey.ai](https://developers.harvey.ai) for the full API reference. ## **Example 1: “All logs since 10:00 AM”** Goal: at 10:15 AM, get every audit log from 10:00 AM onward. ### **Step 1 — Get the first log and its ID (timestamp → ID)** * Call: `GET /api/v1/logs/audit/search?time=<10:00 AM in ISO 8601 or your API’s accepted format>` * Response: `{ "log": { "id": "abc-123-...", "timestamp": "2025-03-11T10:00:00.000Z", ... } }` * **Keep this log** — it is the first log in your range. Add it to your result set. * **Save** `log.id` (e.g. `abc-123-...`) — this is your cursor for the next request. If the response is an error (e.g. no logs available for that time), there are no logs at or after 10:00 AM; you’re done. ### **Step 2 — Fetch the next logs (ID-based)** * Call: `GET /api/v1/logs/audit?from=abc-123-...&take=1000` * Response: `{ "logs": [ ... ] }` — up to 1000 logs whose ID is **after** `abc-123-...`. Append these to your result set. ### **Step 3 — Paginate if needed** * Each response contains **at most** `take` logs (here, 1000). You never get “more than 1000” in one response. * If you got **exactly 1000** logs, there may be more. Take the **last** log in the array and use its `id` as the new `from`: * `GET /api/v1/logs/audit?from=&take=1000` * Repeat until a response has **fewer than 1000** logs — then there are no more. Your full “logs since 10:00 AM” set is: **\[log from Step 1] + \[all logs from Step 2 and Step 3].** ## **Example 2: “A 15-minute slice starting at 8:00 AM”** Goal: all logs from 8:00 AM to 8:15 AM. You still use **search** to turn “8:00 AM” into a starting log ID, then **query** by ID. The only extra part is **stopping** when logs go past 8:15 AM. ### **Step 1 — Get the first log at or after 8:00 AM** * Call: `GET /api/v1/logs/audit/search?time=<8:00 AM>` * Keep the returned **log** as the first log in your slice. * Save `log.id` for the next request. ### **Step 2 — Fetch in pages and stop at the end time** * Call: `GET /api/v1/logs/audit?from=&take=1000` * For each log in `logs`, check its `timestamp`: * If `timestamp <= 8:15 AM` → include it in your 15-minute slice. * If `timestamp > 8:15 AM` → you’ve passed the end of the window; stop requesting more and (optionally) drop any later logs from this batch. * If you got 1000 logs and the last one is still before or at 8:15 AM, there may be more in that window. Use the **last** log’s `id` as `from` and call again. Repeat until you either get fewer than 1000 logs or you see a timestamp after 8:15 AM. So: **timestamps** are used only to (1) find the start via search and (2) filter or stop when you’ve reached your end time. **IDs** are used for every “give me the next page” request. ## **Summary** * **Timestamps** answer: “Where do I start?” (search) and “Where do I stop?” (your own end-time filter). * **Log IDs** answer: “What’s the next page?” (query’s `from` and pagination). * Always **include the log returned by search** in your results; the first **query** call returns only logs **after** that log’s ID. * Pagination: use the **last** log’s ID from each response as `from` for the next request; when you get fewer than `take` logs, you’ve reached the end. For exact parameter names, formats, and error codes, use the [Public API reference](https://developers.harvey.ai) for the audit log endpoints. # Audit Logs Source: https://developers.harvey.ai/guides/audit_logs Query and retrieve audit logs for workspace activity monitoring The Audit Log API allows customers to query audit logs for their workspace. These APIs cover ways to query audit logs at a given time or from an ID and how to paginate through audit logs over time. The current API request rate limits for Audit Log API endpoints are **60 requests per minute**. ```bash theme={null} GET /api/v1/logs/audit/search GET /api/v1/logs/audit/earliest GET /api/v1/logs/audit/latest GET /api/v1/logs/audit ``` ## Overview Use the Audit Log API to: * **Track User Activity**: Monitor all actions taken by users in your workspace * **Maintain Compliance**: Keep detailed records for audit and compliance purposes * **Investigate Incidents**: Retrieve historical logs to investigate specific events * **Export Records**: Fetch and store audit logs in your own systems *** ## Endpoints ### Search Audit Logs ```bash theme={null} GET /api/v1/logs/audit/search ``` Returns the audit log at or after a specified timestamp. Useful to begin pagination from a specific point in time. **Parameters:** * `time` (required): UTC epoch timestamp, up to 1 year old from now * `log_type` (optional): Filter to return only logs of a specific type (e.g., `auth:login`, `admin:add_users`) **Example:** ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/logs/audit/search?time=1712066546" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` **Example with filtering by log type:** ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/logs/audit/search?time=1712066546&log_type=auth:login" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` ### Get Earliest Audit Log ```bash theme={null} GET /api/v1/logs/audit/earliest ``` Returns the earliest audit log for the workspace. Useful to begin pagination from the very beginning. **Parameters:** * `log_type` (optional): Filter to return only logs of a specific type (e.g., `auth:login`, `admin:add_users`) **Example:** ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/logs/audit/earliest" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` **Example with filtering by log type:** ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/logs/audit/earliest?log_type=auth:login" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` ### Get Latest Audit Log ```bash theme={null} GET /api/v1/logs/audit/latest ``` Returns the latest audit log for the workspace. Useful to begin pagination from the most recent event. **Parameters:** * `log_type` (optional): Filter to return only logs of a specific type (e.g., `auth:login`, `admin:add_users`) **Example:** ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/logs/audit/latest" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` **Example with filtering by log type:** ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/logs/audit/latest?log_type=auth:login" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` ### Query Audit Logs ```bash theme={null} GET /api/v1/logs/audit ``` Paginates forward in time from a given audit log ID. Use this endpoint to fetch multiple log entries at once. **Parameters:** * `from` (required): Audit log ID to begin fetching from (UUID format) * `take` (required): Number of audit log entries to fetch (max 1000) * `log_type` (optional): Filter to return only logs of a specific type (e.g., `auth:login`, `admin:add_users`) **Example:** ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/logs/audit?from=018e983f-d10f-72aa-9c94-d8263e53c6a4&take=100" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` **Example with filtering by log type:** ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/logs/audit?from=018e983f-d10f-72aa-9c94-d8263e53c6a4&take=100&log_type=auth:login" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` *** ## Audit Log Types Each audit log entry includes a `type` field that identifies the specific action performed. Below is a complete list of audit log types you may encounter: ### API Operations | Audit Log Type | Description | | ------------------------------ | -------------------------------- | | `api:audit_log_fetch` | Fetches audit logs via API | | `api:create_query` | Creates a query via API | | `api:client_matter_management` | Manages client matters via API | | `api:history_fetch` | Fetches history records via API | | `api:token_mgmt_rotate` | Rotates API tokens | | `api:vault_list_projects` | Lists vault projects via API | | `api:vault_get_metadata` | Gets vault metadata via API | | `api:vault_upload_files` | Uploads files to vault via API | | `api:vault_delete_file` | Deletes files from vault via API | | `api:vault_delete_project` | Deletes vault projects via API | ### Authentication | Audit Log Type | Description | | -------------- | ----------------------------- | | `auth:login` | User login | | `auth:logout` | User logout | | `auth:failed` | Failed authentication attempt | ### Admin Operations | Audit Log Type | Description | | ------------------------------------------ | ----------------------------------------------------- | | `admin:client_view_workspace_history` | Admin views workspace history in client | | `admin:fetch_workspace_history` | Admin fetches workspace history | | `admin:client_view_workspace_history_item` | Admin views specific workspace history item in client | | `admin:fetch_workspace_history_item` | Admin fetches specific workspace history item | | `admin:delete_workspace_history_item` | Admin deletes workspace history item | | `admin:delete_workspace_history_items` | Admin deletes multiple workspace history items | | `admin:export_workspace_history` | Admin exports workspace history | | `admin:export_query_usage` | Admin exports query usage data | | `admin:client_export_workspace_users` | Admin exports workspace users from client | | `admin:add_users` | Admin adds users | | `admin:remove_users` | Admin removes users | | `admin:grant_perms` | Admin grants permissions | | `admin:revoke_perms` | Admin revokes permissions | | `admin:create_role` | Admin creates role | | `admin:update_role` | Admin updates role | | `admin:delete_role` | Admin deletes role | | `admin:update_user_role` | Admin updates user role | | `admin:create_export_template` | Admin creates export template | | `admin:edit_export_template` | Admin edits export template | | `admin:delete_export_template` | Admin deletes export template | | `admin:download_export_template` | Admin downloads export template | | `admin:bulk_update_role_configs` | Admin bulk updates role configurations | | `admin:get_role_users` | Admin gets users for a role | | `admin:fetch_client_matters` | Admin fetches client matters | | `admin:add_client_matters` | Admin adds client matters | | `admin:delete_client_matters` | Admin deletes client matters | | `admin:enable_integration` | Admin enables integration | | `admin:disable_integration` | Admin disables integration | | `admin:update_integration` | Admin updates integration | | `admin:update_client_matters` | Admin updates client matters | | `admin:manage_client_matters` | Admin manages client matters | | `admin:fetch_stats` | Admin fetches statistics | | `admin:fetch_workspace_users` | Admin fetches workspace users | | `admin:update_sharing_settings` | Admin updates sharing settings | | `admin:upsert_workspace_notice` | Admin creates or updates workspace notice | | `admin:upsert_workspace_guidance` | Admin creates or updates workspace guidance | | `admin:upsert_workspace_logo` | Admin creates or updates workspace logo | | `admin:delete_workspace_logo` | Admin deletes workspace logo | | `admin:update_workspace_brand_name` | Admin updates workspace brand name | | `admin:edit_user_profile` | Admin edits user profile | | `admin:update_playbook_permissions` | Admin updates playbook permissions | | `admin:publish_playbook` | Admin publishes playbook | | `admin:unpublish_playbook` | Admin unpublishes playbook | ### User Operations | Audit Log Type | Description | | ---------------------------------------------- | ----------------------------------------------- | | `user:create_query` | User creates query | | `user:client_view_history` | User views history in client | | `user:fetch_history` | User fetches history | | `user:client_view_history_item` | User views specific history item in client | | `user:fetch_history_item` | User fetches specific history item | | `user:update_history_item` | User updates history item | | `user:delete_history_item` | User deletes history item | | `user:cancel_history_item` | User cancels history item | | `user:fetch_client_matters` | User fetches client matters | | `user:add_client_matters` | User adds client matters | | `user:delete_client_matters` | User deletes client matters | | `user:update_client_matters` | User updates client matters | | `user:fetch_vault_top_level_folders` | User fetches vault top-level folders | | `user:fetch_vault_example_project` | User fetches vault example project | | `user:set_vault_example_project` | User sets vault example project | | `user:unset_vault_example_project` | User unsets vault example project | | `user:fetch_vault_folder_path` | User fetches vault folder path | | `user:fetch_project_metadata` | User fetches project metadata | | `user:fetch_vault_folder` | User fetches vault folder | | `user:fetch_vault_file` | User fetches vault file | | `user:fetch_vault_file_review_rows` | User fetches vault file review rows | | `user:fetch_vault_files` | User fetches vault files | | `user:fetch_vault_folders_by_path` | User fetches vault folders by path | | `user:create_vault_folder` | User creates vault folder | | `user:create_vault_review_query` | User creates vault review query | | `user:upload_vault_files` | User uploads vault files | | `user:update_vault_file_metadata` | User updates vault file metadata | | `user:update_vault_folder_metadata` | User updates vault folder metadata | | `user:delete_vault_files` | User deletes vault files | | `user:delete_vault_folder` | User deletes vault folder | | `user:fetch_query_questions` | User fetches query questions | | `user:semantic_search_with_vault_folder` | User performs semantic search with vault folder | | `user:retry_vault_files` | User retries vault files | | `user:rerun_vault_review_queries` | User reruns vault review queries | | `user:mark_review_event_completed` | User marks review event as completed | | `user:clear_vault_query_errors` | User clears vault query errors | | `user:fetch_vault_review_query_usage` | User fetches vault review query usage | | `user:fetch_vault_folder_history_stats` | User fetches vault folder history stats | | `user:fetch_vault_projects_history_stats` | User fetches vault projects history stats | | `user:create_vault_folder_sharing_permissions` | User creates vault folder sharing permissions | | `user:update_vault_folder_sharing_permissions` | User updates vault folder sharing permissions | | `user:delete_vault_folder_sharing_permissions` | User deletes vault folder sharing permissions | | `user:create_event_sharing_permissions` | User creates event sharing permissions | | `user:update_event_sharing_permissions` | User updates event sharing permissions | | `user:create_library_item` | User creates library item | | `user:update_library_item` | User updates library item | | `user:delete_library_item` | User deletes library item | | `user:connect_integration` | User connects integration | | `user:disconnect_integration` | User disconnects integration | | `user:fetch_connected_integrations` | User fetches connected integrations | | `user:fetch_integration_token` | User fetches integration token | | `user:export_library` | User exports library | | `user:accept_workspace_notice` | User accepts workspace notice | | `user:enable_workspace_feature` | User enables workspace feature | | `user:disable_workspace_feature` | User disables workspace feature | | `user:view_dms_one_way_sync` | User views DMS one-way sync | | `user:create_dms_one_way_sync` | User creates DMS one-way sync | | `user:trigger_dms_one_way_sync` | User triggers DMS one-way sync | | `user:update_dms_one_way_sync` | User updates DMS one-way sync | | `user:delete_dms_one_way_sync` | User deletes DMS one-way sync | | `user:dms_folder_upload` | User uploads folder via DMS | | `user:bulk_patch_resource_access` | User bulk patches resource access | | `user:revoke_resource_access` | User revokes resource access | | `user:list_resource_access` | User lists resource access | | `user:dms_file_import` | User imports file from DMS | | `user:dms_file_export` | User exports file to DMS | | `user:add_user_profile` | User adds user profile | | `user:edit_user_profile` | User edits user profile | | `user:fetch_vault_history_item` | User fetches vault history item | | `user:review_playbook_document` | User reviews playbook document | | `user:create_playbook` | User creates playbook | | `user:create_user_group` | User creates user group | | `user:add_user_group_members` | User adds user group members | | `user:remove_user_group_members` | User removes user group members | | `user:get_user_group_members` | User gets user group members | | `user:get_user_group` | User gets user group | | `user:list_user_groups` | User lists user groups | | `user:delete_user_group` | User deletes user group | | `user:delete_playbook` | User deletes playbook | | `user:update_playbook` | User updates playbook | | `user:convert_playbook_document` | User converts playbook document | | `user:fetch_playbook_permissions` | User fetches playbook permissions | | `user:duplicate_playbook` | User duplicates playbook | | `user:export_playbook_review` | User exports playbook review | | `user:export_playbook` | User exports playbook | | `user:list_playbooks` | User lists playbooks | | `user:fetch_playbook_history` | User fetches playbook history | | `user:fetch_playbook_version` | User fetches playbook version | ### Microsoft add-ins Microsoft Word and Outlook add-in activity is captured as user audit log events. You can filter for these events with the `log_type` query parameter, for example `log_type=user:word_add_in_docx_drafting` or `log_type=user:outlook_add_in_ask`. #### Word add-in | Audit Log Type | Description | | --------------------------------------------- | ---------------------------------------------------------------- | | `user:word_add_in_ask` | User submits a Word add-in ask request | | `user:word_add_in_docx_drafting` | User drafts or edits a Word document using the Word add-in agent | | `user:word_add_in_proofread_document` | User proofreads a document from the Word add-in | | `user:word_redact` | User runs Redact or Convert to Template from the Word add-in | | `user:word_fill_template` | User runs Fill Template from the Word add-in | | `user:word_suggest` | User requests Word add-in suggestions | | `user:playbook_suggest` | User requests Playbook suggestions from the Word add-in | | `user:word_contextual_prompts` | User requests contextual prompts from the Word add-in | | `user:word_add_in_insert` | User inserts generated text from the Word add-in | | `user:word_add_in_apply_edit` | User applies a Word add-in edit | | `user:word_add_in_apply_suggestions` | User applies Word add-in suggestions | | `user:word_add_in_dismiss_suggestions` | User dismisses Word add-in suggestions | | `user:word_add_in_restore_suggestions` | User restores Word add-in suggestions | | `user:word_add_in_update_suggestions` | User updates Word add-in suggestions | | `user:word_add_in_create_word_document` | User creates a Word document session | | `user:word_add_in_get_word_document` | User fetches a Word document session or snapshot | | `user:word_add_in_get_latest_export_event` | User fetches the latest export event for a Word document | | `user:word_add_in_get_word_event_suggestions` | User fetches suggestions for Word events | | `user:word_add_in_get_history` | User fetches Word add-in history | | `user:word_add_in_format_ooxml` | User formats OOXML from the Word add-in | | `user:word_add_in_extract_definitions` | User extracts definitions from the Word add-in | | `user:word_add_in_get_contextual_prompts` | User fetches Word add-in contextual prompts | | `user:word_add_in_metadata_redaction` | User redacts metadata from the Word add-in | | `user:word_add_in_translation` | User translates content from the Word add-in | | `user:word_add_in_detect_language` | User detects document language from the Word add-in | #### Outlook add-in | Audit Log Type | Description | | --------------------------- | ----------------------------------------------------------- | | `user:outlook_add_in_ask` | User submits an initial ask request from the Outlook add-in | | `user:create_outlook_email` | User creates an Outlook email session | | `user:get_outlook_email` | User fetches an Outlook email session | ### System Operations | Audit Log Type | Description | | --------------------------------- | -------------------------------- | | `system:trigger_dms_one_way_sync` | System triggers DMS one-way sync | ### Shared Spaces Shared Spaces and external connection audit logs capture collaboration activity: space membership, resource publishing, and external connection lifecycle. Events are scoped per workspace; each workspace sees audit events for actions its users perform or approve. #### Space membership and lifecycle | Audit Log Type | Description | | -------------------------------------- | ------------------------------------------------------------------------------- | | `user:spaces_add_members_to_space` | User requested one or more people to be added to a shared space | | `user:spaces_member_approval_changed` | A member was approved (or status changed) to be added to a shared space | | `admin:approve_collab_request` | Admin approved a collaboration request (member or resource addition to a space) | | `admin:decline_collab_request` | Admin declined a collaboration request | | `admin:cancel_collab_request` | Admin cancelled a collaboration request | | `admin:approve_space_request` | Admin approved a space request | | `admin:decline_space_request` | Admin declined a space request | | `user:spaces_remove_member_from_space` | A member was removed from a shared space | | `user:spaces_leave_space` | A user left a shared space | | `user:spaces_create_space` | User created a new shared space | | `user:spaces_update_space` | User updated shared space settings (e.g. name, color) | | `user:spaces_delete_space` | User deleted a shared space | | `user:spaces_get_home_page` | User viewed the Shared Spaces home page | | `user:spaces_get_details_page` | User viewed a specific shared space’s details page | | `user:list_collab_requests` | User listed collaboration requests | | `user:get_collab_request` | User retrieved a collaboration request | #### Resource sharing in spaces | Audit Log Type | Description | | --------------------------------------- | ------------------------------------------------------------------------------ | | `user:spaces_add_resources_to_space` | User requested to publish resources (e.g. playbooks, vaults) to a shared space | | `user:spaces_resource_approval_changed` | Resource(s) were approved and added to a shared space (new access granted) | | `user:spaces_resource_unshared` | Resource(s) were removed from a shared space | | `user:spaces_get_publishable_resources` | User fetched the list of resources that can be published to a space | | `user:spaces_get_members` | User fetched members of a space | | `user:spaces_get_invitable_members` | User fetched invitable members for a space | #### External connections | Audit Log Type | Description | | ------------------------------------------------ | ----------------------------------------------------- | | `admin:create_external_connection_invite` | Admin created an external connection invite | | `admin:update_external_connection_invite` | Admin updated an external connection invite | | `admin:approve_external_connection_request` | Admin approved an external connection request | | `admin:reject_external_connection_request` | Admin rejected an external connection request | | `admin:add_users_to_external_connection` | Admin added users to an external connection | | `admin:remove_user_from_external_connection` | Admin removed a user from an external connection | | `admin:update_user_role_in_external_connection` | Admin updated a user’s role in an external connection | | `admin:remove_resource_from_external_connection` | Admin removed a resource from an external connection | | `admin:delete_external_connection` | Admin deleted an external connection | | `user:get_external_connections_requests_page` | User viewed the external connection requests page | | `user:get_external_connections_details_page` | User viewed the external connection details page | *** ## Use Cases ### Use Case 1: Compliance Monitoring and Audit Trail Capture **Challenge**: Organizations must maintain detailed records of all user activity for compliance and regulatory requirements. **Solution**: Regularly fetch and store audit logs using the pagination workflow. Each log entry includes the user, timestamp, IP address, and action type. ### Use Case 2: Incident Response and User Investigations **Challenge**: When investigating a security incident, teams need to reconstruct what happened during a specific time period. **Solution**: Use `/search?time=` to start from a specific point in time, then paginate through subsequent logs to track all activity during the incident window. ### Use Case 3: Continuous Monitoring **Challenge**: Security teams need to monitor recent activity in near real-time. **Solution**: Periodically poll `/latest` to get the most recent log entry, then use `/audit?from=&take=100` to fetch any new logs since the last check. *** ## Regular Cadence Fetching For continuous monitoring and compliance requirements, you'll want to fetch audit logs on a regular schedule. Here's the recommended approach: ### Initial Backfill If you're setting up audit log collection for the first time: ```python theme={null} import requests import time token = "YOUR_API_KEY" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {token}" } # Start from the earliest log response = requests.get("https://api.harvey.ai/api/v1/logs/audit/earliest", headers=headers) current_log = response.json()["log"] # Save to your database save_to_database([current_log]) last_processed_id = current_log["id"] # Paginate through all historical logs while True: time.sleep(1) # Respect 60 req/min rate limit response = requests.get( f"https://api.harvey.ai/api/v1/logs/audit?from={last_processed_id}&take=1000", headers=headers ) logs = response.json() if not logs: break save_to_database(logs) last_processed_id = logs[-1]["id"] print(f"Processed {len(logs)} logs, last ID: {last_processed_id}") # Store checkpoint in database save_checkpoint(last_processed_id) ``` ### Incremental Updates After your initial backfill, run this on a regular schedule (e.g., every 5-15 minutes): ```python theme={null} import requests import time token = "YOUR_API_KEY" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {token}" } # Load the last processed ID from your database last_processed_id = load_checkpoint() # Fetch new logs since last check response = requests.get( f"https://api.harvey.ai/api/v1/logs/audit?from={last_processed_id}&take=1000", headers=headers ) new_logs = response.json() if new_logs: save_to_database(new_logs) # Update the checkpoint last_processed_id = new_logs[-1]["id"] save_checkpoint(last_processed_id) print(f"Fetched {len(new_logs)} new logs") else: print("No new logs since last check") ``` ### Scheduling Recommendations * **High-activity workspaces**: Poll every 5-10 minutes with `take=1000` * **Medium-activity workspaces**: Poll every 15-30 minutes with `take=500` * **Low-activity workspaces**: Poll hourly with `take=100` ### Key Considerations * **Persistent storage**: Always save the last processed log ID to disk/database so your process can resume after restarts. * **Idempotency**: Audit logs are immutable, so it's safe to reprocess the same log multiple times if needed. * **Error handling**: If a fetch fails, retry from the same log ID and don't skip ahead. * **Rate limiting**: With the 60 req / min, fetching 1000 logs takes approximately 1 second per batch. Plan your cadence accordingly. * **Gap detection**: Monitor timestamps to detect if you're falling behind. If the latest fetched timestamp is more than your polling interval old, increase frequency or batch size. *** ## Best Practices * **Respect rate limits**: The API is limited to 60 requests per minute. Implement appropriate delays in your polling logic * **Store logs externally**: Export audit logs to your own SIEM or audit repository for long-term retention and analysis * **Handle timestamps correctly**: The `time` parameter uses UTC epoch timestamps (seconds since January 1, 1970) * **Track pagination state**: Always save the last processed log ID to persistent storage to resume pagination if your process is interrupted * **Monitor for new event types**: The API may add new event types over time, so build your parsing logic to handle unknown types gracefully * **Implement retries with backoff**: If you hit rate limits or encounter errors, implement exponential backoff before retrying * **Deduplicate on ingestion**: Use the log `id` field as a unique identifier to prevent duplicate storage if you need to reprocess logs * **Set up alerting**: Monitor your sync process to ensure logs are being fetched regularly and alert if the process fails * **Use log\_type filtering when needed**: When you only need specific types of logs, use the `log_type` parameter to filter server-side and reduce bandwidth, processing overhead, and API calls ## Error Handling | Status Code | Description | Example Error Message | | ----------- | --------------------------------------- | ----------------------------------------- | | 200 | Success | N/A | | 400 | Bad Request – Invalid query input | `{ "error": "Missing required filters" }` | | 401 | Unauthorized – Invalid API key | `{ "error": "Unauthorized" }` | | 429 | Too Many Requests – Rate limit exceeded | `{ "error": "Rate limit exceeded" }` | | 500 | Internal Server Error | `{ "error": "Unexpected server error" }` | *** Need help getting started? Contact your Harvey Customer Success Manager for more information. # Authentication Source: https://developers.harvey.ai/guides/authentication To create and manage API tokens for your organization’s workspace, visit the “API Tokens” section in your workspace settings. If this section isn’t visible to you, or you need more help getting started, contact your Customer Success Manager. The Harvey API uses bearer token authentication. Include the token in the Authorization header of all API requests. ```bash theme={null} curl https://api.harvey.ai/v2/endpoint \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -H "Content-Type: application/json" ``` # Security Your bearer tokens grant access to sensitive data and privileged operations, so they must be kept secure. Never share tokens in public repositories, client-side code, or unsecured channels. If you need to contact Harvey support, make sure to redact your token from any example requests or screenshots. To help you further control what can be done with your bearer tokens, each token also has a manageable permissions list which can be used to restrict what API endpoints can be used with the token. Consult the API Tokens setting page to learn more. # HTTPS All API requests must use HTTPS. Requests sent over HTTP or without authentication will be rejected. If your organization is using Harvey’s EU-hosted deployment, update the request URL to point to the EU API endpoint: **[https://eu.api.harvey.ai](https://eu.api.harvey.ai)** ```bash theme={null} curl https://eu.api.harvey.ai/v2/endpoint \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -H "Content-Type: application/json" ``` # Client Matters Source: https://developers.harvey.ai/guides/client_matters Manage billing attribution and access control for legal work The Client Matter API allows you to programmatically create, retrieve, and remove client-matter associations in Harvey. This enables alignment of usage and query activity with specific billing codes, legal engagements, or internal projects. The current API request rate limits for Client Matter API endpoints are **150 requests per minute**. ```bash theme={null} POST /api/v1/client_matters GET /api/v1/client_matters DELETE /api/v1/client_matters ``` ## Overview Use the Client Matter API to: * **Track Usage by Client Matter**: Attribute usage to specific clients or matters * **Streamline Onboarding**: Bulk upload client-matter lists during rollout * **Maintain Clean Data**: Deactivate unused or outdated entries *** ## Endpoints ### Add or Update Client Matters ```bash theme={null} POST /client_matters ``` ```bash theme={null} curl -X POST https://api.harvey.ai/api/v1/client_matters \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "client_matters": [ { "cm_name": "M-2024-0034", "cm_desc": "Doe vs. Smith", "cm_allowed": "true" }, { "cm_name": "M-2025-0094", "cm_desc": "Fisher vs. Smith", "cm_allowed": "false" } ] }' ``` ### List Existing Client Matters ```bash theme={null} GET /client_matters ``` ```bash theme={null} curl -X GET https://api.harvey.ai/api/v1/client_matters \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Delete Client Matters ```bash theme={null} DELETE /client_matters ``` ```bash theme={null} curl -X DELETE https://api.harvey.ai/api/v1/client_matters \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "client_matters": ["M-2024-0035"] }' ``` *** ## Use Cases ### Use Case 1: Bulk Onboarding of Client Matters **Challenge**: Large firms need to load thousands of client-matter combinations before go-live. **Solution**: Use the POST endpoint to upload up to 10,000 entries at once. ### Use Case 2: Enforcing Scope-Based Access **Challenge**: Admins need to ensure users only access work linked to authorized matters. **Solution**: Sync client-matter assignments with workspace or group-level permissions. ### Use Case 3: Cleaning Up Inactive Matters **Challenge**: Outdated entries clutter reporting and can lead to billing confusion. **Solution**: Use the DELETE endpoint to retire no-longer-used matter IDs. *** ## Best Practices * **Normalize naming**: Ensure consistent `client_id`, `matter_id`, and `name` conventions across systems * **Automate imports**: Tie the POST endpoint to your firm’s intake or billing system * **Verify before deletion**: Always run a `GET` call before using DELETE to confirm matter IDs * **Track usage attribution**: Cross-reference matter IDs in `/history/usage` and `/history/query` responses * **Use clear naming**: Populate the `name` field with a human-readable description for internal clarity ## Error Handling | Status Code | Description | Example Error Message | | ----------- | --------------------------------------- | ---------------------------------------- | | 200 | Success | N/A | | 400 | Bad Request – Invalid format | `{ "error": "Missing client_id" }` | | 401 | Unauthorized – Invalid API key | `{ "error": "Unauthorized" }` | | 429 | Too Many Requests – Rate limit exceeded | `{ "error": "Rate limit exceeded" }` | | 500 | Internal Server Error | `{ "error": "Unexpected server error" }` | *** Need help getting started? Contact your Harvey Customer Success Manager for more information. # Harvey MCP Source: https://developers.harvey.ai/guides/harvey_mcp connect AI assistants to Harvey's legal AI capabilities through MCP. The Harvey MCP Server gives AI assistants secure access to Harvey's legal AI capabilities through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction), an open standard for connecting AI tools to external data and services. ## What is the Harvey MCP Server? The Harvey MCP Server exposes some of Harvey's core features — legal Q\&A, Vault document analysis, and research knowledge sources as MCP tools. It is designed to work with MCP-compatible clients such as Claude, Google Gemini, and Microsoft 365 Copilot. ### What can you do with the Harvey MCP Server? * **Ask general legal questions** — Get answers from Harvey's broad legal knowledge without referencing specific documents. * **Analyze Vault documents** — Ask questions about documents in your Vault projects with source citations. * **Discover resources** — List your Vault projects and available knowledge sources to find the right context for your questions. * **Research with knowledge sources** — Query specialized legal research databases like UK tax law. Harvey's MCP integration allows you to connect Harvey to third-party AI assistants like Claude, Google Gemini, and Microsoft 365 Copilot. Any data sent to or processed by those third-party services is subject to your agreements with those providers. Harvey is not responsible for how third-party services handle data once it leaves Harvey's systems. *** ## Setup guides ### Prerequisites * A Harvey account * An MCP-compatible AI assistant. Harvey MCP works with Anthropic's Claude, Google Gemini, and Microsoft 365 Copilot. * Your client must support remote MCP servers over Streamable HTTP transport with OAuth authentication. ### Claude Web 1. Open and sign in to [Claude](https://claude.ai). 2. Go to **Settings**. 3. Go to **Connectors**, search for **Harvey**. 4. Connect, authenticate, and make sure the Harvey connector is toggled on when chatting. ### Claude Desktop 1. Open Claude Desktop and sign in. 2. Go to **Settings**. 3. Go to **Connectors**, search for **Harvey**. 4. Connect and authenticate with your Harvey account. 5. Once connected, Harvey tools will appear in your conversations. ### Google Gemini 1. As an admin, open the **Gemini Enterprise** page in the Google Cloud console. 2. Go to **Agents** > **Add agents**, then choose **Agents via Marketplace**. 3. Find **Harvey** in the Google Cloud Marketplace and add it to your Gemini Enterprise app. 4. In the Gemini Enterprise web app, open Harvey from the agent gallery and authenticate with your Harvey account via OAuth when prompted. ### Microsoft 365 Copilot 1. As an admin, open the **Microsoft 365 admin center** and goes to **Copilot** > **Connectors**. 2. On the **Your connections** tab, find the **Harvey** partner connector and approve and enable it for your organization. 3. In Microsoft 365 Copilot, the Harvey connector becomes available. On first use, authenticate with your Harvey account via OAuth. 4. Once connected, Harvey tools appear in your Copilot conversations. *** ## Available tools | Tool | Description | Example prompts | | --------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------- | | `ask_harvey` | Ask a general legal question using Harvey's broad legal knowledge | "What are the elements of a breach of contract claim?" | | `ask_with_knowledge_source` | Ask a question using a specific research knowledge source | "What is the HMRC guidance on capital gains for non-residents?" | | `list_knowledge_sources` | List all available research knowledge sources | "What research databases can I search?" | | `list_vault_projects` | List all Vault projects accessible to the authenticated user | "What Vault projects do I have access to?" | | `ask_about_vault` | Ask a question about documents in a specific Vault project | "Summarize the indemnification clauses in this project" | ## Troubleshooting Check with your Harvey admin or representative to ensure you're enrolled in this feature. Your Harvey account lacks the required permission for the specific tool you're trying to use. For example, `ask_about_vault` requires the `VAULT` permission. Contact your Harvey workspace administrator to check your permissions. The `vault_project_id` parameter must be a valid UUID. Use `list_vault_projects` first to get valid project IDs. The `knowledge_source_type` value doesn't match any available knowledge source. Use `list_knowledge_sources` to see valid types for your account. * Verify your Harvey account is active and you have access to the MCP feature. * Try re-authenticating by removing and re-adding the MCP server in your client. * Check that your MCP client supports Streamable HTTP transport (not just SSE or stdio). * Re-authenticate if the connection was previously established. *** ## FAQ Yes. Each user authenticates individually through the browser OAuth flow. The server resolves each request to the authenticated user and enforces their specific permissions and feature gates. The MCP server can only access data that the authenticated user has permission to view in Harvey. Vault project queries are scoped to projects the user can access, and knowledge source queries are limited to sources enabled for the user's account. Each tool call is stateless — the server does not maintain conversation history between requests. To build multi-turn workflows, your MCP client should manage context across tool calls. # Introduction Source: https://developers.harvey.ai/guides/introduction Welcome to the Harvey API Guide. This guide provides everything you need to start integrating with Harvey. It is designed to support secure, scalable automation across your workflows and systems. Harvey APIs enable organizations to integrate proprietary data, streamline workflows, and enhance operational efficiency. Key benefits include: * **Harness Your Organization’s Expertise**: Integrate your proprietary knowledge into Harvey for more precise and tailored AI-driven outputs. * **Boost Lawyer Productivity**: Embed Harvey's AI directly into your internal applications, eliminating the need for manual tasks. * **Effortless API Adoption**: Designed for developers, Harvey's APIs integrate seamlessly into existing platforms, reducing implementation time and engineering overhead. * **Future-Proof Your Tech Stack**: Leverage continuously improving AI models via API, ensuring your firm stays ahead without disruptive platform changes. Please see your Order Form or email [support@harvey.ai](mailto:support@harvey.ai) for details on which feature(s) your organization has permission to use. # Review Tables Source: https://developers.harvey.ai/guides/review_tables Read results from and add rows to Vault review tables Harvey's Review Table APIs let your systems programmatically read a review table's structure and results, and add new documents as rows without rebuilding the table in the UI. Review tables are built on top of Vault, so the documents a table reviews are uploaded and managed through the [Vault APIs](/guides/vault) first. The current API request rate limits for Review Table API endpoints are **10 requests per minute**. ```bash theme={null} GET /api/v1/vault/review_table/{review_table_id} GET /api/v1/vault/get_row/{review_table_id}/{file_id} POST /api/v1/vault/add_row/{review_table_id} ``` ## Overview A review table extracts structured answers from the documents in a Vault project — one row per document (or file group), one column per question. Use these APIs to: * **Export Results**: Read a table's title, file list, and per-row cells, including Harvey's answers, reasoning, citations, and verification status * **Extend a Table**: Add new documents as rows — individually or grouped — and have Harvey review them against the table's existing columns ## Use Cases ### Use Case 1: Fetch Review Table Data **Challenge**: After a review table has been run in Vault, teams need to programmatically access the table's structure and results — for example, to export answers, check verification status, or build downstream workflows. **Solution**: Use `review_table_ids` from Get Project Metadata to discover available review tables, then retrieve each table's metadata (title, file list) and drill into individual row results. **Step 1** — Get the project's review table IDs from the metadata endpoint: ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/vault/get_metadata/{project_id}" \ -H "Authorization: Bearer YOUR_API_KEY" ``` The response includes a `review_table_ids` array (e.g., `[2365724, 2365725]`). An empty array means the project has no review tables. **Step 2** — Fetch a review table's metadata by ID to get its title and file list: ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/vault/review_table/{review_table_id}" \ -H "Authorization: Bearer YOUR_API_KEY" ``` The response contains the table's `title`, `created_at` timestamp, and `file_ids` — one ID per document row in the table. **Step 3** — Retrieve a specific row using the `review_table_id` and a `file_id` from the previous step: ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/vault/get_row/{review_table_id}/{file_id}" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Each row contains an array of `cells` with the column name, Harvey's short answer (`summary`), the full reasoning behind it (`additional_context`), supporting `citations`, and verification/flag status. Files reviewed together as a file group share a single row: requesting any file in the group returns that shared row, with `file_id` echoing the file you asked for. Within each field, a user-edited value takes precedence over the AI-generated value. Inline citation markers in `summary` and `additional_context` use `[N]` bracket notation, where `N` is the 1-based index into the cell's `citations` array. ### Use Case 2: Add New Rows to an Existing Review Table **Challenge**: Review tables are often long-lived — new documents arrive after the table was first run, and teams want them reviewed against the same columns without rebuilding the table in the UI. Sometimes a single row needs to cover several related documents, such as a master agreement and its amendments. **Solution**: Use the add row endpoint to add files from the review table's Vault project as new rows. Harvey schedules a review run that populates each new row's cells for every existing visible column. **Step 1** — Upload the files to the review table's Vault project (or pick existing files) and wait until each `processing_status` reaches `ready_to_query`: ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/vault/get_files?ids={file_id}" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Step 2** — Add the files to the review table. Pass a single ID in `file_ids` to add one file as its own row: ```bash theme={null} curl -X POST "https://api.harvey.ai/api/v1/vault/add_row/{review_table_id}" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"file_ids": ["0199c5c1-50d9-7d60-93aa-cd65c3b7d5a9"]}' ``` The response confirms the run was scheduled. `review_file_group_id` is `null` because a single file becomes its own row: ```json theme={null} { "response": { "event_id": 2365724, "file_ids": ["0199c5c1-50d9-7d60-93aa-cd65c3b7d5a9"], "review_event_run_id": "019f8d8f-fc20-79e0-8b78-980b747c5ef3", "review_file_group_id": null, "status": "scheduled" } } ``` **Step 3** — The run is asynchronous. Poll the row endpoint until its cells are populated: ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/vault/get_row/{review_table_id}/{file_id}" \ -H "Authorization: Bearer YOUR_API_KEY" ``` #### Reviewing several files together as one row Pass two or more IDs in `file_ids` to create a **file group** — the files are reviewed together and occupy a single row in the table, so each cell answers across the whole set of documents. Use the optional `group_name` to label the group: ```bash theme={null} curl -X POST "https://api.harvey.ai/api/v1/vault/add_row/{review_table_id}" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "file_ids": [ "0199c5c1-50d9-7d60-93aa-cd65c3b7d5a9", "019f66b0-5706-7239-b7b8-9c61cbec8b7a" ], "group_name": "Acme MSA and amendments" }' ``` The response returns the ID of the group that was created: ```json theme={null} { "response": { "event_id": 2365724, "file_ids": [ "0199c5c1-50d9-7d60-93aa-cd65c3b7d5a9", "019f66b0-5706-7239-b7b8-9c61cbec8b7a" ], "review_event_run_id": "019f97bd-6d6c-7715-b63e-a0a11437f202", "review_file_group_id": "019f97bd-6d57-7aaf-9559-58812be0e1a7", "status": "scheduled" } } ``` Because the group is a single row, poll it with `get_row` using any member file ID — each member resolves to the same grouped row. A few rules to keep in mind: * Every file must belong to the same Vault project the review table was created from; files from other projects return `404`. * A file that already has a row returns `409`. For a group request, a file that already belongs to a file group in the table also returns `409`. A file that is still processing returns `409` too — retry once it reaches `ready_to_query`. In each case the error message names the offending file ID. * `group_name` defaults to the first file's name, and is ignored when only one file is sent. * A request may carry up to 25 files by default; workspaces with a raised file-group limit may send more. Repeating the same ID in one request returns `400`. * Adding several files at once always creates one grouped row rather than several individual rows. To add multiple independent rows, send one request per file. * File grouping must be enabled for your workspace; multi-file requests return `422` otherwise. Adding an already-grouped file as its own row also returns `422`. * Re-adding a file whose row was previously deleted restores the original row instead of creating a duplicate. ## Error Handling | Status Code | Description | Example Error Message | | ----------- | -------------------------------------------------------- | --------------------------------------------- | | 200 | Success | N/A | | 400 | Bad Request – Missing or invalid input | `{ "error": "Duplicate file id" }` | | 401 | Unauthorized – Invalid API key | `{ "error": "Unauthorized" }` | | 404 | Not Found – Review table or file not found | `{ "error": "File not found" }` | | 409 | Conflict – File already has a row or is still processing | `{ "error": "File already has a row" }` | | 422 | Unprocessable – File grouping not enabled for workspace | `{ "error": "File grouping is not enabled" }` | | 500 | Internal Server Error | `{ "error": "Unexpected server error" }` | *** Need help getting started? Contact your Harvey Customer Success Manager for more information. # History Exports Source: https://developers.harvey.ai/guides/usage_history Export usage and query history across your organization Harvey's History Export APIs let you retrieve detailed logs of how users are interacting with the platform. Use them to power usage reports, perform compliance investigations, or attribute activity to clients and matters. The current API request rate limits for History Export API endpoints are **2 requests per minute**. ```bash theme={null} GET /api/v2/history/usage GET /api/v2/history/query GET /api/v1/history/usage GET /api/v1/history/query ``` ## Overview The History APIs support: * **Usage Tracking**: Understand frequency, volume, and system-wide adoption * **Query Forensics**: Review exact prompts, outputs, and sources for internal audits or client escalations * **Billing & Cost Attribution**: Map usage and queries back to client-matter structures The **v2** endpoints return enriched event data with additional metadata such as `product_surface_area`, `subsurface`, `vault_project_name`, and more. We recommend using v2 for all new integrations. These APIs include sensitive data for resource names across your entire workspace, and are not gated by any form of client-matter or ethical wall boundaries. We recommend caution when pulling this information via API and sharing API tokens carefully and selectively. ### What's new in v2 * Workflow, playbook, and vault names to identify commonly used resources * Unique usage id (uuid) for every single usage log returned by the API * Clear distinction between creation vs. run for playbooks and workflows * Clear distinction between starting new threads vs. asking follow-up queries *** ## Event Types Each v2 history event includes a `product_surface_area` and `subsurface` field that identify where and how the event occurred. Below is a complete list of possible values. ### Product Surface Area | Value | Description | | ----------- | ---------------------- | | `ASSISTANT` | Assistant product area | | `VAULT` | Vault product area | | `PLAYBOOK` | Playbook product area | | `WORKFLOW` | Workflow product area | | `WORD` | Word add-in | | `OUTLOOK` | Outlook add-in | | `DRAFT` | Draft product area | ### Subsurface | Value | Description | | --------------------------- | --------------------------------------------------- | | `ASSISTANT_THREAD` | A new Assistant thread was started | | `ASSISTANT_THREAD_FOLLOWUP` | A follow-up message in an existing Assistant thread | | `REVIEW_TABLE` | A Vault review table query was created/run | | `WORKFLOW_PUBLISHED` | A published workflow was run | | `WORKFLOW_TEST` | A workflow was run in test mode | *** ## Usage History ### v2 ```bash theme={null} GET /api/v2/history/usage ``` Returns usage events wrapped in an `events` array. Each event includes metadata about the product area, action type, and user — without sensitive inputs or outputs. ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v2/history/usage?start_time=1711920000&end_time=1714521600" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Example response:** ```json theme={null} { "events": [ { "access_point": "WEB", "action": "CREATE", "cm_id": "1234.56", "parent_thread_id": 2374992, "playbook_name": "", "product_surface_area": "ASSISTANT", "review_table_name": "", "source": "Files", "space_name": "", "subsurface": "ASSISTANT_THREAD, ASSISTANT_THREAD_FOLLOWUP", "utc_time": "2026-02-22 14:01:23", "unique_usage_id": "019c85a7-a7c9-784f-bc59-0ddd5654274d", "user": "user@example.com", "vault_project_name": "", "workflow_name": "", "metadata": {} } ] } ``` ### v1 ```bash theme={null} GET /api/v1/history/usage ``` Returns a flat array of usage events with basic metadata. ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/history/usage?start_time=1711920000&end_time=1714521600" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Use Cases #### Usage Reporting and Oversight **Challenge**: Firms need reliable, exportable usage metrics to support leadership reporting and billing. **Solution**: Pull usage data weekly or monthly and load it into your reporting environment. Use the `product_surface_area` field (v2) or `Task` field (v1) to break down usage by Harvey product. #### Monitoring Adoption Across Teams **Challenge**: Legal and operational leaders need to understand how teams are engaging with Harvey. **Solution**: Pull usage logs and associate them with user emails or internal department mappings. The v2 endpoint provides additional context through `subsurface` and `access_point` fields. *** ## Query History ### v2 ```bash theme={null} GET /api/v2/history/query ``` Returns query events wrapped in an `events` array. Each event includes the full query and response text alongside all usage metadata. ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v2/history/query?start_time=1711920000&end_time=1714521600" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Example response:** ```json theme={null} { "events": [ { "access_point": "WEB", "action": "CREATE", "cm_id": "1234.56", "feedback_comments": "", "feedback_sentiments": "", "link": "https://app.harvey.ai/assistant/assist/2374992", "parent_thread_id": 2374992, "playbook_name": "", "product_surface_area": "ASSISTANT", "query": "Can you summarize the key indemnity provisions in this contract?", "response": "The contract contains three main indemnity provisions...", "review_table_name": "", "source": "Files", "space_name": "", "subsurface": "ASSISTANT_THREAD, ASSISTANT_THREAD_FOLLOWUP", "utc_time": "2026-02-22 14:01:23", "unique_usage_id": "019c85a7-a7c9-784f-bc59-0ddd5654274d", "user": "user@example.com", "vault_project_name": "", "workflow_name": "", "metadata": {} } ] } ``` ### v1 ```bash theme={null} GET /api/v1/history/query ``` Returns a flat array of query events including prompts, responses, and document references. ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/history/query?start_time=1711920000&end_time=1714521600" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Use Cases #### Deep Dive Analysis of Specific Queries **Challenge**: Admins need to understand exactly what was asked, by whom, and what sources were used. **Solution**: Use query history logs to reconstruct an interaction. The v2 `link` field provides a direct URL to view the event in Harvey. #### Reviewing Draft Quality and Sources **Challenge**: Teams need to verify whether specific outputs were grounded in expected sources. **Solution**: Use the `source` and `response` fields (v2) to trace how the AI formulated its answer. In v1, the `Documents` field lists specific filenames used. *** ## Best Practices * **Limit to 1-day data pulls**: The API supports a maximum range of 30 days, but it's best to retrieve a max of one day at a time on a regular cadence. * **Align client-matter attribution**: Combine query and usage logs with client-matter metadata to analyze usage patterns and client activity. Use `cm_id` (v2) or `Client Matter #` (v1) to match events. * **Analyze product usage**: Use `product_surface_area` and `subsurface` (v2) or `Task` (v1) to understand how different Harvey features are used. * **Trace user activity contextually**: Use email, timestamp, and source fields to piece together how a user interacted with a specific document or feature. ## Error Handling | Status Code | Description | Example Error Message | | ----------- | --------------------------------------- | ---------------------------------------- | | 200, 201 | Success | N/A | | 400 | Bad Request – Missing or invalid input | `{ "error": "Missing start_time" }` | | 401 | Unauthorized – Invalid API key | `{ "error": "Unauthorized" }` | | 429 | Too Many Requests – Rate limit exceeded | `{ "error": "Rate limit exceeded" }` | | 500 | Internal Server Error | `{ "error": "Unexpected server error" }` | *** Need help getting started? Contact your Harvey Customer Success Manager for more information. # Vault Source: https://developers.harvey.ai/guides/vault Automate secure document workflows with Vault Harvey's Vault APIs enable your systems to programmatically upload, manage, and delete documents within secure Vault projects. These endpoints support integration with DMS systems, document pipelines, and client workflows requiring consistent structure, metadata, and compliance. The current API request rate limits for Vault API endpoints are **10 requests per minute**. ```bash theme={null} GET /api/v1/vault/workspace/projects GET /api/v1/vault/workspace/recycle_bin POST /api/v1/vault/upload_files/{project_id} GET /api/v1/vault/get_metadata/{project_id} GET /api/v1/vault/projects/{project_id}/files GET /api/v1/vault/get_files DELETE /api/v1/vault/delete_file/{file_id} DELETE /api/v1/vault/delete_project/{project_id} ``` ## Overview The Vault APIs are designed to streamline how legal teams ingest and manage large volumes of files (and other supported data formats), making them searchable and reviewable by Harvey. Use it to: * **Automate Document Ingestion**: Upload documents in real-time from your data source of choice (e.g., Document Management System, Contract Lifecycle Management tool, File Storage platform, etc.) * **Preserve Folder Structure**: Create a custom file library system with clear organization using nested directories * **Track and Manage Files**: Retrieve metadata or delete obsolete files as needed automatically Looking to read results from or add rows to a Vault review table? Those endpoints are documented in the [Review Tables guide](/guides/review_tables). ### Supported File Types Vault supports the following formats: * PDF * Word (.doc, .docx) * Excel (.xls, .xlsx) * PowerPoint (.ppt, .pptx) * Text (.txt) * Markdown (.md) * HTML (.html) * CSV * RTF * XML * Email (.eml, .msg) * Images (.jpeg, .png, .tiff) * Common code file types (.c, .cpp, .java, .js, .json, .php, .py, .tex, .ts, .xml, .rb, .css) ## Use Cases ### Use Case 1: List All Workspace Projects **Challenge**: Organizations need visibility into all Vault projects within their workspace to manage content effectively. **Solution**: Use the workspace projects endpoint to retrieve a paginated list of all projects accessible to your API token. ```bash theme={null} curl -X GET https://api.harvey.ai/api/v1/vault/workspace/projects?page=1&per_page=20 \ -H "Authorization: Bearer YOUR_API_KEY" ``` This returns project details including IDs, names, file counts, and whether they're designated as knowledge bases. ### Use Case 2: Secure Document Storage in Vault **Challenge**: Managing legal documents across multiple systems can lead to inefficiencies and security risks. **Solution**: Upload files directly into Vault to ensure secure, up-to-date storage with consistent project-level organization. ```bash theme={null} curl -X POST https://api.harvey.ai/vault/upload_files/{project_id} \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "files=@/path/to/contract.pdf" \ -F "files=@/path/to/terms.docx" \ -F "file_paths=contract.pdf" \ -F "file_paths=terms.docx" ``` ### Use Case 3: Retrieve Project Storage Details **Challenge**: Without visibility into stored files, users risk losing track of critical documents. **Solution**: Use the metadata endpoint to retrieve file IDs, names, sizes, and other details from a Vault project. ```bash theme={null} curl -X GET https://api.harvey.ai/vault/get_metadata/{project_id} \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Use Case 4: Check File Processing Status **Challenge**: After uploading files, organizations need to know when those files have finished processing and are ready to query. **Solution**: Use the get files endpoint to poll the processing status of one or more files by their IDs. This is useful as a heartbeat check in upload pipelines to confirm files are ready before issuing queries against them. ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/vault/get_files?file_ids=01936a5f-8289-703a-9962-42bf196ae611&file_ids=01936a5f-82a2-708a-9df6-91d72c1cd26d" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Each file in the response includes its `processing_status` (e.g., `uploaded`, `processing`, `ready_to_query`), `content_type`, and `deleted_at` timestamp. Files that are not found return an `error` field instead. ### Use Case 5: Remove Outdated or Erroneous Files **Challenge**: Projects evolve and occasionally contain outdated or incorrectly uploaded files that must be removed. **Solution**: Use the file deletion endpoint to remove files by ID. This is especially useful in automated pipelines or when enforcing compliance. ```bash theme={null} curl -X DELETE https://api.harvey.ai/vault/delete_file/{file_id} \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json" ``` ### Use Case 6: Delete Entire Vault Projects **Challenge**: Organizations need to completely remove Vault projects that are no longer needed, ensuring complete cleanup of all associated documents and metadata. **Solution**: Use the project deletion endpoint to remove an entire Vault project by project ID. This action cannot be undone. Deletion continues asynchronously after the API request returns. ```bash theme={null} curl -X DELETE https://api.harvey.ai/api/v1/vault/delete_project/{project_id} \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json" ``` The success response confirms that deletion is in progress: ```json theme={null} { "message": "Project deletion is in progress" } ``` ### Use Case 7: List and Filter Files Within a Project **Challenge**: For large Vault projects, `get_metadata` returns flat parallel ID/name arrays that don't allow filtering. Users have use cases to search and filter for specific files within their vault projects, without enumerating everything. **Solution**: Use the list project files endpoint to retrieve files with cursor pagination, server-side filtering, and sorting. Filter by `name` (case-insensitive substring), `content_type`, `processing_status`, or `uploaded_after` / `uploaded_before`. Sort by `name`, `uploaded_at`, or `size` in either direction. ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/vault/projects/{project_id}/files?name=contract&content_type=application/pdf&processing_status=READY_TO_QUERY&sort_by=uploaded_at&sort_order=desc&limit=50" \ -H "Authorization: Bearer YOUR_API_KEY" ``` The response includes a `pagination` block with `next_cursor` — pass it back as the `cursor` query parameter to fetch the next page. Continue until `has_more` is `false`. ### Use Case 8: Review Vaults in the Recycle Bin **Challenge**: When a Vault project is deleted it is not purged immediately — it first moves to a workspace recycle bin, where it can be reviewed (and, if needed, restored) before being permanently deleted. Administrators need visibility into which vaults are pending permanent deletion, who deleted them, and when that deletion is scheduled. **Solution**: Use the workspace recycle-bin endpoint to list every vault currently in the recycle bin for your workspace. This endpoint is restricted to workspace vault admins (the same permission as `GET /api/v1/vault/workspace/projects`). ```bash theme={null} curl -X GET "https://api.harvey.ai/api/v1/vault/workspace/recycle_bin?search_text=acme&client_matter_id=11111111-2222-3333-4444-555555555555" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Both query parameters are optional: * `search_text` — case-insensitive substring filter on the vault name. * `client_matter_id` — restrict results to vaults associated with this client matter (the client matter UUID, not the human-readable matter number). The response returns an `items` array ordered by `deleted_at` descending, plus a `total` count. Each entry describes the recycle-bin row and embeds the deleted vault under `vault_project` (the same project shape returned by `GET /api/v1/vault/workspace/projects`): ```json theme={null} { "items": [ { "id": "0197a1b2-3c4d-5e6f-7a8b-9c0d1e2f3a4b", "resource_id": "abcdef12-3456-7890-abcd-ef1234567890", "resource_type": "vault_project", "recycle_bin_status": "deleted", "deleted_at": "2026-07-15T18:42:10.512000Z", "recycle_bin_purged_scheduled_at": "2026-08-14T18:42:10.512000Z", "delete_source": "customer_delete", "deleted_source_id": "12345678-1234-5678-1234-567812345678", "deleted_by_user_email": "user@example.com", "vault_project": { "id": "abcdef12-3456-7890-abcd-ef1234567890", "name": "Acme Contract Repository", "created_at": "2026-01-15T10:30:00.000000", "creator_email": "user@example.com", "files_count": 42, "is_knowledge_base_project": false } } ], "total": 1 } ``` Key fields on each entry: * `recycle_bin_status` — always `deleted` for entries returned by this endpoint. * `deleted_at` — when the vault was moved into the recycle bin. * `delete_source` — how the delete was initiated: `customer_delete`, `admin_delete`, `retention_delete`, or `system_delete`. * `deleted_by_user_email` — the user who deleted the vault, populated for `customer_delete` and `admin_delete`; `null` for retention/system deletes or when the actor is unknown. * `recycle_bin_purged_scheduled_at` — when the vault is scheduled to be permanently purged from the recycle bin. `null` when no purge is scheduled. Permanent deletion is not instantaneous at `recycle_bin_purged_scheduled_at`. The purge is carried out by a periodic background sweep, so a vault can take up to 30 minutes after `recycle_bin_purged_scheduled_at` passes to be fully purged. ## Best Practices ### Organize by Project Use distinct `project_id` values to group documents by matter, client, or internal team structure. ### Maintain File Path Consistency Use the `file_paths` field to define relative folder structures so that uploads reflect your organization’s hierarchy. ### Confirm Uploads and Deletions After uploading, call `GET /vault/get_metadata/{project_id}` to confirm files are present, and use `GET /vault/get_files` to poll processing status until files reach `ready_to_query`. After deletions, check for a 200 confirmation response. When deleting entire projects, the project should no longer appear in the workspace projects list once deletion has completed. ## Error Handling | Status Code | Description | Example Error Message | | ----------- | -------------------------------------- | ---------------------------------------- | | 201 | Success | N/A | | 400 | Bad Request – Missing or invalid input | `{ "error": "Missing file" }` | | 401 | Unauthorized – Invalid API key | `{ "error": "Unauthorized" }` | | 404 | Not Found – Project or File not found | `{ "error": "File not found" }` | | 500 | Internal Server Error | `{ "error": "Unexpected server error" }` | *** Need help getting started? Contact your Harvey Customer Success Manager for more information. # Get Query History Source: https://developers.harvey.ai/history-export/queries/get-query-history /history_export_api.json get /api/v1/history/query Fetches the query history and metadata for a specified time range, including sensitive information such as inputs to and outputs from the AI system. > **Warning:** These APIs include sensitive data for resource names across your entire workspace, and are not gated by any form of client-matter or ethical wall boundaries. We recommend caution when pulling this information via API and sharing API tokens carefully and selectively. ### Permissions Requires `Territory admin` or `Organization admin`, and `View history` permissions. # Get Query History (v2) Source: https://developers.harvey.ai/history-export/queries/get-query-history-v2 /history_export_api.json get /api/v2/history/query Fetches the query history and metadata for a specified time range, including sensitive information such as inputs to and outputs from the AI system. Returns enriched event data with product surface area, subsurface details, and additional metadata. > **Warning:** These APIs include sensitive data for resource names across your entire workspace, and are not gated by any form of client-matter or ethical wall boundaries. We recommend caution when pulling this information via API and sharing API tokens carefully and selectively. ### Permissions Requires `Territory admin` or `Organization admin`, and `View history` permissions. # Get Usage History Source: https://developers.harvey.ai/history-export/usage/get-usage-history /history_export_api.json get /api/v1/history/usage Fetches the usage history and metadata for a specified time range. Includes query events from your workspace users across Harvey product areas. The data includes basic metadata like user, timestamp and event kind. It does **not** include sensitive information such as inputs to or outputs from the AI system. ### Permissions Requires `Territory admin` or `Organization admin` permission. # Get Usage History (v2) Source: https://developers.harvey.ai/history-export/usage/get-usage-history-v2 /history_export_api.json get /api/v2/history/usage Fetches the usage history and metadata for a specified time range. Returns enriched event data with product surface area, subsurface details, and additional metadata across Harvey product areas. > **Warning:** These APIs include sensitive data for resource names across your entire workspace, and are not gated by any form of client-matter or ethical wall boundaries. We recommend caution when pulling this information via API and sharing API tokens carefully and selectively. ### Permissions Requires `Territory admin` or `Organization admin`, and `View history` permissions.