# findDeals

Search AND TOTAL the deals you can see: `totals` sums EVERY match, not the page (price, average, commission; totalCount is the count), so a total is one call. Filters: title, contact (contactIds: deals of ANY of these contacts in ONE read, matched by each row's linked contacts; page hasMore before calling one dealless, never a findDeals per contact), pipeline, stage (stageId, or stageName in all your own pipelines), outcome OPEN/WON/LOST, stageChangedAfter/Before (last stage move, eg a win; Before exclusive), closeDateAfter/Before, archived, assignees. NUMBERS: quote `totals` as they read; never add, average or count rows yourself. IMPORTANT: archived deals are INCLUDED BY DEFAULT (they sort last). Pass isArchived: false for active-only, always for "what is in my pipeline", or true to find archived ones (to restore with archiveDeal); check each result's isArchived before calling a deal current. Each deal carries its assigned users (an empty array means the deal is UNASSIGNED, nobody owns it) and its linked contacts (id + name). hasAssignedUsers: false gives the unowned deals over every deal you can see (totalCount is the count); userIds (listTeammates, never empty) gives one person's. Whether anyone is on a linked CONTACT comes only from getContact, one call per contact; a partner org's contact it refuses is "not visible to you", not "nobody". Each row carries the commission figures: commissionCents (the derived GCI) and the stored commissionAmountCents / commissionPercentBps / teamSplitAmountCents / teamSplitPercentBps, so a portfolio money question ("our GCI on everything closing this month") is one page. Read them as getDeal documents: amount XOR percent per side; all-null means no commission RECORDED, not zero. participantSplits is NOT here (getDeal). `customFieldValues` IS here, LEANER than on getDeal: the value plus the field NAME (`dealCustomField { name }`), no ids or type, for surveying (who holds which card, which have no Difficulty set) rather than writing back. Read the ONE sub-field matching the type, as getDeal documents. A field never given a value is absent, so an empty list means nothing filled in, never no fields. Custom fields multiply per row: on a `truncated` page lower `limit` rather than assume the missing deals have no values. TASKS: `taskSummary` counts open tasks and appointments on the DEAL (not its contacts); 0 means none, so "which deals have no task" is this page. In Ask Goliath omitting isArchived reads live deals only; null reads both.

- Call: `POST https://server.goliathdata.com/api/v1/call` with `{ "operationId": "findDeals", "variables": {...} }`
- Scope: `READ`
- Type: query
- Idempotency: a read; rejects `Idempotency-Key`
- Rate-limited: no
- Result cap: `limit` is clamped to 50, without an error

## Variables

- `titleContains`: `String`
- `contactId`: `ID`
- `contactIds`: `[ID!]`
- `pipelineId`: `ID`
- `stageId`: `ID`
- `isArchived`: `Boolean`
- `hasAssignedUsers`: `Boolean`
- `userIds`: `[ID!]`
- `stageName`: `String`
- `outcome`: `PipelineItemOutcomeFilter` (one of `OPEN`, `WON`, `LOST`)
- `stageChangedAfter`: `DateTime`
- `stageChangedBefore`: `DateTime`
- `closeDateAfter`: `DateTime`
- `closeDateBefore`: `DateTime`
- `limit`: `Int` (default `20`)
- `offset`: `Int` (default `0`)

## Response (data, an example)

```json
{
  "dealQuery": {
    "findDeals": {
      "deals": [
        {
          "id": "<ID>",
          "title": "…",
          "priceCents": "…",
          "priceFormatted": "…",
          "closeDate": "2026-01-01T00:00:00.000Z",
          "isArchived": true,
          "createdAt": "2026-01-01T00:00:00.000Z",
          "updatedAt": "2026-01-01T00:00:00.000Z",
          "lastStageChangeAt": "2026-01-01T00:00:00.000Z",
          "commissionCents": "…",
          "commissionAmountCents": "…",
          "commissionPercentBps": 0,
          "teamSplitAmountCents": "…",
          "teamSplitPercentBps": 0,
          "stage": {
            "id": "<ID>",
            "name": "…"
          },
          "pipeline": {
            "id": "<ID>",
            "name": "…"
          },
          "users": [
            {
              "id": "<ID>",
              "firstName": "…",
              "lastName": "…"
            }
          ],
          "contacts": [
            {
              "id": "<ID>",
              "name": "…"
            }
          ],
          "taskSummary": {
            "openTaskCount": 0,
            "openAppointmentCount": 0
          },
          "customFieldValues": [
            {
              "textValue": "…",
              "dateValue": "2026-01-01T00:00:00.000Z",
              "numberValue": 0,
              "dropdownSelectedValues": [
                "…"
              ],
              "dealCustomField": {
                "name": "…"
              }
            }
          ]
        }
      ],
      "totalCount": 0,
      "hasMore": true,
      "totals": {
        "pricedDealCount": 0,
        "priceFormatted": "…",
        "averagePriceFormatted": "…",
        "commissionDealCount": 0,
        "commissionFormatted": "…"
      }
    }
  }
}
```

## Example

```bash
curl https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer $GOLIATH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operationId": "findDeals",
    "variables": {}
  }'
```
