> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.benchling.com/in-vivo/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.benchling.com/in-vivo/_mcp/server.

# Update samples

PATCH https://acme-api.invivo.benchling.com/api/public/v1/studies/{studyId}/samples
Content-Type: application/json

Updates between 1 and 100 samples on the study. The request is validated as a whole; if any item is invalid, none are updated.

Reference: https://docs.benchling.com/in-vivo/study-samples/study-sample-bulk-update

## Authentication

- OAuth2 — send the obtained token as `Authorization: Bearer <token>`

## Request

### Path parameters

- `studyId` (string, required) — The unique identifier of the study.

### Body (application/json)

This endpoint expects a list of SamplePatchV1.

- `list of SamplePatchV1`

## Response

### 200

The updated samples.

- `data` (list of SampleV1, required) — The samples.

## Errors

### 400 Bad Request Error

The request was rejected. Validation failures return a `ValidationErrorResponse`; an unrecognised `X-Studies-Api-Version` header returns an `AuthErrorResponse` with the code `invalid_header`.

- `BadRequestErrorResponse`

### 401 Unauthorized Error

Authentication failed. The body is normally empty; when an otherwise valid access token is missing required claims the body is an `AuthErrorResponse` with the code `invalid_token`.

- `any`

### 403 Forbidden Error

The access token does not grant the scopes this operation requires. The body is normally empty; when the token's team is missing or deleted the body is an `AuthErrorResponse` with the code `invalid_data`.

- `any`

### 429 Too Many Requests Error

A rate limit was exceeded. Retry once the window resets; no `Retry-After` header is sent, so use `X-RateLimit-Reset`.

- `error` ("rate_limit_exceeded", required) — A machine-readable error code.
- `message` (string, required) — A human-readable explanation of the failure.

## Types

### SamplePatchV1

The changes to apply to one sample on the study. Omitted properties are left untouched. A collected sample cannot be moved back to `planned`, and a `collected_at` once set cannot be cleared.

- `id` (string, required) — The sample to update. Must be on the study.
- `sample_id` (string, optional) — The human-readable identifier written on the sample. Must be unique across your team and within the request.
- `status` (enum, optional, nullable) — The new status. Only `collected` and `planned` are accepted, and null leaves the status unchanged. Moving to `collected` requires `collected_at`, either already set or sent in the same item; `planned` rejects it.
  - Allowed values: `collected`, `planned`, `cancelled`
- `collected_at` (string, optional, nullable) — When the sample was collected, as a full ISO-8601 UTC date-time: either an explicit UTC instant (offset `Z` or `+00:00`) or an offset-less date-time taken as UTC. Date-only values and non-UTC offsets are rejected. May not be before the animal's date of birth. Null is accepted only while the sample has no collection time, and changes nothing.
- `timepoint` (string, optional, nullable) — When the sample is due relative to the study schedule, as an ISO-8601 duration such as `P1D` or `PT4H`, optionally negative. For a sample from a definition it must be one of the definition's timepoints; otherwise its magnitude must be zero or between 1 minute and 365 days. Null clears it.
- `comments` (string, optional, nullable) — A comment recorded against the sample. Null clears it.
- `details` (list of SampleDetailV1, optional, nullable) — Replaces the sample's measured attributes; null clears them. Each key must be valid for the sample type and appear once, a non-null `value` must be a non-negative number and needs a `unit`, and a unit already recorded for a key cannot change.
- `metadata` (map from string to any, optional, nullable) — Custom fields merged into the existing metadata, keyed by your team's active sample metadata glossary slugs. Set an individual value to null to delete that key; keys your team marks mandatory cannot be deleted. Multi-select values must be arrays.

### SampleV1

A specimen collected from an animal, or planned for collection. A sample is described by its sample definition, which determines its `type`, the `details` recorded against it, and the `timepoint` it is due at relative to the study schedule.

- `id` (string, required) — Unique identifier for a sample.
- `sample_id` (string, required) — The human-readable identifier written on the sample itself. This is a label, not an API identifier — use `id` to address the sample through the API.
- `sample_definition_id` (string, required, nullable) — The sample definition describing what was collected. Null for a sample recorded without one.
- `type` (string, required, nullable) — What was collected. Free-form text drawn from your team's configuration rather than a fixed set of values.
- `label` (string, required, nullable) — The short label your team has given the sample type, for use where the full type name does not fit.
- `status` (enum, required) — Whether a sample has been collected yet. A `planned` sample was scheduled from a sample definition but not yet taken.
  - Allowed values: `collected`, `planned`, `cancelled`
- `timepoint` (string, required, nullable) — When the sample is due, as an offset from the study event it hangs off. Null for a sample that is not scheduled.
- `collected_at` (datetime, required, nullable) — The time the sample was collected. Null while the sample is only planned.
- `details` (list of SampleDetailV1, required) — The attributes measured on the sample.
- `comments` (string, required, nullable) — Any note recorded alongside the sample.
- `metadata` (map from string to any, required, nullable) — The metadata associated to the sample.
- `study` (StudyNestedV1, required, nullable) — The study the sample was collected under. Null when the animal is not on a study.
- `animal` (AnimalNestedV1, required) — The animal a record belongs to, as embedded in dosages, measurements, observations and samples. Carries the same attributes as an animal retrieved directly, except that the cage, study and treatment group are given as identifiers rather than embedded objects.
- `user` (UserV1, required, nullable) — The user who collected the sample.
- `created_at` (datetime, required) — UTC timestamp with microsecond precision, always suffixed with `Z`, in the form `yyyy-MM-ddTHH:mm:ss.SSSSSSZ`.
- `updated_at` (datetime, required) — UTC timestamp with microsecond precision, always suffixed with `Z`, in the form `yyyy-MM-ddTHH:mm:ss.SSSSSSZ`.

### ValidationErrorResponse

Returned when a request body or parameter fails validation.

- `message` (string, required) — A summary of the failure.
- `errors` (map from string to list of string, required) — Failure messages keyed by the offending field, using the field's name as it appears on the wire. Nested fields are dotted, e.g. `schedule.duration`.

### AuthErrorResponse

Returned when a request is rejected during authentication, before it is processed.

- `error` (enum, required) — A machine-readable error code.
  - Allowed values: `invalid_header`, `invalid_token`, `invalid_data`
- `error_description` (string, required) — A human-readable explanation of the failure.

### ProblemDetail

An RFC 9457 problem detail, returned when a request is rejected before it reaches a controller method — most commonly an unparseable or absent JSON body. Unlike the rest of this API, null members are omitted rather than serialised as `null`.

- `title` (string, required) — A short, human-readable summary of the problem type.
- `status` (integer, required) — The HTTP status code, repeated in the body.
- `detail` (string, required) — A human-readable explanation specific to this occurrence.
- `instance` (string, required) — The path of the request that produced the problem.

### SampleDetailV1

One measured attribute of a sample, such as the volume or mass collected. Which details a sample carries is determined by its sample definition.

- `key` (string, required, nullable) — The slug identifying the detail within the sample definition.
- `value` (string, required, nullable) — The recorded value, as a string so that the precision recorded is preserved exactly.
- `unit` (string, required, nullable) — The unit the value was recorded in.

### StudyNestedV1

The study a record belongs to, as embedded in animals, dosages, measurements, observations and samples. Carries the same attributes as a study retrieved directly, except that the project is given as an identifier rather than an embedded object.

- `id` (string, required) — Unique identifier for a study.
- `project_id` (string, required, nullable) — The project of the study. Null when the study is not in a project.
- `name` (string, required) — The name of the study.
- `code` (string, required, nullable) — The code of the study.
- `study_code_id` (string, required, nullable) — The unique identifier of the study code template.
- `type` (enum, required) — Whether the study is run in-house or by an external partner. The `all` value accepted by some filters is not a valid study type and is never returned.
  - Allowed values: `internal`, `external`
- `status` (enum, required) — Review status of a study.
  - Allowed values: `awaiting_approval`, `in_progress`, `rejected`
- `description` (string, required, nullable) — The description of the study.
- `timezone` (string, required, nullable) — The timezone of the study, as an IANA timezone identifier.
- `metadata` (map from string to any, required, nullable) — The metadata associated to the study.
- `author` (StudyAuthorUserV1, required, nullable) — The author of the study.
- `owner` (StudyAuthorUserV1, required, nullable) — The owner of the study.
- `started_on` (date, required) — Calendar date with no time or offset component, in ISO-8601 form.
- `tracking_day_base` (integer, required, nullable) — The day number assigned to the study's start date, from which all subsequent tracking days are counted.
- `completed_at` (datetime, required, nullable) — The completed timestamp of the study.
- `canceled_at` (datetime, required, nullable) — The canceled timestamp of the study.
- `created_at` (datetime, required) — UTC timestamp with microsecond precision, always suffixed with `Z`, in the form `yyyy-MM-ddTHH:mm:ss.SSSSSSZ`.
- `updated_at` (datetime, required) — UTC timestamp with microsecond precision, always suffixed with `Z`, in the form `yyyy-MM-ddTHH:mm:ss.SSSSSSZ`.

### AnimalNestedV1

The animal a record belongs to, as embedded in dosages, measurements, observations and samples. Carries the same attributes as an animal retrieved directly, except that the cage, study and treatment group are given as identifiers rather than embedded objects.

- `id` (string, required) — Unique identifier for an animal.
- `name` (string, required) — The name of the animal.
- `number` (integer, required) — The position of the animal within its cage.
- `catalog` (string, required, nullable) — The catalog number of the animal.
- `species` (string, required, nullable) — The species of the animal, derived from its strain. Null when the animal has no strain assigned.
- `strain` (string, required, nullable) — The strain of the animal.
- `sex` (enum, required, nullable) — The sex of the animal.
  - Allowed values: `m`, `f`, `u`
- `dob` (date, required, nullable) — The date of birth of the animal.
- `donor` (string, required, nullable) — The donor identifier of the animal.
- `ear` (string, required, nullable) — The ear marking identifying the animal.
- `tag` (string, required, nullable) — The tag identifying the animal.
- `tail` (string, required, nullable) — The tail marking identifying the animal.
- `cage_id` (string, required, nullable) — The cage the animal is housed in.
- `study_id` (string, required, nullable) — The study the animal is enrolled on. Null when it is not on a study.
- `study_group_id` (string, required, nullable) — The treatment group the animal is assigned to. Null when it is not on a study, or is on one but not yet grouped.
- `tracking_date` (date, required, nullable) — The date from which the animal's tracking days are counted.
- `disease_induction_date` (date, required, nullable) — The date the animal had a disease induced.
- `disease_survivor` (boolean, required, nullable) — Whether the animal survived the induced disease.
- `terminated_at` (date, required, nullable) — The date the animal was terminated. Null while the animal is alive.
- `terminated_by` (StudyAuthorUserV1, required, nullable) — The user who recorded the termination.
- `terminated_reason` (AnimalTerminatedReasonV1, required, nullable) — Why the animal was terminated.
- `metadata` (map from string to any, required, nullable) — The metadata associated to the animal.
- `created_at` (datetime, required) — UTC timestamp with microsecond precision, always suffixed with `Z`, in the form `yyyy-MM-ddTHH:mm:ss.SSSSSSZ`.
- `updated_at` (datetime, required) — UTC timestamp with microsecond precision, always suffixed with `Z`, in the form `yyyy-MM-ddTHH:mm:ss.SSSSSSZ`.

### UserV1

A member of your team, as referenced by the records they created. This is the fuller user representation; studies reference a narrower one that omits `status`, `metadata` and the timestamps.

- `id` (string, required) — Unique identifier for a user.
- `name` (string, required) — The name of the user.
- `email` (string, required) — The email address of the user.
- `timezone` (string, required, nullable) — The timezone of the user, as an IANA timezone identifier.
- `status` (enum, required) — The standing of a user within your team. `pending` means the invitation has not yet been accepted, and `revoked` means access was withdrawn.
  - Allowed values: `active`, `pending`, `inactive`, `revoked`
- `metadata` (map from string to any, required, nullable) — The metadata associated to the user.
- `created_at` (datetime, required) — UTC timestamp with microsecond precision, always suffixed with `Z`, in the form `yyyy-MM-ddTHH:mm:ss.SSSSSSZ`.
- `updated_at` (datetime, required) — UTC timestamp with microsecond precision, always suffixed with `Z`, in the form `yyyy-MM-ddTHH:mm:ss.SSSSSSZ`.

### StudyAuthorUserV1

A user referenced as the author or owner of a study.

- `id` (string, required) — Unique identifier for a user.
- `name` (string, required) — The name of the user.
- `email` (string, required) — The email address of the user.
- `timezone` (string, required) — The timezone of the user. Defaults to `UTC` when the user has none set.

### AnimalTerminatedReasonV1

Why an animal was terminated. The reason is chosen from the shared glossary, or recorded free-form when no glossary entry fits.

- `glossary_id` (string, required, nullable) — The glossary entry the reason was chosen from. Null when the reason was recorded free-form.
- `title` (string, required, nullable) — The reason for the termination.
- `comment` (string, required, nullable) — Any further detail recorded alongside the reason.

## Examples

**Request**

```json
[
  {
    "id": "spl_8wQ5mKpNvR3xTz7YbCdFgP"
  }
]
```

**Response**

```json
{
  "data": [
    {
      "id": "spl_8wQ5mKpNvR3xTz7YbCdFgP",
      "sample_id": "S596602244",
      "sample_definition_id": "sdf_7yQ2mKpNvR8xTw4YbCdFgT",
      "type": "Blood",
      "label": "BLOOD",
      "status": "collected",
      "timepoint": "PT4H",
      "collected_at": "2026-09-18T14:03:22.123456Z",
      "details": [
        {
          "key": "volume",
          "value": "5",
          "unit": "ml"
        }
      ],
      "comments": "string",
      "metadata": {
        "cohort_size": 24,
        "species": "Mus musculus"
      },
      "study": {
        "id": "sdy_3vQ8kZpLmN2xRt7YwBcDfG",
        "project_id": "pjt_9kLmNpQrStUvWxYzAbCdEf",
        "name": "string",
        "code": "string",
        "study_code_id": "sdc_7hJ4nQrXsT9wYzAbCdEfGh",
        "type": "internal",
        "status": "in_progress",
        "description": "string",
        "timezone": "America/Los_Angeles",
        "metadata": {
          "cohort_size": 24,
          "species": "Mus musculus"
        },
        "author": {
          "id": "usr_2fBnKqWxYz5tRvMpLsJdHc",
          "name": "string",
          "email": "string",
          "timezone": "string"
        },
        "owner": {
          "id": "usr_2fBnKqWxYz5tRvMpLsJdHc",
          "name": "string",
          "email": "string",
          "timezone": "string"
        },
        "started_on": "2026-09-18",
        "tracking_day_base": 1,
        "completed_at": "2026-09-18T14:03:22.123456Z",
        "canceled_at": "2026-09-18T14:03:22.123456Z",
        "created_at": "2026-09-18T14:03:22.123456Z",
        "updated_at": "2026-09-18T14:03:22.123456Z"
      },
      "animal": {
        "id": "aml_7KpQ2mNvR4tXwZ9bYcDfGh",
        "name": "string",
        "number": 1,
        "catalog": "string",
        "species": "Mus musculus",
        "strain": "string",
        "sex": "m",
        "dob": "2026-09-18",
        "donor": "string",
        "ear": "string",
        "tag": "string",
        "tail": "string",
        "cage_id": "cge_5mR8kWpQnL3xTv7YzBcDfH",
        "study_id": "sdy_3vQ8kZpLmN2xRt7YwBcDfG",
        "study_group_id": "grp_9nT4kZpMvR2xQw8YbCdFgJ",
        "tracking_date": "2026-09-18",
        "disease_induction_date": "2026-09-18",
        "disease_survivor": true,
        "terminated_at": "2026-09-18",
        "terminated_by": {
          "id": "usr_2fBnKqWxYz5tRvMpLsJdHc",
          "name": "string",
          "email": "string",
          "timezone": "string"
        },
        "terminated_reason": {
          "glossary_id": "gly_5xQ4mKpNvR9zTw3YbCdFgV",
          "title": "string",
          "comment": "string"
        },
        "metadata": {
          "cohort_size": 24,
          "species": "Mus musculus"
        },
        "created_at": "2026-09-18T14:03:22.123456Z",
        "updated_at": "2026-09-18T14:03:22.123456Z"
      },
      "user": {
        "id": "usr_2fBnKqWxYz5tRvMpLsJdHc",
        "name": "string",
        "email": "string",
        "timezone": "America/Los_Angeles",
        "status": "active",
        "metadata": {
          "cohort_size": 24,
          "species": "Mus musculus"
        },
        "created_at": "2026-09-18T14:03:22.123456Z",
        "updated_at": "2026-09-18T14:03:22.123456Z"
      },
      "created_at": "2026-09-18T14:03:22.123456Z",
      "updated_at": "2026-09-18T14:03:22.123456Z"
    }
  ]
}
```

**SDK Code**

```python
import requests

url = "https://acme-api.invivo.benchling.com/api/public/v1/studies/sdy_3vQ8kZpLmN2xRt7YwBcDfG/samples"

payload = [{ "id": "spl_8wQ5mKpNvR3xTz7YbCdFgP" }]
headers = {
    "Authorization": "<token>.",
    "Content-Type": "application/json"
}

response = requests.patch(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://acme-api.invivo.benchling.com/api/public/v1/studies/sdy_3vQ8kZpLmN2xRt7YwBcDfG/samples';
const options = {
  method: 'PATCH',
  headers: {Authorization: '<token>.', 'Content-Type': 'application/json'},
  body: '[{"id":"spl_8wQ5mKpNvR3xTz7YbCdFgP"}]'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```