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

# Editing orders

> How to correct an existing order with a merge patch, and what to expect when the change fails partway.

[Update an order](https://api.docs.originone.ai/api-reference/orders/update.md) (`PATCH /api/v2/orders/{id}`) corrects an order you already placed: the participant's details, the test reason, the agency and job category, the location, the package, or when the order expires. It applies the same rules as an edit made in the Origin One app. The token needs the `order.update` scope.

> [!NOTE]
>
> An edit that changes the order notifies the participant again and regenerates the order's documents by default. Set `resendNotifications` or `reIssueDocuments` to `false` in [`settings`](#say-why-the-order-changes) to turn either off.

## Send only what changes

The body is a [JSON Merge Patch](https://www.rfc-editor.org/rfc/rfc7396) shaped like the [order](https://api.docs.originone.ai/api-reference/orders/get.md) you read:

* A member you leave out keeps its value.
* A member set to `null` is cleared, where the field allows it (such as `participant.middleName` or `agency`).
* An array replaces the whole list, except `participant.identifiers`, which is merged by `type` (see [Identifiers](#identifiers)).

Send the body as `application/merge-patch+json` or `application/json`; both mean the same. This request fixes a misspelled last name and nothing else:

```bash theme={null}
curl --request PATCH https://api.origin.one/api/v2/orders/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 \
  --header "Authorization: Bearer $ORIGIN_ONE_API_TOKEN" \
  --header "Content-Type: application/merge-patch+json" \
  --data '{
    "participant": { "lastName": "Doe" },
    "settings": { "changeReason": "misspelling" }
  }'
```

## Say why the order changes

Every request carries a `settings` member. It says why the order changes, how a new collection site is chosen, and what to send afterwards. It is not part of the order and is never returned.

| Member | Description |
| - | - |
| `changeReason` | Required. One of `misspelling`, `wrongParticipantLocation`, `wrongParticipantName`, `missingInformation`, `wrongReasonForTest`, or `other`. Recorded in the order's history. |
| `otherChangeReason` | Detail for a `changeReason` of `other`, up to 60 characters. Required with `other` and not allowed otherwise. |
| `clinicSelectionMode` | How a new collection site is chosen when `packages` changes the package and the order's site can't collect it, or it has none. `closestToParticipant` takes the nearest site within 100 miles, and `configured` the location's configured site; both schedule an `ordered` order, and the edit returns `422` when no site qualifies. `requesterSelects` assigns none and is allowed only while the order is `ordered`. Not allowed with `clinic`. |
| `reIssueDocuments` | Whether to regenerate the order's documents after the change. Defaults to `true`. Ignored while the order is `ordered`, `expired`, or `noShow`. |
| `resendNotifications` | Whether to send the order's current status notification again. Defaults to `true`. |

Documents and notifications go out once per request, and only when the order actually changed. They're sent shortly after the response, not during it, and sending is retried if it fails.

## What you can change

| Member | Notes |
| - | - |
| `participant` | `firstName`, `middleName`, `lastName`, `birthDate`, `email`, `phone`, `address`, and `identifiers`. Only the members you send change. |
| `participant.address` | Only the members you send change; the address can't be removed. An order with no address yet needs `line1`, `city`, `state`, and `postalCode`. A `country` requires `state`. |
| `testReason`, `otherTestReason` | `otherTestReason` is allowed only when `testReason` is `other`, and is cleared when `testReason` changes to another value. |
| `agency` | Required while the order has a DOT service and not allowed otherwise. `null` removes it. |
| `jobCategory` | One of the categories the order's `agency` publishes, from [List agencies](https://api.docs.originone.ai/api-reference/agencies/list.md). Required when `agency` changes to one that publishes more than one category, on an order with a DOT service; a sole category is assigned automatically. |
| `location` | Must be under a company linked to your token and offer the order's package. |
| `packages` | A one-item list; the package replaces the order's package. It must be available at the location, and it can change only until collection starts. Once the order has a collection site, that site must offer every service in the new package; otherwise send `clinic` or `settings.clinicSelectionMode` with it. |
| `clinic` | The collection site to move the order to, such as one from [List an order's clinics](https://api.docs.originone.ai/api-reference/orders/clinics.md). It must offer every service on the order, at any distance from the participant. An `ordered` order becomes `scheduled`. Allowed until collection starts; for an `expired` or `noShow` order, only when its lab is Quest, LabCorp, CRL, or Origin. |
| `expiresAt` | An ISO 8601 date-time at least one hour from now. An `expired` or `noShow` order becomes active again. |

Any other member returns `400 Bad Request` with the code `unrecognizedKeys`.

### Identifiers

`participant.identifiers` is merged by `type`, not replaced:

* Each entry replaces the stored identifier of its `type`.
* An entry with `"value": null` removes the identifier of that `type`.
* A `type` you leave out is kept.

At least one identifier must remain. A `driverLicense` with a `value` needs its `issuingState`. With `order.participant.read`, you can send an `ssn` back masked, exactly as the order returns it, and it is kept; a masked `ssn` that doesn't match the stored one returns `400 Bad Request`. Without that scope, a masked `ssn` always returns `400 Bad Request`. Send the full number to change it.

```json theme={null}
{
  "participant": {
    "identifiers": [
      { "type": "employerId", "value": "E-42" },
      { "type": "driverLicense", "value": null }
    ]
  },
  "settings": { "changeReason": "missingInformation" }
}
```

Writing identifiers needs only `order.update`. Reading them back in the response needs [`order.participant.read`](https://api.docs.originone.ai/scopes#available-scopes), as on every order response.

## The response

A successful request always returns `200 OK` with the up-to-date order, including when the patch changed nothing (for example, a body with only `settings`). The participant's `identifiers` are included only when your token also has `order.participant.read`.

## Avoid overwriting someone else's change

Every response from [Get an order](https://api.docs.originone.ai/api-reference/orders/get.md) and [Update an order](https://api.docs.originone.ai/api-reference/orders/update.md) carries an `ETag` header naming that version of the order. To change the order only if nobody else has changed it since you read it, send that value back in `If-Match`:

```bash theme={null}
curl --request PATCH https://api.origin.one/api/v2/orders/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 \
  --header "Authorization: Bearer $ORIGIN_ONE_API_TOKEN" \
  --header "Content-Type: application/merge-patch+json" \
  --header 'If-Match: W/"5a1-Lr0V3wqYk6wX0Qp9c1xQyR8m2nA"' \
  --data '{ "testReason": "random", "settings": { "changeReason": "wrongReasonForTest" } }'
```

* `If-Match` is optional. Without it, the change applies to whatever the order holds now.
* The `ETag` describes the order as your token sees it, so use one your own token received. Another token with different scopes can get a different `ETag` for the same order.
* The comparison is weak: the `W/` prefix is optional.
* When the order has changed since that version, the response is `409 Conflict` with the code `conflict` and nothing is saved. Get the order again, reapply your change, and retry with the new `ETag`.

## Errors

| Status | When |
| - | - |
| `400 Bad Request` | A value is wrong or missing. Each entry's `source.pointer` names the member at fault. A missing member has the code `required`, including one another member makes required; a value a rule rejects has `invalidValue`. |
| `403 Forbidden` | The token lacks `order.update`. |
| `404 Not Found` | The order doesn't exist or isn't under a company linked to your token. |
| `409 Conflict` | `If-Match` names an older version of the order. |
| `422 Unprocessable Entity` | The order's status or history no longer allows the change, with the code `invalidState` and a `detail` naming the rule, such as `packages cannot change once collection has started.` A new package whose services the order's collection site doesn't offer is also refused this way, since an edit can't change the collection site. |

See [Errors](https://api.docs.originone.ai/errors.md) for the error body.

## If a request fails partway

Every part of the patch is validated before anything is saved, so a `400`, `409`, or `422` means nothing changed. The order is then saved section by section: location and package, then test reason and agency, then the participant, then the expiry. If a request fails after that (a `5xx`), the sections saved before the failure stay saved, and their documents and notifications still go out.

To finish the edit, [get the order](https://api.docs.originone.ai/api-reference/orders/get.md), see which changes were saved, and send a patch with the rest, with the new `ETag` in `If-Match`. That patch's `settings` decide whether documents and notifications go out again:

* Documents are regenerated from the order as it is when they're sent, so they may show only the saved part. Keep `reIssueDocuments` on to regenerate them from the finished order.
* Set `resendNotifications` to `false` if the participant shouldn't be notified a second time.

Sending the same patch again also works: sections that already saved are unchanged and skipped. If the rest changes the order, documents and notifications go out again unless you turn them off.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.