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

# Query

> Retrieve + summarise observations across many entities. Three powers — group by entity, subtract a set, roll up by value — answer 'hottest leads', 'no reply in 5d', 'funnel by stage' without new endpoints.

Where `/v2/context` is one entity, `query` is many. Pull the last 30 days of email replies, all meetings in a property, every signal from a CRM — and let your agent reason over the corpus.

Three composable powers cover most "find me X" questions without adding endpoints:

1. **`return: 'entities'`** groups results by entity (one row per person/company), ranked by most-recent matching activity
2. **`without`** subtracts a second scope from the first — for set-difference queries like "sent but no reply"
3. **`rollups.by_value`** appears when `scope.kind = 'state'` — counts entities by current value (funnel reports)

## Request

```bash theme={null}
curl -X POST https://api.opennous.cloud/v2/query \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "scope": {
      "kind": "event",
      "property": "interaction.email_replied",
      "since_days": 7,
      "limit": 10
    },
    "return": "entities",
    "question": "Who are the hottest leads this week?"
  }'
```

### Body

<ParamField body="scope" type="object" required>
  Primary filter for the corpus.

  <Expandable title="scope">
    <ParamField body="kind" type="string">
      `"event"` or `"state"`. Omit for both.
    </ParamField>

    <ParamField body="property" type="string">
      Prefix match — `interaction.email` matches `email_sent` and `email_replied`.
    </ParamField>

    <ParamField body="source" type="string">
      e.g. `"gmail"`, `"linkedin"`, `"fireflies"`.
    </ParamField>

    <ParamField body="entity_id" type="string">
      Scope to one entity.
    </ParamField>

    <ParamField body="since_days" type="number">
      Only observations within the last N days.
    </ParamField>

    <ParamField body="limit" type="number">
      Max items returned (default 50, cap 200).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="without" type="object">
  Optional set-subtract filter — **same shape as scope**. Entities matching `scope` MINUS entities matching `without`. Use for "did X but not Y" questions.
</ParamField>

<ParamField body="return" type="string" default="observations">
  `"observations"` — one row per observation (the classic shape).
  `"entities"` — one row per entity, ranked by most-recent matching activity. Each row reports its match count + the most-recent matching observation.
</ParamField>

<ParamField body="question" type="string">
  Your analytical question. Echoed back in the response. When set (and `without` is not), enables semantic ranking via embeddings.
</ParamField>

<ParamField body="budget_tokens" type="number">
  Approximate token budget for item summaries.
</ParamField>

## Response

### `return: 'observations'` (default)

```json theme={null}
{
  "scope": { ... },
  "mode": "structured",
  "return": "observations",
  "matched": 142,
  "returned": 50,
  "sampled": true,
  "items": [
    {
      "observation_id": "...",
      "entity_id": "...",
      "entity_name": "Sarah Chen",
      "when": "2026-05-21T15:00:00Z",
      "type": "interaction.email_replied",
      "source": "gmail",
      "summary": "Interested but budget waiting on Q3"
    }
  ],
  "rollups": {
    "by_type":   { "interaction.email_replied": 142 },
    "by_source": { "gmail": 120, "outlook": 22 }
  }
}
```

### `return: 'entities'`

```json theme={null}
{
  "scope": { ... },
  "return": "entities",
  "matched": 47,
  "returned": 10,
  "items": [
    {
      "entity_id": "a1b2c3d4-...",
      "entity_name": "Sarah Chen",
      "matches": 4,
      "most_recent_at": "2026-05-21T15:00:00Z",
      "most_recent_type": "interaction.email_replied",
      "most_recent_source": "gmail",
      "most_recent_summary": "Interested but budget waiting on Q3"
    }
  ],
  "rollups": { ... }
}
```

### `rollups.by_value` (when `scope.kind = 'state'`)

```json theme={null}
{
  "scope": { "kind": "state", "property": "stage" },
  "rollups": {
    "by_type":   { "stage": 198 },
    "by_source": { "hubspot": 162, "agent": 36 },
    "by_value":  {
      "identified": 120,
      "aware":      45,
      "interested": 22,
      "evaluating":  8,
      "client":      3
    }
  }
}
```

## Recipe book

The four most common "find me X" patterns:

### 🔥 Hottest leads — recent replies, grouped

```json theme={null}
{
  "scope": {
    "kind": "event",
    "property": "interaction.email_replied",
    "since_days": 7
  },
  "return": "entities",
  "limit": 10
}
```

Top 10 entities by most-recent reply.

### ❄️ Cooled in last 5 days — was active, went silent

```json theme={null}
{
  "scope":   { "kind": "event", "since_days": 30 },
  "without": { "kind": "event", "since_days": 5 },
  "return": "entities"
}
```

Entities with any activity in the last 30 days, **minus** those with any activity in the last 5 days.

### 📭 Sent without reply in last 5 days

```json theme={null}
{
  "scope":   { "kind": "event", "property": "interaction.email_sent",    "since_days": 5 },
  "without": { "kind": "event", "property": "interaction.email_replied", "since_days": 5 },
  "return": "entities"
}
```

Entities you sent to in the last 5 days, **minus** those who replied in the same window.

### 📊 Full funnel report

```json theme={null}
{
  "scope": { "kind": "state", "property": "stage" }
}
```

Read `rollups.by_value` for the stage distribution. Pair with `since_days` to bound the time window.

## Pattern-finding belongs to the agent

The graph retrieves and shapes. Your agent does the reasoning. The four recipes above are the most common; combine `scope` + `without` + `return` + `rollups.by_value` for anything else.

For your own GTM profile (ICP, pricing, etc.) use [`/v2/workspace/facts`](/public-api/gtm-profile) instead — `query` is for per-entity observations only.
