# startSearchJob

mutation · in the family [Reading your records](/reference/reading-your-records/)

## What it does

Start a search plan in the background — start at one kind of record, follow its links step by step, and let the platform dig while you carry on; read the matches when it is done.

Start ONE background search — a validated plan run AS YOU, in the background: the SearchPlanInput grammar VERBATIM, and the SAME PLAN GATE as searchPlanRun refuses BEFORE any read — an unknown family, a field outside its roster, a hop that is not a relationship of the current family — naming the legal words; a family you may not list refuses the whole plan. The job records the plan (`planJson`) and its words, runs ONE bounded step at a time (pages of 1000; at most 50000 records examined — the estimate refuses a plan that cannot fit, with the numbers; 300 s from the start → expired WITH the partials; at most 400 steps), and lands its matches as ONE result set for 7 days (read them with searchJobMatches). ONE running job per signed-in session — a second start refuses CONFLICT/SEARCH_JOB_ACTIVE naming the holder: wait for it to finish or cancel it. Where no machine is wired the same steps run inline and the job comes back finished. A JSON null on an optional input field reads as absent. Requires the unrestricted capability on a USER session (an API key or a collaborator refuses AUTHZ/FORBIDDEN — the job is yours: your user, your session).

## What happens

It runs as you, inside your organization, over records you may already list; a plan naming a kind you cannot list is refused before anything is read. One background search runs per sign-in at a time — a second start is refused until the first finishes or you cancel it. A search stops on its own after five minutes or fifty thousand records examined, keeping what it found so far. Nothing else changes.

## Who may call it

Capability area: **Reading your records** — Looking up and listing the records of your organization.

- Owner
- System Administrator
- Manager
- Associate Manager
- Warehouse Associate
- Sales Associate
- An API key whose scope allows `api:startSearchJob`

## Arguments

| Name | Type | Required | Notes |
| --- | --- | --- | --- |
| `plan` | [SearchPlanInput](/types/SearchPlanInput/) `SearchPlanInput!` | yes | No further notes. |

## Returns

[SearchJob](/types/SearchJob/) `SearchJob!` — the budget rule: at most 50000 records examined (the estimate refuses a plan that cannot fit, with the numbers) · 300 s from the start (past it the job is expired WITH its partials) · 400 machine steps. ONE running job per signed-in session (the SEARCHLOCK marker — a second start refuses CONFLICT/SEARCH_JOB_ACTIVE naming the holder). Lifecycle queued → running → done | cancelled | expired | failed: cancel is the owner's (cancelSearchJob) or the session's end; done stays listed, the other terminals are doomed-class. The generic wire is READ-ONLY (the two reads) — the bespokes own the writes: startSearchJob (THE PLAN GATE, then the per-family list-op offer AS THE CALLER — a family you may not list stops the plan before any read) · cancelSearchJob · searchJobMatches (gated by the READER's own list right over the plan's terminal family).

## Example request

```graphql
mutation ExampleStartSearchJob($plan: SearchPlanInput!) {
  startSearchJob(plan: $plan) {
    id
    sysId
    type
    caption
    status
    parentId
    rootId
    createdAt
    updatedAt
    revisionNum
    revision
    userId
    sessionId
    planJson
    words
    stepsDone
    examined
    matchCount
    startedAt
    finishedAt
    problem
    sfExecutionArn
    resultTtl
  }
}
```

Variables:

```json
{
  "plan": {
    "start": {
      "family": "<family>",
      "filter": {
        "clauses": [
          {
            "field": "<field>",
            "op": "<op>",
            "values": [
              "<values>"
            ]
          }
        ]
      }
    },
    "hops": [
      {
        "direction": "outbound",
        "field": "<field>",
        "family": "<family>",
        "filter": {
          "clauses": [
            {
              "field": "<field>",
              "op": "<op>",
              "values": [
                "<values>"
              ]
            }
          ]
        }
      }
    ]
  }
}
```

Send it with the envelope naming the version: `"extensions": {"at": {"version": {"name":"genesis","number":0}}}`.

## Example response

```json
{
  "data": {
    "startSearchJob": {
      "id": "01900000-0000-7000-8000-37386ae00000",
      "sysId": "SJ-EXMP-0000-000F",
      "type": "SearchJob",
      "caption": "Blue jeans",
      "status": "queued",
      "parentId": "01900000-0000-7000-8000-065235280000",
      "rootId": "01900000-0000-7000-8000-a093dd800000",
      "createdAt": "2027-01-31T00:00:00.000Z",
      "updatedAt": "2027-01-31T00:00:00.000Z",
      "revisionNum": 1,
      "revision": "01900000-0000-7000-8000-b7960e180000",
      "userId": "01900000-0000-7000-8000-11f967df0000",
      "sessionId": "01900000-0000-7000-8000-be25a35a0000",
      "planJson": "<plan json>",
      "words": "<words>",
      "stepsDone": 1,
      "examined": 1,
      "matchCount": 1,
      "startedAt": "2027-01-31T00:00:00.000Z",
      "finishedAt": "2027-01-31T00:00:00.000Z",
      "problem": "<problem>",
      "sfExecutionArn": "<sf execution arn>",
      "resultTtl": 1
    }
  },
  "extensions": {
    "at": {
      "callId": "01EXAMPLE-CALL-ID",
      "version": {
        "requested": {
          "name": "genesis",
          "number": 0
        },
        "serviced": {
          "name": "genesis",
          "number": 0
        }
      }
    }
  }
}
```

## Errors this call can answer

- `VALIDATION/INVALID` — Something in the request is not valid. ([VALIDATION](/errors/VALIDATION/))
- `AUTHN/REQUIRED` — Sign in to do this. ([AUTHN](/errors/AUTHN/))
- `AUTHZ/FORBIDDEN` — Your role does not allow this action. ([AUTHZ](/errors/AUTHZ/))
- `RATE_LIMIT/THROTTLED` — Too many requests in a short time. ([RATE_LIMIT](/errors/RATE_LIMIT/))
- `CONFLICT/*` — The record’s state, or a change made in the meantime, does not allow this; the codes are on the CONFLICT page. ([CONFLICT](/errors/CONFLICT/))
- `VALIDATION/VERSION_REQUIRED` — The request did not say which app version it came from. ([VALIDATION](/errors/VALIDATION/))
