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

# Search and reports over the API

> Two reads that cut across objects: find a record by a word, and count or sum records the way the report builder does.

Two reads that cut across objects: find a record by a word, and count or sum
records the way the report builder does.

## Cross-object search — `GET /v1/search`

```
GET /v1/search?q=ada&objects=leads,customers&limit=5
```

| Parameter | Meaning                                                                                                                |
| --------- | ---------------------------------------------------------------------------------------------------------------------- |
| `q`       | 2–100 characters. Matched case-insensitively as a substring.                                                           |
| `objects` | Comma-separated object names (from `GET /v1/objects`). Omit for every object you may view. An unknown name is a `404`. |
| `limit`   | Hits per object, 1–25, default 5.                                                                                      |

For each object the search looks at its textual fields — name-like fields first
(`name`, `first_name`, `last_name`, `title`, `email`, `phone`, …), at most six —
and runs the same `contains` filter `GET /v1/objects/{object}/records` accepts, OR-ed
across those fields. That means everything the records read already enforces
applies unchanged: your workspace only, your record-level reach, no deleted
records, live or test dataset by credential, and the object's own `<module>:view`
scope. **An object your credential cannot view is simply absent from the
answer**, not an error. Objects with no textual field (pure numbers/dates) are
skipped.

Response: `groups[]` per object with `hits[]` (`id`, a human `label`, the
`matched_field`, and the `record` as the records read returns it), plus
`objects` (what was searched) and `total_hits`. No scope of its own: every
authenticated credential may call it and sees what its scopes allow.

Not offered: id-fragment search (the GUI's search bar matches short id
suffixes); use `GET /v1/objects/{object}/records/{id}` when you hold an id.

## Reports — `/v1/reports`

All three take `reports:view`.

### `POST /v1/reports/query`

```json theme={null}
{ "object": "deals", "metric": "sum", "field": "amount",
  "group_by": "stage", "from": "2026-09-01T00:00:00Z", "to": "2026-10-01T00:00:00Z",
  "filter": { "field": "owner", "op": "eq", "value": "…" } }
```

| Field         | Meaning                                                                                                                             |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `metric`      | `count` (default), `sum`, `avg`, `min`, `max`. All but `count` need `field`, a number field (`min`/`max` also accept a date field). |
| `group_by`    | A published field, or `created_at`. With `bucket: day \| week \| month` a date field is bucketed (UTC; weeks start Monday).         |
| `from` / `to` | A window on `created_at`.                                                                                                           |
| `filter`      | The records filter grammar, passed through as is.                                                                                   |

The report runs over the rows the records read would return to you (same
scopes, reach, soft-delete and test-mode rules), **up to 5,000 rows**. When the
window holds more, `truncated: true` says so and the figures cover the first
5,000 by the records read's order — narrow the window or the filter. Groups
come sorted by key; rows with an empty group key are reported under `key: null`,
last.

This is the same arithmetic the GUI's report builder does client-side, so a
saved report's `config` (`object`, `groupBy`, `aggregation`, `aggregationField`,
`filters`) maps onto one `aggregate` call.

### `GET /v1/reports/pipeline?object=leads|deals`

The status breakdown (`total`, `by_status`, and for leads `converted`) — the
same numbers the AI assistant's `pipeline_summary` tool reports.

### `GET /v1/reports/saved`

The workspace's saved report definitions from the report builder (`name`,
`object_id`, `config`, `is_shared`). Read-only here; run one through
`aggregate`.
