List contaminations
The workspace's contamination logs, newest first. Narrow to one plant or explant, to one status, or to what was logged since a point in time. Withdrawn logs are never listed.
https://app.xplantpro.com/ api/ v1/ contaminationsread:contaminationsQuery parameters
| Name | Type | Required | Description |
|---|---|---|---|
plant_id | string (uuid) | No | Only contaminations linked to this plant. |
explant_id | string (uuid) | No | Only contaminations linked to this explant. |
status | "active" | "resolved" | "quarantined" | "archived" | "under investigation" | No | Only contaminations in this state. |
since | string (date-time) | No | Only contaminations logged at or after this ISO 8601 timestamp. Keep the newest created_at you have received and send it back to fetch only what is new. |
limit | integer | No | Page size. Values above 200 are capped at 200. Default 50. From 1 to 200. |
offset | integer | No | Number of records to skip. Prefer cursor where a list offers it: an offset shifts when records are added ahead of it. Default 0. At least 0. |
cursor | string | No | Continue from the previous page: pass its meta.next_cursor unchanged, with the same filters. Treat it as opaque. Not combinable with offset. Up to 2048 characters. |
Example
curl "https://app.xplantpro.com/api/v1/contaminations?explant_id=7c1d9e2a-3b4f-4a5c-8d6e-1f2a3b4c5d6e&status=active" \
-H "Authorization: Bearer $XPLANT_API_KEY"Response
200 with { "ok": true, "data": … }. data is an array. To get the next page, pass meta.next_cursor back as cursor; it is null on the last page. See Pagination.
| Field | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | Yes | — |
workspace_id | string | null | Yes | The workspace the log belongs to. |
type | string | null | Yes | What was seen: mold, bacteria, hyperhydricity, phenolic, algae, yeast, endophytic, viral, fungal, physiological, contaminated_media, damage, insect, other. |
type_other | string | null | Yes | The contamination in the logger's own words, when type is other. |
issue | string | Yes | A short summary of what was seen. |
description | string | null | Yes | — |
notes | string | null | Yes | — |
severity | string | Yes | How serious it is: very low, low, medium, high, critical. |
status | string | Yes | Where it stands: active, resolved, quarantined, archived, under investigation. |
observed_at | string | null | Yes | When it was seen. ISO 8601. |
resolved_at | string | null | Yes | When it was marked resolved. ISO 8601. |
vessels_affected | integer | null | Yes | How many vessels it reached. Null when nobody counted, which is not the same as none. |
plants_affected | integer | null | Yes | How many plants it reached. Null when nobody counted, which is not the same as none. |
affected_vessel_markings | string | null | Yes | Which vessels, as written on them. |
custom_fields | object | Yes | Your lab's own fields on this contamination, keyed by field key. Always an object: {} when none were filled in. |
plant_ids | string (uuid)[] | Yes | The plants the log is linked to. |
explant_ids | string (uuid)[] | Yes | The explants the log is linked to. |
logged_by | string (uuid) | Yes | User id of the workspace member who logged it. |
created_at | string | null | Yes | When it was logged. ISO 8601. |
updated_at | string | null | Yes | When it last changed. ISO 8601. |
{
"ok": true,
"data": [
{
"id": "8a3c1e57-4b2d-4f60-9c81-2d7e5b9a0f14",
"workspace_id": "3f9d2b61-7c4e-4a85-b0d3-6e1f8a2c5b97",
"type": "bacteria",
"type_other": null,
"issue": "Cloudy halo around the base of the Phalaenopsis explant",
"description": null,
"notes": "Noticed at the weekly check on shelf 3.",
"severity": "medium",
"status": "active",
"observed_at": "2026-09-24T08:30:00.000Z",
"resolved_at": null,
"vessels_affected": 2,
"plants_affected": null,
"affected_vessel_markings": "P-07 / P-09",
"custom_fields": {
"hood": "Hood 2"
},
"plant_ids": [],
"explant_ids": [
"6d2f9a14-8b3e-4c71-a5d0-1f7e3b8c2a96"
],
"logged_by": "0d7e4b9a-6f21-4c3e-8a5b-2e9f1c7d4a60",
"created_at": "2026-09-24T08:41:12.000Z",
"updated_at": "2026-09-24T08:41:12.000Z"
}
]
}The envelope can also carry meta:
| Field | Type | Required | Description |
|---|---|---|---|
next_cursor | string | null | Yes | Pass as cursor to fetch the next page. null means this is the last page. |
| Response header | Meaning |
|---|---|
X-Request-Id | Identifies this request. Include it when you contact support. |
Errors
| Status | Code | When |
|---|---|---|
401 | UNAUTHORIZED | The key is missing, malformed or revoked, or its owner is no longer a member of the workspace. |
402 | PAID_PLAN_REQUIRED | The workspace's plan does not include the API. The full API is included with xPlant+ Teams and Enterprise; on Hobby and Pro Lab, keys can connect devices only. |
403 | FORBIDDEN | The key lacks a scope this operation requires, or its owner's current role in the workspace cannot use it — a key never does more than its owner can in xPlant. error names the scope, and for a role, the role it needs. |
403 | DEVICE_TOKEN_NOT_ACCEPTED | A device token was sent; this operation needs a workspace API key. |
404 | NOT_FOUND | plant_id or explant_id names no plant or explant in the key's workspace; error says which. |
422 | VALIDATION_ERROR | Both cursor and offset were sent; use one. |
422 | INVALID_CURSOR | The cursor is malformed, or came from a different list or different filters. Start again without it. |
422 | VALIDATION_ERROR | A filter is malformed; error names it. |
429 | RATE_LIMIT_EXCEEDED | Too many requests for this key, device token or workspace. Wait Retry-After seconds. |
500 | CONTAMINATION_QUERY_FAILED | The logs could not be read. Retry later. |
Branch on code, never on the error text. See Errors.
List change history
What has happened to the workspace's plants or explants, oldest first: transfers, stage changes, contamination records, observations, printed labels.
Record a contamination
Records a contamination seen on one plant or explant, as the key's owner. It is the same record the app makes: it appears in the plant's or explant's history, and for an explant the stage and room the culture was in when it was seen are recorded with it, which is what lets the app show that room's conditions over the week before.