> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.termina.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.termina.ai/_mcp/server.

# Advanced Search

POST https://app.termina.ai/api/v1/deal/advanced-search
Content-Type: application/json

Reference: https://docs.termina.ai/api-reference/deal-management/deal/advanced-search

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Servers

- `https://app.termina.ai` (Production server, default)
- `https://app.termina.dev` (Development server)
- `http://localhost:8000` (Local development server)

## Request

### Body (application/json)

This endpoint expects a SearchDealsAdvancedRequest.

- `filters` (DealSearchFilter, optional, nullable) — Base filter model for deal search. Supports individual field filters or logical operators (`$and`, `$or`). Example with benchmark metrics: ```json { "filters": { "$and": [ {"company_name": "Acme"}, { "benchmark_metrics": { "field_name": "revenue", "conditions": [ {"operator": "$gte", "value": 1000000}, {"operator": "$lte", "value": 5000000} ] } } ] } } ```
- `sort` (list of SortCriterion, optional, nullable) — Optional list of sort criteria. Earlier items take precedence. Each item must specify 'sort_by' (SortField, BenchmarkMetricField, or DateField enum) and 'sort_order'. 'sort_by' values must be unique.
- `page` (integer, optional, default: 1) — Page number
- `page_size` (integer, optional, default: 100) — Number of items per page

## Response

### 200

Successful Response

- `total_count` (integer, required)
- `page` (integer, required)
- `page_size` (integer, required)
- `data` (list of DealWithFilesResponse, required)

## Errors

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

## Types

### DealSearchFilter

Base filter model for deal search. Supports individual field filters or logical operators (`$and`, `$or`). Example with benchmark metrics: ```json { "filters": { "$and": [ {"company_name": "Acme"}, { "benchmark_metrics": { "field_name": "revenue", "conditions": [ {"operator": "$gte", "value": 1000000}, {"operator": "$lte", "value": 5000000} ] } } ] } } ```

- `$and` (list of DealSearchFilter, optional, nullable)
- `$or` (list of DealSearchFilter, optional, nullable)
- `group_id` (integer, optional, nullable) — Exact match on group ID
- `company_id` (integer, optional, nullable) — Exact match on company ID
- `deal_id` (integer, optional, nullable) — Exact match on deal ID
- `company_name` (string, optional, nullable) — Case-insensitive partial match (no fuzzy). Matches must be consecutive tokens in order. E.g., 'acme' matches 'Acme Corp', 'acme c' matches 'Acme Corp', but 'corp acme' does NOT match 'Acme Corp'.
- `company_domain` (string, optional, nullable) — Case-insensitive partial match (no fuzzy). Matches must be consecutive tokens in order. E.g., 'acme' matches 'acme.com', but does not allow typos or fuzzy matching.
- `categories` (list of string, optional, nullable) — Case-insensitive exact match. If multiple values are provided, matches deals that contain ANY of them.
- `round_name` (string, optional, nullable) — Case-insensitive partial match (no fuzzy). Matches must be consecutive tokens in order. E.g., 'series' matches 'Series A', 'series a' matches 'Series A', but 'series b' does NOT match 'Series A'.
- `deal_lead_name` (string, optional, nullable) — Case-insensitive partial match (no fuzzy). Matches must be consecutive tokens in order. E.g., 'jane' matches 'Jane Doe', 'jane d' matches 'Jane Doe', but 'doe jane' does NOT match 'Jane Doe'.
- `deal_lead_email` (string, optional, nullable) — Case-insensitive partial match (no fuzzy). Matches must be consecutive tokens in order. E.g., 'jane' matches 'jane@example.com', but does not allow typos or fuzzy matching.
- `group_account` (string, optional, nullable) — Case-insensitive partial match on group account/domain. Combine with $or for multiple accounts.
- `group_name` (string, optional, nullable) — Case-insensitive partial match on group name (no fuzzy). Combine with $or for multiple names.
- `notes` (string, optional, nullable) — Case-insensitive fuzzy match. Allows approximate matching with typos and misspellings.
- `tags` (list of string, optional, nullable) — Case-insensitive exact match. If multiple values are provided, matches deals that contain ANY of them.
- `priority` (string, optional, nullable) — Case-insensitive exact match (no partials, no fuzzy).
- `status` (DealSearchFilterStatus, optional, nullable) — Exact match on deal status. Accepts single status or list. If multiple values are provided, matches deals that have ANY of them.
- `general_text` (string, optional, nullable) — Case-insensitive search across all searchable fields. Performs partial/fuzzy matching on text fields (company name, domain, round name, deal lead, notes, etc.) AND exact matching on keyword fields (priority, tags, categories). Returns deals matching either type.
- `dates` (DateCriterion, optional, nullable) — Filter for date fields. Example: ```json { "field_name": "created_at", "conditions": [ {"operator": "$gte", "value": "2024-01-01T00:00:00Z"}, {"operator": "$lte", "value": "2024-12-31T23:59:59Z"} ] } ```
- `benchmark_metrics` (BenchmarkMetricFilter, optional, nullable) — Filter for nested benchmark\_metrics field. Example: ```json { "field_name": "revenue", "conditions": [ {"operator": "$gte", "value": 1000000}, {"operator": "$lte", "value": 5000000} ] } ``` NOTE: field\_name must be a valid BenchmarkMetricField enum value. This is kept in sync with numeric fields in BenchmarkMetrics response model.

### SortCriterion

Single sort criterion for advanced search. Accepts any of: SortField, BenchmarkMetricField, or DateField enum values. Benchmark metrics are automatically prefixed with 'benchmark_metrics.' in the backend.

- `sort_by` (SortCriterionSortBy, required) — Field to sort by. Can be a regular field, benchmark metric, or date field.
- `sort_order` (string, optional, default: asc) — Sort order: 'asc' or 'desc'

### DealWithFilesResponse

- `round_name` (string, required) — The name of the round
- `id` (integer, required)
- `group_id` (integer, required)
- `company` (CompanyResponse, required)
- `files` (list of FileResponse, required, nullable)
- `notes` (string, optional, nullable) — Notes about the deal
- `priority` (enum, optional, nullable) — The priority of the deal
  - Allowed values: `low`, `normal`, `high`, `urgent`
- `status` (enum, optional, nullable) — Deal status tracking where a deal is in the diligence workflow. NOTE: We use lowercase values everywhere (DB and API) to keep things simple. No case conversion needed - what the user sends is what we store. The members are lower case because sqlalchemy uses the member names, not the values. In the future, we're going to want to make all enums in the database consistent. In this case since it's also used in search and filtering, it's important to get it right *now*.
  - Allowed values: `intake`, `exploring`, `meet`, `get_data`, `queued`, `run_analysis`, `finalize`, `done`, `closed`
- `round_amount` (integer, optional, nullable) — The dollar amount to be raised of the round
- `round_target` (integer, optional, nullable) — The target post-money dollar amount of the round
- `tags` (list of string, optional, nullable) — The tags associated with the deal
- `company_summary` (string, optional, nullable) — The summary of the company
- `deal_lead_id` (integer, optional, nullable) — The id of the user who is the deal lead
- `created_at` (string, optional)
- `updated_at` (string, optional, nullable)
- `is_archived` (boolean, optional, nullable)
- `group` (BasicGroupResponse, optional, nullable) — Minimal group response - excludes computed fields requiring relationships
- `data` (DealDataAvailabilityResponse, optional, nullable)
- `categories` (list of string, optional, nullable)
- `deal_lead` (DealLeadUserResponse, optional, nullable)

### ValidationError

- `loc` (list of ValidationErrorLocItems, required)
- `msg` (string, required)
- `type` (string, required)
- `input` (any, optional)
- `ctx` (ValidationErrorCtx, optional)

### DealSearchFilterStatus

Exact match on deal status. Accepts single status or list. If multiple values are provided, matches deals that have ANY of them.

- DealStatus: enum
  - Allowed values: `intake`, `exploring`, `meet`, `get_data`, `queued`, `run_analysis`, `finalize`, `done`, `closed`
- list of enum
  - Allowed values: `intake`, `exploring`, `meet`, `get_data`, `queued`, `run_analysis`, `finalize`, `done`, `closed`

### DateCriterion

Filter for date fields. Example: ```json { "field_name": "created_at", "conditions": [ {"operator": "$gte", "value": "2024-01-01T00:00:00Z"}, {"operator": "$lte", "value": "2024-12-31T23:59:59Z"} ] } ```

- `field_name` (enum, required) — Enum of available date fields for filtering.
  - Allowed values: `created_at`, `updated_at`, `benchmark_metrics_date`
- `conditions` (list of DateCondition, optional)

### BenchmarkMetricFilter

Filter for nested benchmark\_metrics field. Example: ```json { "field_name": "revenue", "conditions": [ {"operator": "$gte", "value": 1000000}, {"operator": "$lte", "value": 5000000} ] } ``` NOTE: field\_name must be a valid BenchmarkMetricField enum value. This is kept in sync with numeric fields in BenchmarkMetrics response model.

- `field_name` (enum, required) — Enum of available benchmark metric fields for filtering. These correspond to numeric fields in the BenchmarkMetrics response model.
  - Allowed values: `revenue`, `rolling_3m_average_revenue`, `annualized_revenue`, `rolling_3m_annualized_revenue`, `revenue_share_of_top_20_percent`, `revenue_share_of_top_10_count`, `average_to_median`, `gini_coefficient`, `lifetime_quick_ratio`, `lifetime_gross_retention`, `lifetime_net_churn`, `cmgr3`, `cmgr6`, `cmgr12`, `yoy`, `operating_margin`, `quarterly_operating_margin`, `ebitcac`, `quarterly_ebitcac`, `ebitcac_margin`, `quarterly_ebitcac_margin`, `gross_margin`, `quarterly_gross_margin`, `magic_number`, `margin_magic_number`, `rule_of_40`, `cac_of_40`, `burn_multiple`, `margin_burn_multiple`, `roas`, `margin_roas`, `acquisition_spend`, `total_opex`, `logo_retention_6m`, `logo_retention_12m`, `revenue_retention_6m`, `revenue_retention_12m`, `ltv_6m`, `ltv_12m`, `ltv6_cac`, `ltv12_cac`, `gmltv6_cac`, `gmltv12_cac`, `lifetime_ltv6_cac`, `lifetime_ltv12_cac`, `lifetime_gmltv6_cac`, `lifetime_gmltv12_cac`, `cac`, `employee_count`, `cumulative_person_years`, `employee_retention_1yr`, `employee_retention_2yr`, `average_years_of_experience`, `lifetime_employee_retention`, `percent_employees_sales_and_marketing`, `fully_loaded_employee_cost`, `annualized_revenue_per_employee`
- `conditions` (list of BenchmarkMetricCondition, optional)

### SortCriterionSortBy

Field to sort by. Can be a regular field, benchmark metric, or date field.

- SortField: enum
  - Allowed values: `company_name`, `company_domain`, `round_name`, `deal_lead_name`, `deal_lead_email`, `priority`, `status`, `created_at`, `updated_at`, `benchmark_metrics_date`
- BenchmarkMetricField: enum
  - Allowed values: `revenue`, `rolling_3m_average_revenue`, `annualized_revenue`, `rolling_3m_annualized_revenue`, `revenue_share_of_top_20_percent`, `revenue_share_of_top_10_count`, `average_to_median`, `gini_coefficient`, `lifetime_quick_ratio`, `lifetime_gross_retention`, `lifetime_net_churn`, `cmgr3`, `cmgr6`, `cmgr12`, `yoy`, `operating_margin`, `quarterly_operating_margin`, `ebitcac`, `quarterly_ebitcac`, `ebitcac_margin`, `quarterly_ebitcac_margin`, `gross_margin`, `quarterly_gross_margin`, `magic_number`, `margin_magic_number`, `rule_of_40`, `cac_of_40`, `burn_multiple`, `margin_burn_multiple`, `roas`, `margin_roas`, `acquisition_spend`, `total_opex`, `logo_retention_6m`, `logo_retention_12m`, `revenue_retention_6m`, `revenue_retention_12m`, `ltv_6m`, `ltv_12m`, `ltv6_cac`, `ltv12_cac`, `gmltv6_cac`, `gmltv12_cac`, `lifetime_ltv6_cac`, `lifetime_ltv12_cac`, `lifetime_gmltv6_cac`, `lifetime_gmltv12_cac`, `cac`, `employee_count`, `cumulative_person_years`, `employee_retention_1yr`, `employee_retention_2yr`, `average_years_of_experience`, `lifetime_employee_retention`, `percent_employees_sales_and_marketing`, `fully_loaded_employee_cost`, `annualized_revenue_per_employee`
- DateField: enum
  - Allowed values: `created_at`, `updated_at`, `benchmark_metrics_date`

### CompanyResponse

- `name` (string, required) — The name of the company
- `domain` (string, required) — The domain of the company
- `id` (integer, required)
- `group_id` (integer, required)
- `thumbnail_url` (string, optional, nullable) — The thumbnail URL of the company
- `created_at` (string, optional)
- `updated_at` (string, optional, nullable)
- `is_archived` (boolean, optional, nullable)

### FileResponse

- `name` (string, required) — The human-readable name of the file
- `id` (integer, required)
- `deal_id` (integer, required, nullable)
- `type` (enum, optional, nullable) — The type of the file
  - Allowed values: `deck`, `financials`, `raw_data`, `snapshot`, `full`, `mini`, `nano`, `other`
- `created_at` (string, optional)
- `updated_at` (string, optional, nullable)
- `is_archived` (boolean, optional, nullable)
- `filesize` (integer, optional, default: 0) — The size of the file in bytes

### BasicGroupResponse

Minimal group response - excludes computed fields requiring relationships

- `id` (integer, required)
- `name` (string, required)
- `account` (string, required)
- `thumbnail_url` (string, optional, nullable)
- `chatbot_enabled` (boolean, optional, default: false)

### DealDataAvailabilityResponse

- `financials_exist` (boolean, required) — Financials data has been processed for this deal
- `talent_exists` (boolean, required) — Talent data has been processed for this deal
- `product_metrics` (list of ProductInfoResponse, required) — List of which product metrics are available for this deal
- `unit_economics_metrics` (list of UnitEconomicsInfoResponse, required) — List of which user types with unit economics metrics are available for this deal
- `benchmark_user_types` (list of string, required) — List of user types with benchmarks available for this deal
- `excel_export_exists` (boolean, required) — Whether the data export is available for this deal
- `benchmark_categories` (list of string, required, deprecated) — List of categories applied to the company associated with this deal
- `balance_sheet_exists` (boolean, optional, default: false) — Balance sheet data has been processed for this deal

### DealLeadUserResponse

- `name` (string, required) — The name of the user
- `email` (string, required) — The email address of the user
- `thumbnail_url` (string, optional, nullable) — The thumbnail URL of the user

### ValidationErrorLocItems

- string
- integer

### ValidationErrorCtx

### DateCondition

Single date comparison condition.

- `operator` (enum, required) — Comparison operator: `$eq`, `$ne`, `$gte`, `$lte`, `$gt`, `$lt`
  - Allowed values: `$eq`, `$ne`, `$gte`, `$lte`, `$gt`, `$lt`
- `value` (string, required)

### BenchmarkMetricCondition

- `operator` (enum, required) — Comparison operator: `$eq`, `$ne`, `$gte`, `$lte`, `$gt`, `$lt`
  - Allowed values: `$eq`, `$ne`, `$gte`, `$lte`, `$gt`, `$lt`
- `value` (double, required)

### ProductInfoResponse

- `user_type` (string, required)
- `metric` (string, required)

### UnitEconomicsInfoResponse

- `user_type` (string, required)

## Examples

**Request**

```json
{}
```

**Response**

```json
{
  "total_count": 1,
  "page": 1,
  "page_size": 1,
  "data": [
    {
      "round_name": "string",
      "id": 1,
      "group_id": 1,
      "company": {
        "name": "string",
        "domain": "example.com",
        "id": 1,
        "group_id": 1,
        "thumbnail_url": "string",
        "created_at": "2024-01-15T09:30:00Z",
        "updated_at": "2024-01-15T09:30:00Z",
        "is_archived": true
      },
      "files": [
        {
          "name": "string",
          "id": 1,
          "deal_id": 1,
          "type": "deck",
          "created_at": "2024-01-15T09:30:00Z",
          "updated_at": "2024-01-15T09:30:00Z",
          "is_archived": true,
          "filesize": 0
        }
      ],
      "notes": "string",
      "priority": "low",
      "status": "intake",
      "round_amount": 1,
      "round_target": 1,
      "tags": [
        "string"
      ],
      "company_summary": "string",
      "deal_lead_id": 1,
      "created_at": "2024-01-15T09:30:00Z",
      "updated_at": "2024-01-15T09:30:00Z",
      "is_archived": true,
      "group": {
        "id": 1,
        "name": "string",
        "account": "string",
        "thumbnail_url": "string",
        "chatbot_enabled": false
      },
      "data": {
        "financials_exist": true,
        "talent_exists": true,
        "product_metrics": [
          {
            "user_type": "consumer",
            "metric": "revenue"
          }
        ],
        "unit_economics_metrics": [
          {
            "user_type": "consumer"
          }
        ],
        "benchmark_user_types": [
          "consumer"
        ],
        "excel_export_exists": true,
        "benchmark_categories": [
          "saas",
          "fintech"
        ],
        "balance_sheet_exists": false
      },
      "categories": [
        "string"
      ],
      "deal_lead": {
        "name": "string",
        "email": "string",
        "thumbnail_url": "string"
      }
    }
  ]
}
```

**SDK Code**

```python
import requests

url = "https://app.termina.ai/api/v1/deal/advanced-search"

payload = {}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://app.termina.ai/api/v1/deal/advanced-search';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://app.termina.ai/api/v1/deal/advanced-search"

	payload := strings.NewReader("{}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://app.termina.ai/api/v1/deal/advanced-search")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://app.termina.ai/api/v1/deal/advanced-search")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://app.termina.ai/api/v1/deal/advanced-search', [
  'body' => '{}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://app.termina.ai/api/v1/deal/advanced-search");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://app.termina.ai/api/v1/deal/advanced-search")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```