---
title: "query"
description: "Read CRM data through OQL — filter, sort, select fields, and aggregate across contacts, deals, actions, notes, calls, and meetings."
canonical_url: https://developer.onepagecrm.com/mcp/tools/query/
source: Markdown mirror of https://developer.onepagecrm.com/mcp/tools/query/
---

`query` is the primary **read** tool. It accepts a JSON query object
that the OnePageCRM Query Language ([OQL](/oql/overview/)) understands
and runs it. Everything OQL can
express — filters, ordering, field projection, aggregates, date
helpers — is available here.

## Signature

```json
{
  "type": "object",
  "properties": {
    "query": {
      "type": "object",
      "properties": {
        "select":    { "description": "Field array, [\"*\"], or aggregates." },
        "from":      { "type": "string", "description": "Entity name." },
        "where":     { "type": "object", "description": "Filter conditions (AND'd)." },
        "order_by":  { "type": "array",  "description": "Sort order." },
        "group_by":  { "type": "array",  "description": "Group fields (max 3)." },
        "having":    { "type": "object", "description": "Post-aggregation filter (requires group_by)." },
        "distinct":  { "type": "boolean", "description": "Unique combinations of the selected fields." },
        "limit":     { "type": "integer" }
      }
    }
  },
  "required": ["query"]
}
```

The `query` argument is a [JSON OQL query](/oql/concepts/) — the same
shape shown throughout the [OQL docs](/oql/overview/).

## Entities you can query

`contacts`, `companies`, `deals`, `actions`, `notes`, `calls`,
`meetings`. See [OQL Entities](/oql/entities/contacts/) for the fields
each one exposes.

## Examples

**Today's open actions:**

```json
{
  "query": {
    "from": "actions",
    "select": ["*"],
    "where": { "date": "TODAY()", "completed": false },
    "limit": 50
  }
}
```

**Won deals this quarter, by owner:**

```json
{
  "query": {
    "from": "deals",
    "select": ["count()", { "sum": ["amount"] }],
    "where": { "status": "won", "close_date": "THIS_QUARTER()" },
    "group_by": ["owner_id"],
    "order_by": [{ "sum_amount": "desc" }]
  }
}
```

**A specific contact by email:**

```json
{
  "query": {
    "from": "contacts",
    "select": ["id", "first_name", "last_name", "emails"],
    "where": { "emails.address": "jane.doe@acmesolar.example" }
  }
}
```

For more patterns, see [OQL Recipes](/oql/recipes/).

## Response shape

```jsonc
{
  "rows": [ /* one object per result row */ ],
  "row_count": 17
}
```

When a result set is clipped to the response cap, a `"truncated": true`
flag is added — it is omitted otherwise. If you see it, ask for a
tighter filter or a smaller `select`.

## Operators and functions

OQL supports `=`, `!=`, `<`, `>`, `<=`, `>=`, `in`, `between`, `like`,
`{"is": null}`, and `{"is not": null}`. Date helpers (`TODAY()`,
`THIS_QUARTER()`, `LAST_QUARTER()`, `DAYS_AGO(n)`, …) and the aggregate
functions `count()`, `sum`, `avg`, `min`, `max`, `median`, and
`percentile` are available, each with an optional `distinct` modifier.
Grouped results can be filtered after aggregation with `having`, and
`distinct: true` returns unique combinations of the selected fields.
The authoritative references are:

- [OQL Operators](/oql/operators/)
- [OQL Functions](/oql/functions/)
- [OQL Limits & errors](/oql/limits-and-errors/)

## Errors

- **Schema errors** — unknown entity or unknown field on the entity.
- **Syntax errors** — malformed `where` clauses, unsupported operators.
- **Execution errors** — limit exceeded, type mismatch, etc.

Each error comes back as a structured response (not an exception) so
the agent can correct itself and retry on the next turn.

## Scope

`crm.readonly` is sufficient. `crm` also works (write scope includes
read).

Results are always filtered to records the **authenticated user** can
see — `query` doesn't bypass per-user permissions, even when the
account has multiple users.
