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

# Update Order Search

> Update a search status within an order

# Update Order Search

Updates a single search within a verification order. Use this endpoint when you need to close, cancel, or reassign a specific search after the order has been created.

The route is order-scoped and validates that `searchId` belongs to the order identified by `id`.

## Path Parameters

<ParamField path="id" type="string" required>
  Verification order UUID.
</ParamField>

<ParamField path="searchId" type="string" required>
  Search UUID within the order.
</ParamField>

## Request Body

<ParamField body="searchStatus" type="string" required>
  Target status: `IN_PROGRESS`, `COMPLETED`, `CANCELLED`, or `REASSIGNED`.
</ParamField>

<ParamField body="resolution" type="object">
  Required when `searchStatus` is `COMPLETED`. The `outcome` field discriminates between a verified closeout and an
  action-required closeout.
</ParamField>

<ParamField body="resolution.outcome" type="string">
  Terminal outcome. Accepted values:

  * `VERIFIED` — verification succeeded.
  * `VERIFIED_DISCREPANCY` — verification succeeded with one or more discrepancies.
  * `VERIFIED_NO_DISCREPANCY` — verification succeeded without a discrepancy.
  * `ACTION_REQUIRED` — the search closed without a verified result and requires downstream action.

  The three verified outcomes persist a verification result and emit `verification.completed`. `ACTION_REQUIRED` does not persist
  a verification result and emits `verification.action_required`.
</ParamField>

<ParamField body="resolution.reasonCode" type="string">
  Required when `resolution.outcome` is `ACTION_REQUIRED` and prohibited for verified outcomes.

  Accepted values:

  * `THIRD_PARTY_RECORD`
  * `UPSTREAM_ISSUE`
  * `SYSTEM_FAILURE`
  * `SLA_REACHED`
  * `HUMAN_ESCALATION`
  * `PRIMARY_EDUCATION`
  * `OTHER`
</ParamField>

<ParamField body="resolution.resultDetails" type="string | object">
  Optional result details for verified outcomes. Objects are serialized before persistence.
</ParamField>

<ParamField body="resolution.submittedAt" type="string">
  Optional submission timestamp for verified outcomes.
</ParamField>

<ParamField body="resolution.metadata" type="object">
  Optional additional fields included in the `verification.completed` result payload for verified outcomes.
</ParamField>

<ParamField body="reason" type="string">
  Human-readable reason for the status update. Included in the `SEARCH_UPDATED` notification metadata and terminal context where applicable.
</ParamField>

<ParamField body="metadata" type="object">
  Additional metadata included in the `SEARCH_UPDATED` notification and terminal webhook context where applicable.
</ParamField>

<Note>
  For `COMPLETED`, provide exactly one `resolution` object. Its `outcome` determines which terminal operation and webhook the API uses. `resolution` is prohibited for `IN_PROGRESS`, `REASSIGNED`, and `CANCELLED`.
</Note>

<Note>
  `resolution.reasonCode` is required when `resolution.outcome` is `ACTION_REQUIRED` and prohibited for verified outcomes.
</Note>

## Status Transitions

| Transition                                                              | Result                                                                                                                      |
| ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Any terminal status to `IN_PROGRESS`                                    | Rejected with `409`                                                                                                         |
| Any terminal status to a different terminal status                      | Rejected with `409`                                                                                                         |
| Same status as current                                                  | `200` no-op; no webhooks are re-emitted                                                                                     |
| `IN_PROGRESS` to `COMPLETED` with a verified `resolution.outcome`       | Persists the result and emits `verification.notification` (`SEARCH_UPDATED`) and `verification.completed`                   |
| `IN_PROGRESS` to `COMPLETED` with `resolution.outcome: ACTION_REQUIRED` | Emits `verification.notification` (`SEARCH_UPDATED`) and `verification.action_required`                                     |
| `IN_PROGRESS` to `REASSIGNED`                                           | Emits `verification.notification` (`SEARCH_UPDATED`) and `verification.action_required` with `reasonCode: HUMAN_ESCALATION` |
| `IN_PROGRESS` to `CANCELLED`                                            | Emits `verification.notification` (`SEARCH_UPDATED`) only                                                                   |

<Note>
  Sending the search's current status returns `200` as a no-op. The API does not re-emit webhooks, cancel outbound work again, or repeat workflow changes.
</Note>

## Terminal Side Effects

Real transitions to `COMPLETED`, `REASSIGNED`, or `CANCELLED` cancel pending and scheduled outbound work for that search and stop workflow processing.

Cancellation covers pending outbound work plus `SCHEDULED` or `PAUSED` contact attempts.

<Note>
  Already-sent outbound is not recalled.
</Note>

## Order Roll-Up

An order becomes `COMPLETED` when none of its searches remain `IN_PROGRESS`. Terminal-for-order search statuses are:

* `COMPLETED`
* `CANCELLED`
* `REASSIGNED`

The parent order is set to `COMPLETED` when the final in-progress sibling leaves `IN_PROGRESS`. Use `DELETE /background-check/v1/orders/{id}` to set an order to `CANCELLED`.

## Example Requests

### Complete With a Verification Result

<CodeGroup>
  ```bash cURL theme={null}
  curl -sS -X PATCH "https://sandbox.theary.ai/background-check/v1/orders/550e8400-e29b-41d4-a716-446655440000/searches/7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "searchStatus": "COMPLETED",
      "resolution": {
        "outcome": "VERIFIED",
        "resultDetails": "Employment dates and title verified by HR.",
        "submittedAt": "2026-07-02T18:00:00.000Z"
      },
      "reason": "Manual verified closeout"
    }'
  ```

  ```javascript JavaScript theme={null}
  const orderId = '550e8400-e29b-41d4-a716-446655440000'
  const searchId = '7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111'
  const response = await fetch(
    `https://sandbox.theary.ai/background-check/v1/orders/${orderId}/searches/${searchId}`,
    {
      method: 'PATCH',
      headers: {
        Authorization: 'Bearer YOUR_JWT_TOKEN',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        searchStatus: 'COMPLETED',
        resolution: {
          outcome: 'VERIFIED',
          resultDetails: 'Employment dates and title verified by HR.',
          submittedAt: '2026-07-02T18:00:00.000Z',
        },
        reason: 'Manual verified closeout',
      }),
    },
  )

  const result = await response.json()
  ```

  ```python Python theme={null}
  import requests

  order_id = "550e8400-e29b-41d4-a716-446655440000"
  search_id = "7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111"
  response = requests.patch(
      f"https://sandbox.theary.ai/background-check/v1/orders/{order_id}/searches/{search_id}",
      headers={
          "Authorization": "Bearer YOUR_JWT_TOKEN",
          "Content-Type": "application/json",
      },
      json={
          "searchStatus": "COMPLETED",
          "resolution": {
              "outcome": "VERIFIED",
              "resultDetails": "Employment dates and title verified by HR.",
              "submittedAt": "2026-07-02T18:00:00.000Z",
          },
          "reason": "Manual verified closeout",
      },
  )

  result = response.json()
  ```
</CodeGroup>

### Complete As Action Required

<CodeGroup>
  ```bash cURL theme={null}
  curl -sS -X PATCH "https://sandbox.theary.ai/background-check/v1/orders/550e8400-e29b-41d4-a716-446655440000/searches/7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "searchStatus": "COMPLETED",
      "resolution": {
        "outcome": "ACTION_REQUIRED",
        "reasonCode": "OTHER"
      },
      "reason": "No record found after manual review"
    }'
  ```

  ```javascript JavaScript theme={null}
  const orderId = '550e8400-e29b-41d4-a716-446655440000'
  const searchId = '7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111'
  const response = await fetch(
    `https://sandbox.theary.ai/background-check/v1/orders/${orderId}/searches/${searchId}`,
    {
      method: 'PATCH',
      headers: {
        Authorization: 'Bearer YOUR_JWT_TOKEN',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        searchStatus: 'COMPLETED',
        resolution: {
          outcome: 'ACTION_REQUIRED',
          reasonCode: 'OTHER',
        },
        reason: 'No record found after manual review',
      }),
    },
  )

  const result = await response.json()
  ```

  ```python Python theme={null}
  import requests

  order_id = "550e8400-e29b-41d4-a716-446655440000"
  search_id = "7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111"
  response = requests.patch(
      f"https://sandbox.theary.ai/background-check/v1/orders/{order_id}/searches/{search_id}",
      headers={
          "Authorization": "Bearer YOUR_JWT_TOKEN",
          "Content-Type": "application/json",
      },
      json={
          "searchStatus": "COMPLETED",
          "resolution": {
              "outcome": "ACTION_REQUIRED",
              "reasonCode": "OTHER",
          },
          "reason": "No record found after manual review",
      },
  )

  result = response.json()
  ```
</CodeGroup>

### Reassign

<CodeGroup>
  ```bash cURL theme={null}
  curl -sS -X PATCH "https://sandbox.theary.ai/background-check/v1/orders/550e8400-e29b-41d4-a716-446655440000/searches/7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "searchStatus": "REASSIGNED",
      "reason": "Manual operator review requested"
    }'
  ```

  ```javascript JavaScript theme={null}
  const orderId = '550e8400-e29b-41d4-a716-446655440000'
  const searchId = '7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111'
  const response = await fetch(
    `https://sandbox.theary.ai/background-check/v1/orders/${orderId}/searches/${searchId}`,
    {
      method: 'PATCH',
      headers: {
        Authorization: 'Bearer YOUR_JWT_TOKEN',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        searchStatus: 'REASSIGNED',
        reason: 'Manual operator review requested',
      }),
    },
  )

  const result = await response.json()
  ```

  ```python Python theme={null}
  import requests

  order_id = "550e8400-e29b-41d4-a716-446655440000"
  search_id = "7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111"
  response = requests.patch(
      f"https://sandbox.theary.ai/background-check/v1/orders/{order_id}/searches/{search_id}",
      headers={
          "Authorization": "Bearer YOUR_JWT_TOKEN",
          "Content-Type": "application/json",
      },
      json={
          "searchStatus": "REASSIGNED",
          "reason": "Manual operator review requested",
      },
  )

  result = response.json()
  ```
</CodeGroup>

### Cancel

<CodeGroup>
  ```bash cURL theme={null}
  curl -sS -X PATCH "https://sandbox.theary.ai/background-check/v1/orders/550e8400-e29b-41d4-a716-446655440000/searches/7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "searchStatus": "CANCELLED",
      "reason": "Applicant withdrew from hiring process"
    }'
  ```

  ```javascript JavaScript theme={null}
  const orderId = '550e8400-e29b-41d4-a716-446655440000'
  const searchId = '7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111'
  const response = await fetch(
    `https://sandbox.theary.ai/background-check/v1/orders/${orderId}/searches/${searchId}`,
    {
      method: 'PATCH',
      headers: {
        Authorization: 'Bearer YOUR_JWT_TOKEN',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        searchStatus: 'CANCELLED',
        reason: 'Applicant withdrew from hiring process',
      }),
    },
  )

  const result = await response.json()
  ```

  ```python Python theme={null}
  import requests

  order_id = "550e8400-e29b-41d4-a716-446655440000"
  search_id = "7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111"
  response = requests.patch(
      f"https://sandbox.theary.ai/background-check/v1/orders/{order_id}/searches/{search_id}",
      headers={
          "Authorization": "Bearer YOUR_JWT_TOKEN",
          "Content-Type": "application/json",
      },
      json={
          "searchStatus": "CANCELLED",
          "reason": "Applicant withdrew from hiring process",
      },
  )

  result = response.json()
  ```
</CodeGroup>

## Response

<ResponseField name="success" type="boolean">
  Whether the update succeeded.
</ResponseField>

<ResponseField name="orderId" type="string">
  Parent order identifier.
</ResponseField>

<ResponseField name="searchId" type="string">
  Updated search identifier.
</ResponseField>

<ResponseField name="externalSearchId" type="string">
  External system search identifier.
</ResponseField>

<ResponseField name="previousStatus" type="string">
  Search status before the request.
</ResponseField>

<ResponseField name="currentStatus" type="string">
  Search status after the request.
</ResponseField>

<ResponseField name="orderStatus" type="string">
  Parent order status after the update.
</ResponseField>

<ResponseField name="orderRollupApplied" type="boolean">
  True when this update caused the parent order to roll up to `COMPLETED`.
</ResponseField>

<ResponseField name="webhooksEmitted" type="string[]">
  Webhook event types emitted by the request.
</ResponseField>

## Example Response

```json theme={null}
{
  "success": true,
  "orderId": "550e8400-e29b-41d4-a716-446655440000",
  "searchId": "7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111",
  "externalSearchId": "EXT-12345",
  "previousStatus": "IN_PROGRESS",
  "currentStatus": "COMPLETED",
  "orderStatus": "COMPLETED",
  "orderRollupApplied": true,
  "webhooksEmitted": ["verification.notification", "verification.completed"]
}
```

## Webhook Behavior

Every status-changing request emits a `verification.notification` webhook with `notificationType: SEARCH_UPDATED`. Depending on
the target status and resolution, the API may also emit a terminal webhook:

| Update                                                                            | Webhooks emitted                                                                                                      |
| --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `COMPLETED` with `VERIFIED`, `VERIFIED_DISCREPANCY`, or `VERIFIED_NO_DISCREPANCY` | `verification.notification` (`SEARCH_UPDATED`) and `verification.completed`                                           |
| `COMPLETED` with `ACTION_REQUIRED`                                                | `verification.notification` (`SEARCH_UPDATED`) and `verification.action_required`                                     |
| `REASSIGNED`                                                                      | `verification.notification` (`SEARCH_UPDATED`) and `verification.action_required` with `reasonCode: HUMAN_ESCALATION` |
| `CANCELLED`                                                                       | `verification.notification` (`SEARCH_UPDATED`)                                                                        |
| Same status as current                                                            | No webhook is emitted                                                                                                 |

The `SEARCH_UPDATED` notification describes the lifecycle transition. Its `metadata` includes the previous and current statuses,
the changed field, the API trigger, the optional request reason, and any request `metadata`.

```json theme={null}
{
  "event": "verification.notification",
  "occurredAt": "2026-07-02T18:00:00.000Z",
  "data": {
    "searchId": "7c7b8f66-7f6a-4b52-9e85-8b3f5b7c1111",
    "externalSearchId": "EXT-12345",
    "searchType": "EMPLOYMENT",
    "notificationType": "SEARCH_UPDATED",
    "metadata": {
      "updatedFields": ["searchStatus"],
      "previousStatus": "IN_PROGRESS",
      "currentStatus": "COMPLETED",
      "source": "api",
      "trigger": "search_update",
      "reason": "Manual verified closeout"
    }
  }
}
```

For verified closeouts, `verification.completed` contains the persisted verification result from `resolution`. For
action-required closeouts, `verification.action_required` contains `resolution.reasonCode`; reassignment uses
`HUMAN_ESCALATION`. See [Webhook Events](/webhooks/events) for complete payload definitions.

## Error Responses

| Status | Condition                                                                                                      |
| ------ | -------------------------------------------------------------------------------------------------------------- |
| `400`  | Invalid request body, missing or invalid `resolution`, or a `resolution` supplied for a non-`COMPLETED` update |
| `404`  | Search was not found for the supplied order                                                                    |
| `409`  | Request attempts to move a terminal search back to `IN_PROGRESS` or to another terminal status                 |
